使用logging basicConfig配置多Handler时的日志级别异常问题
Python logging模块多Handler配置的级别问题
我想通过Python logging模块实现:syslog输出WARN及以上级别日志,日志文件输出DEBUG及以上级别日志。但按以下代码实现时,日志文件只输出WARN和ERROR级别的内容,INFO和DEBUG日志没被写入;只有在basicConfig里加上level=logging.DEBUG后,才能达到预期效果——日志文件包含所有级别日志,syslog仅输出WARN和ERROR。我不明白为什么单独给文件Handler设置DEBUG级别没用。
初始实现代码:
import logging import logging.handlers import os from datetime import datetime log_format = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s') f_handler = logging.FileHandler(f'{os.path.expanduser("~")}/logs/test_{datetime.now().strftime("%Y%m%d%H%M%S")}.log') s_handler = logging.handlers.SysLogHandler(address='/dev/log') f_handler.setLevel(logging.DEBUG) s_handler.setLevel(logging.WARN) f_handler.setFormatter(log_format) s_handler.setFormatter(log_format) logging.basicConfig(handlers=[f_handler, s_handler]) print(logging.getLogger().getEffectiveLevel()) logging.warning('This is a warning') logging.error('This is an error') logging.info('This is an info') logging.debug('This is debug')
修改后可正常工作的代码片段:
logging.basicConfig(handlers=[f_handler, s_handler], level=logging.DEBUG)
原因解析
这是因为logging模块的日志过滤是先经过Logger级别过滤,再经过Handler级别过滤的:
- 默认情况下,根Logger的有效级别是
WARNING(对应数值30,你可以通过代码里的print语句看到输出结果)。当你调用logging.debug()或logging.info()时,根Logger会先判断日志级别是否≥自身的WARNING级别,结果不满足,这些日志直接被拦截,根本不会传递给后续的Handler处理——哪怕你给FileHandler设置了DEBUG级别也没用,因为日志根本没到Handler这一步。 - 当你在
basicConfig里设置level=logging.DEBUG时,根Logger的级别被改为DEBUG,此时INFO、DEBUG级别的日志能通过Logger的过滤,再传递给各个Handler:- FileHandler的级别是DEBUG,会接收所有通过Logger的日志;
- SysLogHandler的级别是WARN,只接收WARN及以上的日志,完全符合你的需求。
总结
Logger的级别是日志流转的第一道关卡,只有通过这道关卡的日志,才会进入Handler的级别过滤环节。因此必须把根Logger的级别设置到足够低(比如DEBUG),让你需要的日志能通过,再靠各个Handler的级别来过滤不同输出渠道的内容。
内容的提问来源于stack exchange,提问作者johnmcp
相关产品推荐
相关产品推荐

