Python logging 模块日志重复输出问题排查与解决方案

向北走
向北走
发布时间:2026-10-14| 3人浏览过
原创

本文深入解析Python logging模块中因重复添加Handler导致的日志重复输出问题。通过对比修改前后的代码示例,详细说明了日志重复的根本原因,并提供了四种有效的解决方案,包括使用不同Logger名称、记录后移除Handler、添加前判断以及使用pop方法清理Handler列表,帮助开发者优化日志管理。

Python logging 模块日志重复输出问题

Python logging 模块日志重复输出问题

在使用 Python 的 logging 模块进行日志记录时,可能会遇到日志重复记录的现象:第一条日志正常输出一条,第二条输出两条,第三条输出三条,依此类推。这种重复记录不仅干扰排查,还影响性能,必须找到原因并解决。

问题原因与核心解决思路

问题的核心原因在于未正确移除 Handler。解决方法是在完成日志记录后,显式调用 removeHandler 方法移除已添加的句柄。

修改前代码与输出示例

以下是修改前的示例代码,展示了导致重复输出的典型写法:


import logging


def log(message):
 logger = logging.getLogger('testlog')

 streamhandler = logging.StreamHandler()
 streamhandler.setLevel(logging.ERROR)
 formatter = logging.Formatter('%(asctime)s - %(levelname)s - %(name)s - %(message)s')
 streamhandler.setFormatter(formatter)

 logger.addHandler(streamhandler)
 logger.error(message)

if __name__ == '__main__':
 log('hi')
 log('hi too')
 log('hi three')

修改前代码运行后的输出结果如下:

2016-07-08 09:17:29,740 - ERROR - testlog - hi 2016-07-08 09:17:29,740 - ERROR - testlog - hi too 2016-07-08 09:17:29,740 - ERROR - testlog - hi too 2016-07-08 09:17:29,740 - ERROR - testlog - hi three 2016-07-08 09:17:29,740 - ERROR - testlog - hi three 2016-07-08 09:17:29,740 - ERROR - testlog - hi three

修改后代码与输出示例

针对上述问题,修改后的示例代码如下:


import logging


def log(message):
 logger = logging.getLogger('testlog')

 streamhandler = logging.StreamHandler()
 streamhandler.setLevel(logging.ERROR)
 formatter = logging.Formatter('%(asctime)s - %(levelname)s - %(name)s - %(message)s')
 streamhandler.setFormatter(formatter)

 logger.addHandler(streamhandler)
 logger.error(message)

 # 添加下面一句,在记录日志之后移除句柄
 logger.removeHandler(streamhandler)

if __name__ == '__main__':
 log('hi')
 log('hi too')
 log('hi three')

修改后代码的运行输出结果如下:

2016-07-08 09:32:28,206 - ERROR - testlog - hi 2016-07-08 09:32:28,206 - ERROR - testlog - hi too 2016-07-08 09:32:28,206 - ERROR - testlog - hi three

深入解析:日志重复的根本原因

深入解析:

经过调研分析,问题的根源在于:当第二次调用 log 函数时,通过 getLogger(name) 获取的是同一个 Logger 实例。由于第一次调用时已经向该 Logger 添加了一个 Handler,第二次调用时又再次添加了一个相同的 Handler,导致 Logger 内部持有多个相同的 Handler。以此类推,调用次数越多,Handler 数量越多,日志输出也就越重复。

多种解决方案详解

因此,这里提供以下几种解决办法:

  1. 方案一:每次创建不同 name 的 Logger。由于每次获取的是新的 Logger 实例,自然不存在重复添加 Handler 的问题。(注:此方法较为笨拙,但确实有效,早期曾采用此方式。)
  2. 方案二:如前文示例所示,每次记录完日志后,调用 removeHandler() 将该 Logger 中的 Handler 移除。或者在 log 方法内部进行判断,如果该 Logger 已存在 Handler,则不再重复添加。
  3. 方案三:与方案二类似,但采用 pop 方法将 Logger 的 handlers 列表中的 Handler 移除。

方案三与方案四代码实现

以下是方案三与方案四的代码示例:

方案三代码示例:


import logging


def log(message):
 logger = logging.getLogger('testlog')

 # 这里进行判断,如果logger.handlers列表为空,则添加,否则,直接去写日志
 if not logger.handlers:
 streamhandler = logging.StreamHandler()
 streamhandler.setLevel(logging.ERROR)
 formatter = logging.Formatter('%(asctime)s - %(levelname)s - %(name)s - %(message)s')
 streamhandler.setFormatter(formatter)
 logger.addHandler(streamhandler)

 logger.error(message)


if __name__ == '__main__':
 log('hi')
 log('hi too')
 log('hi three')

方案四代码示例:


import logging


def log(message):
 logger = logging.getLogger('testlog')

 streamhandler = logging.StreamHandler()
 streamhandler.setLevel(logging.ERROR)
 formatter = logging.Formatter('%(asctime)s - %(levelname)s - %(name)s - %(message)s')
 streamhandler.setFormatter(formatter)

 logger.addHandler(streamhandler)

 logger.error(message)

 # 用pop方法把logger.handlers列表中的handler移除,注意如果你add了多个handler,这里需多次pop,或者可以直接为handlers列表赋空值
 logger.handlers.pop()
 # logger.handler = []


if __name__ == '__main__':
 log('hi')
 log('hi too')
 log('hi three')

上述几种方法均经过实测可行。个人倾向于方案三,因为其通过判断 handlers 列表是否为空来决定是否添加 Handler,逻辑更为优雅。各位开发者可根据实际场景选择合适方案。

到此,关于 Python logging 模块日志重复输出问题的解决方案介绍完毕。如需了解更多相关 Python logging 知识,请搜索本站历史文章或继续浏览后续内容。感谢大家的支持!

免责声明:本文内容仅供参考,不代表本站观点。转载或引用请注明出处。

Python 相关产品和应用

全部下载
Selenium

Selenium

4.51.0 · Windows

用于浏览器自动化和 Web 测试的 Python 工具。

scikit-learn

scikit-learn

1.9.1 · Windows

常用 Python 机器学习算法与模型评估工具库。

Black

Black

26.10.1 · Windows

强调一致性的 Python 自动代码格式化工具。

Ruff

Ruff

0.17.1 · macOS

由 Rust 编写的高速 Python 代码检查和格式化工具。

pytest

pytest

9.1.1 · Windows

简洁而强大的 Python 自动化测试框架。

FastAPI

FastAPI

0.146.0 · Windows

高性能 Python API 框架,支持类型提示和自动接口文档。

Flask

Flask

3.1.3 · Windows

轻量灵活的 Python Web 应用框架。

Django

Django

6.1.2 · Windows

成熟的 Python Web 框架,适合构建内容站点和业务系统。

Spyder

Spyder

6.1.7 · Windows

面向科学计算与数据分析的 Python 集成开发环境。

SciPy

SciPy

1.18.1 · Windows

面向科学、工程和技术计算的 Python 算法库。