如何处理日志格式字符串中的可选参数?

2024-09-28 22:44:06 发布

您现在位置:Python中文网/ 问答频道 /正文

我想使用以下日志格式:

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

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

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

第一个log语句之所以有效,是因为它提供了user参数,但第二个log语句失败,返回了KeyError

有没有办法使格式字符串参数成为可选的


Tags: 字符串infologformatmessage参数格式方式
1条回答
网友
1楼 · 发布于 2024-09-28 22:44:06

可选格式参数替换为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"}

动态地向日志输出添加额外的参数

自定义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"}

相关问题 更多 >