Python日志中多模块的自定义额外数据

3
我正在尝试在Python中实现一个涉及多个模块的日志记录器。核心功能涉及一个gRPC微服务,它接收有效负载,生成一个ID并执行一些优化。
当同时出现多个请求时,日志可能会混乱。我想做的是为日志行添加运行ID标记,以便在父模块和所有导入的模块中进行每个函数调用时都打印运行ID。
我尝试过这样做:
logger = logging.getLogger("myservice")
log_file = "logs/solver.log"
formatter = logging.Formatter("%(asctime)s - %(levelname)s - %(log_id)s - %(name)s - %(message)s", datefmt="%y/%m/%d %H:%M:%S")  #: log_id is custom data
log_data = {'log_id': None}

concise_log = logging.FileHandler(log_file)                 #: file handler for concise log
concise_log.setLevel(logging.INFO)
concise_log.setFormatter(formatter)

#: Add the logging hanlders to the logger
logger.addHandler(concise_log)
logger.addHandler(detailed_log)

logger.info(f"log_file: {log_file}", extra=log_data)
logger.info("LOG START", extra=log_data)
logger.debug("Debug level messages are being recorded.", extra=log_data)

一开始我使用了一个虚拟值来代替log_data,因为否则记录器会报错。

后来我设置了log_id并记录了各种信息,如下所示:

    log_id = str(uuid.uuid4())
    log_data = {'log_id': log_id}      #: extra data for logger

    #: load the server config:
    logger.info("loading server config...", extra=log_data)

这个代码可以正常运行,但如果在任何导入的函数中调用我的日志记录器,它就会出错,因为那些函数没有log_data。

我希望能够以更全局的方式设置log_id,以便在导入的模块中,日志记录器始终具有正确的log_id,该log_id会随着每个请求而改变。

是否有其他模式可用于实现此目的?

1个回答

2

最好使用LoggerAdapter来完成此操作。官方文档中有一个非常好的示例,与您尝试做的非常接近。代码将大致如下:

class LogIdAdapter(logging.LoggerAdapter):
    def process(self, msg, kwargs):
        return '[%s] %s' % (self.extra['log_id'], msg), kwargs

tmp_logger = logging.getLogger("myservice")
# ... set up handlers etc here. do not include log_id in formatter, it will be added later
logger = LogIdAdapter(tmp_logger, {'log_id': str(uuid.uuid4())})

logger.info("some text") # this log will have log_id prepended

子模块是否也会继承日志适配器的ID,还是我需要以某种方式将ID传递给子模块? - undefined
1
适配器是日志记录器的包装器。因此,它不会触及日志记录器对象本身。这回答了你的问题吗? - undefined
我明白你说的关于日志适配器作为包装器的意思。我认为对我的问题来说,真正的答案是,如果我希望在这些函数中调用日志记录器时能够知道我的ID,我仍然需要将额外的数据传递给我的导入函数。 - undefined

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接