两种方式来用 Python logging 记录额外的值
Jan 29, 2019
1 minute read

前言

有两种方式来用 Python logging 记录额外的值

  1. 使用 extra 参数
  2. 向 args 传入字典结构的数据

使用 extra 参数

通过 log 方法的 extra 参数可以来记录而外的值。通过 LogRecord.extra 获取,配合 LogFilterLoggerAdapter 使用。还可以通过配置 Formatter 打印出该值

logging.basicConfig(format="%(ip)s - %(message)s")
logging.info("test message", extra={"ip": "127.0.0.1"})

其输出

127.0.0.1 - test message

使用 Formatter 十分方便,但一旦没有通过 extra 传入对应的键值,则会导致日志写出异常

logger = logging.getLogger()
adapted_logger = logging.LoggerAdapter(logger, extra={"ip": "127.0.0.1"})
adapted_logger.info("test message")

可通过 LoggerAdapter 来给所有 log 方法加上 extra 参数

不过官方的实现很奇怪,直接覆盖掉了原本的 extra 参数。

通过继承它,修改 process 方法即可

def process(self, msg, kwargs):
    kwargs["extra"] = {**self.extra, **kwargs.get("extra", {})}
    return msg, kwargs

除了以上这个通过传入 extra 参数来添加额外键值的方法,还有什么更方便的方法来记录额外的数据?

向 args 传入字典结构的数据

logging.basicConfig(format="%(message)s")
logging.info("test message from %(ip)r", {"ip": "127.0.0.1"})
logging.info("test message from %(ip)r", {"ip": "127.0.0.2", "delay": 200})

其输出

test message from "127.0.0.1"
test message from "127.0.0.2"

以这样的方式传入日志参数,比起 extra 来有更高的自由度。打日志时,可以随意的在 msg 中使用 args

传入的 args 参数,可以从 LogRecord.args 获取 LogRecord.__init__

同样,我们可以实现一个类似 LoggerAdapter 的来提供默认的 args

class ArgsLoggerAdapter(logging.LoggerAdapter):
    def process_with_args(self, msg, args, kwargs):
        if (args and len(args) == 1 and isinstance(args[0], collections.abc.Mapping)
            and args[0]):
            args[0] = {**self.extra, **args[0]}
        return msg, args, kwargs

    def log(self, level, msg, *args, **kwargs):
        if self.isEnabledFor(level):
            msg, args, kwargs = self.process_with_args(msg, kwargs)
            self.logger.log(level, msg, *args, **kwargs)

使用这个向 args 传入字典结构数据的方法,配合用 LogFilter 十分的方便




comments powered by Disqus