自定义Logger为何不使用根日志记录器的格式化器?
自定义Logger无法继承根日志处理器的原因及解决方法
问题:根据logging文档,未配置处理器的日志记录器应该回退到根日志记录器,但自定义Logger实例调用日志方法时没有使用根的格式,而通过
logging.getLogger()创建的日志器却正常。示例代码及输出如下:
import logging class MyLogger(logging.getLoggerClass()): pass mylog = MyLogger("mytest") log = logging.getLogger("test") root = logging.getLogger() h = logging.StreamHandler() f = logging.Formatter(fmt="[%(levelname)s] %(message)s") h.setFormatter(f) root.addHandler(h) log.error("Normal log") mylog.error("Test log")
输出:
[ERROR] Normal log Test log
核心原因
日志模块的传播机制依赖日志器的层级关系:
- 通过
logging.getLogger()创建的日志器,会被日志管理器自动构建层级,将父日志器自动设置为根日志器(对应层级的父日志器)。当自身无处理器时,会将日志传播给父日志器处理,因此能使用根的格式。 - 直接实例化自定义Logger类时,实例的
parent属性默认是None,即使propagate=True(默认值),也找不到父日志器来传播日志,只能使用模块内置的“应急”处理器(无格式,仅输出原始消息)。
解决方法
有两种可行的方式让自定义Logger继承根日志的处理器和格式:
方法1:注册自定义Logger类后用logging.getLogger()创建实例
这是最规范的方式,让日志管理器统一处理层级:
import logging class MyLogger(logging.getLoggerClass()): # 自定义逻辑 pass # 注册自定义Logger类,后续getLogger会返回该类的实例 logging.setLoggerClass(MyLogger) # 创建自定义日志器实例,此时会自动设置父日志器 mylog = logging.getLogger("mytest") # 若之后需要恢复默认Logger类,可执行:logging.setLoggerClass(logging.Logger) # 后续配置根日志器的代码不变 root = logging.getLogger() h = logging.StreamHandler() f = logging.Formatter(fmt="[%(levelname)s] %(message)s") h.setFormatter(f) root.addHandler(h) mylog.error("Test log") # 现在会使用根的格式输出
方法2:手动为自定义Logger实例设置父日志器
如果不想全局替换Logger类,可以手动指定父日志器:
import logging class MyLogger(logging.getLoggerClass()): pass mylog = MyLogger("mytest") # 手动将父日志器设置为根日志器 mylog.parent = logging.getLogger() # 后续配置代码不变 root = logging.getLogger() h = logging.StreamHandler() f = logging.Formatter(fmt="[%(levelname)s] %(message)s") h.setFormatter(f) root.addHandler(h) mylog.error("Test log") # 现在会使用根的格式输出
内容的提问来源于stack exchange,提问作者musbur
相关产品推荐
相关产品推荐

