Python配置两个StreamHandler导致日志重复输出的解决方法
问题描述
在新Python实例中配置两个StreamHandler的logger时,调用logger.error会出现重复输出,代码示例如下:
❯ python Python 3.10.6 (main, Nov 14 2022, 16:10:14) [GCC 11.3.0] on linux Type "help", "copyright", "credits" or "license" for more information. >>> import logging >>> logger = logging.getLogger() >>> logger.setLevel(logging.DEBUG) >>> >>> info = logging.StreamHandler() >>> info.setLevel(logging.INFO) >>> >>> error = logging.StreamHandler() >>> error.setLevel(logging.ERROR) >>> >>> logger.addHandler(info) >>> logger.addHandler(error) >>> logger.error("Error!") Error! Error!
预期仅显示一条消息,该如何修复?
已尝试的操作
- 设置
propagate为False,无效:
logger.propagate
True
logger.propagate = False
logger.error("Error!")
Error!
Error!
- 检查未发现额外处理器: ```python >>> logger.handlers [<StreamHandler <stderr> (INFO)>, <StreamHandler <stderr> (ERROR)>]
- 使用自定义日志器,问题仍存在:
logger = logging.getLogger("testing")
- 为处理器设置自定义格式,确认两个处理器均被调用导致重复: ```python >>> error.setFormatter(logging.Formatter("%(levelname)s: %(message)s")) >>> info.setFormatter(logging.Formatter("%(levelname)s: %(message)s")) >>> >>> logger.error("Big error") ERROR: Big error ERROR: Big error
原因与修复方法
原因
日志级别是向下兼容的:ERROR级别高于INFO,调用logger.error()时,这条日志同时满足info处理器(处理INFO及以上级别)和error处理器(处理ERROR及以上级别)的过滤条件,两个处理器都会输出日志,导致重复。
修复方案
给info处理器添加自定义过滤器,限制它只处理指定范围的日志级别,避免和error处理器的处理范围重叠。
方案1:让info处理器仅处理INFO级别日志
import logging # 自定义过滤器:只允许INFO级别的日志通过 class InfoOnlyFilter(logging.Filter): def filter(self, record): return record.levelno == logging.INFO logger = logging.getLogger() logger.setLevel(logging.DEBUG) info = logging.StreamHandler() info.setLevel(logging.INFO) # 给info处理器添加过滤器 info.addFilter(InfoOnlyFilter()) error = logging.StreamHandler() error.setLevel(logging.ERROR) logger.addHandler(info) logger.addHandler(error) # 测试 logger.info("Info message") # 仅info处理器输出 logger.error("Error message") # 仅error处理器输出
方案2:让info处理器处理INFO到WARNING级别日志
如果需要info处理器覆盖INFO到WARNING的日志,不处理ERROR及以上,可修改过滤器:
class InfoToWarningFilter(logging.Filter): def filter(self, record): return logging.INFO <= record.levelno < logging.ERROR
将上述过滤器添加到info处理器后,logger.error()就只会被error处理器处理,不会出现重复输出。
内容的提问来源于stack exchange,提问作者Yoltic Cruz Tello
相关产品推荐
相关产品推荐

