Source code for cobald.monitor.format_json
from collections.abc import Mapping
from logging import Formatter, LogRecord
import json
#: Attributes of a LogRecord.
# See <the docs `https://docs.python.org/3/library/logging.html#logrecord-attributes`>_.
RECORD_ATTRIBUTES = (
"args",
"asctime",
"created",
"exc_info",
"exc_text",
"filename",
"funcName",
"levelname",
"levelno",
"lineno",
"message",
"module",
"msecs",
"msg",
"name",
"pathname",
"process",
"processName",
"relativeCreated",
"stack_info",
"thread",
"threadName",
)
[docs]
class JsonFormatter(Formatter):
"""
Formatter that emits data as JSON
:param fmt: default data for all records
:param datefmt: format for timestamps
The ``datefmt`` parameter has almost the same meaning as
:py:class:`~.Formatter`.
Setting it to ``None`` uses the default time format.
However, setting it to any other value that is boolean
false excludes the timestamp from reports.
"""
def __init__(self, fmt: dict = None, datefmt: str = None):
super().__init__(fmt=None, datefmt=datefmt, style="%")
self._defaults = fmt or {}
if not isinstance(self._defaults, Mapping):
raise TypeError("`fmt` must be a Mapping or None")
self._add_time = self.datefmt or self.datefmt is None
[docs]
def format(self, record: LogRecord):
args = record.args
if args == ({},): # logger.info('message', {}) -> record.args == ({},)
args = {}
assert isinstance(
args, Mapping
), "monitor record argument must be a mapping, not %r" % type(args)
data = self._defaults.copy()
if self._add_time:
data["time"] = self.formatTime(record, self.datefmt)
data["message"] = record.getMessage() if args else record.msg
data.update(args)
return json.dumps(data)
if __name__ == "__main__":
import logging
logger = logging.getLogger()
logger.handlers = [logging.StreamHandler()]
logger.handlers[0].formatter = JsonFormatter({"latitude": 49, "longitude": 8})
logger.warning("forecast", {"temperature": 298, "humidity": 0.45})