Python logging跨模块调用时日志配置不生效如何解决
问题原因
你遇到的问题由三个细节共同导致:
- 你当前只给名为
__main__的logger绑定了handler和格式配置,Python logging的继承规则是子logger默认向上查找父logger(最终到根logger)的配置,submodule对应的logger和__main__是平级,根本不会继承__main__上挂的配置。 - 你在日志配置完成前就导入了
submodule,而submodule里的logger.info('Test 1')、logger.error('Test 2')是导入阶段就直接执行的,执行时日志配置还没生效。 - 未单独配置级别的logger默认日志级别是
WARNING,所以子模块的INFO级别的Test 1会被直接过滤;Test 2是ERROR级别,会触发logging默认挂载的标准错误流handler,这个handler没有设置你自定义的格式,所以只会输出原始消息文本。
修复方法
按以下调整即可,子模块代码不需要做任何修改:
- 统一配置根logger,而不是给
__main__专属logger挂handler,所有模块通过logging.getLogger(__name__)拿到的logger都会自动继承根logger的配置。 - 把导入子模块的逻辑挪到日志全部配置完成之后,保证导入阶段执行的日志语句能拿到正确配置。
- 补上原代码缺失的
sys模块导入,你代码里h1指定输出到sys.stdout但没导入sys,运行会直接抛错。
调整后的main.py代码如下:
# File: main.py import logging import sys def main(): logger = logging.getLogger(__name__) logger.debug(f'Test') if __name__ == '__main__': # 初始化根logger配置 root_logger = logging.getLogger() root_logger.setLevel(logging.DEBUG) formatter = logging.Formatter('[%(levelname)s | %(name)s] %(message)s') # 处理debug、info级别日志输出到stdout h1 = logging.StreamHandler(sys.stdout) h1.setLevel(logging.DEBUG) h1.addFilter(lambda record: record.levelno <= logging.INFO) h1.setFormatter(formatter) # 处理warning及以上级别日志输出到stderr h2 = logging.StreamHandler() h2.setLevel(logging.WARNING) h2.setFormatter(formatter) root_logger.addHandler(h1) root_logger.addHandler(h2) # 日志配置完成后再导入子模块 import submodule main()
运行后就能得到符合预期的输出:
[INFO | submodule] Test 1 [DEBUG | __main__] Test [ERROR | submodule] Test 2
注:Test 1的输出顺序在Test前面是因为submodule导入时就会执行info日志,main函数里的debug日志是调用main()时才触发,属于正常现象。如果需要调整顺序,把submodule里的日志语句放到函数里,等main调用时再执行即可。
内容的提问来源于stack exchange,提问作者user16456506
相关产品推荐
相关产品推荐

