# -*- coding: utf-8 -*- # Copyright 2019 The Matrix.org Foundation C.I.C. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. """ Log formatters that output terse JSON. """ import json import logging _encoder = json.JSONEncoder(ensure_ascii=False, separators=(",", ":")) # The properties of a standard LogRecord. _LOG_RECORD_ATTRIBUTES = { "args", "asctime", "created", "exc_info", # exc_text isn't a public attribute, but is used to cache the result of formatException. "exc_text", "filename", "funcName", "levelname", "levelno", "lineno", "message", "module", "msecs", "msg", "name", "pathname", "process", "processName", "relativeCreated", "stack_info", "thread", "threadName", } class JsonFormatter(logging.Formatter): def format(self, record: logging.LogRecord) -> str: event = { "log": record.getMessage(), "namespace": record.name, "level": record.levelname, } return self._format(record, event) def _format(self, record: logging.LogRecord, event: dict) -> str: # Add any extra attributes to the event. for key, value in record.__dict__.items(): if key not in _LOG_RECORD_ATTRIBUTES: event[key] = value return _encoder.encode(event) class TerseJsonFormatter(JsonFormatter): def format(self, record: logging.LogRecord) -> str: event = { "log": record.getMessage(), "namespace": record.name, "level": record.levelname, "time": round(record.created, 2), } return self._format(record, event)