You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.28 16:22:39