如何在日志记录格式化程序中进行可选参数

时间:2018-11-13 22:13:28

标签: python logging

我想使用以下日志格式化程序:

'format': '{"message": "%(message)s", "user": "%(user)s"}'

但是,我想用两种不同的方式来称呼它:

log.info('hi', extra={"user": str(request.user)})
log.info("hi")

第一个日志语句有效,因为它具有user kwarg,但第二个语句失败,并带有KeyError。有什么方法可以使格式参数为可选?

1 个答案:

答案 0 :(得分:2)

可选格式参数args替换为None

给定固定的日志记录格式字符串,可以使用自定义Formatter类用None替换缺少的参数。

import logging
import re

class CustomFormatter(logging.Formatter):

    def format(self, record: logging.LogRecord) -> str:
        arg_pattern = re.compile(r'%\((\w+)\)')
        arg_names = [x.group(1) for x in arg_pattern.finditer(self._fmt)]
        for field in arg_names:
            if field not in record.__dict__:
                record.__dict__[field] = None

        return super().format(record)


logger = logging.getLogger(__name__)
handler = logging.StreamHandler()
formatter = CustomFormatter('{"message": "%(message)s", "user": "%(user)s"}')
handler.setFormatter(formatter)
logger.setLevel(logging.INFO)
logger.addHandler(handler)

logger.info('hi')
logger.info('hi', extra={"user": "asmith"})

输出

{"message": "hi", "user": "None"}
{"message": "hi", "user": "asmith"}

动态地在日志输出中添加额外的args

自定义Formatter可以根据传递给extra的字典来动态更新格式字符串。

import logging

class ExtraFormatter(logging.Formatter):

    def format(self, record: logging.LogRecord) -> str:
        default_attrs = logging.LogRecord(None, None, None, None, None, None, None).__dict__.keys()
        extras = set(record.__dict__.keys()) - default_attrs

        log_items = ['"message": "%(message)s"']
        for attr in extras:
            log_items.append(f'"{attr}": "%({attr})s"')
        format_str = f'{{{", ".join(log_items)}}}'
        self._style._fmt = format_str

        return super().format(record)


logger = logging.getLogger(__name__)
handler = logging.StreamHandler()
formatter = ExtraFormatter()
handler.setFormatter(formatter)
logger.setLevel(logging.INFO)
logger.addHandler(handler)

logger.info('hi')
logger.info('hi', extra={"user": "asmith", "number": "42"})

输出

{"message": "hi"}
{"message": "hi", "user": "asmith", "number": "42"}