You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

Python配置两个不同格式的日志记录器并解决重复输出问题

Python配置两个不同格式的日志记录器并解决重复输出问题

我来帮你搞定这个日志重复输出的问题!你遇到的核心问题是Python logging模块的日志传播机制,加上默认root日志器的配置干扰,才导致了重复打印的情况。

先分析你原代码的问题

你最初的代码里:

  • 调用logging.basicConfig()时,实际上是给root日志器自动添加了一个StreamHandler,用你指定的第一个格式输出。
  • 自定义的logger1默认会把日志消息向上传播给父级日志器(最终到root),所以logger1的每条日志会被自己的v_obj_CONSOLE和root的Handler各输出一次,自然就重复了。
  • 你直接用logging.debug()/logging.info()这些方法,本质是在调用root日志器的方法,所以会走root的格式。

正确的解决方案

解决思路很简单:关闭自定义日志器的消息传播,同时给每个日志器独立配置Handler、Formatter和级别,避免root日志器的默认配置干扰。

下面是修正后的完整代码:

import logging

# 配置第一个日志器(对应原root的格式)
logger_root_style = logging.getLogger('logger.root_style')
handler_root_style = logging.StreamHandler()
formatter_root_style = logging.Formatter(fmt='### %(levelname)-8s - %(message)s')
handler_root_style.setFormatter(formatter_root_style)
logger_root_style.addHandler(handler_root_style)
logger_root_style.setLevel(logging.NOTSET)
logger_root_style.propagate = False  # 关闭传播,避免传给root日志器

# 配置第二个日志器(带名称、时间戳的格式)
logger_custom_style = logging.getLogger('logger.custom_style')
handler_custom_style = logging.StreamHandler()
formatter_custom_style = logging.Formatter(
    fmt='### %(name)s - %(asctime)s - %(levelname)-8s - %(message)s',
    datefmt='%d-%m-%Y %H:%M'
)
handler_custom_style.setFormatter(formatter_custom_style)
logger_custom_style.addHandler(handler_custom_style)
logger_custom_style.setLevel(logging.NOTSET)
logger_custom_style.propagate = False  # 关键:关闭传播,避免重复输出

# 测试两个日志器
print()
print("=== 使用root风格的日志器 ===")
logger_root_style.log(logging.INFO, 'started')
logger_root_style.debug("test debug")
logger_root_style.info("test INFO")
logger_root_style.warning("test warning")
logger_root_style.error("test error")
logger_root_style.critical("test critical")

print()
print("=== 使用自定义风格的日志器 ===")
logger_custom_style.log(logging.INFO, 'started')
logger_custom_style.debug("test debug")
logger_custom_style.info("test INFO")
logger_custom_style.warning("test warning")
logger_custom_style.error("test error")
logger_custom_style.critical("test critical")

运行结果

=== 使用root风格的日志器 ===
### INFO     - started
### DEBUG    - test debug
### INFO     - test INFO
### WARNING  - test warning
### ERROR    - test error
### CRITICAL - test critical

=== 使用自定义风格的日志器 ===
### logger.custom_style - 24-02-2025 14:30 - INFO     - started
### logger.custom_style - 24-02-2025 14:30 - DEBUG    - test debug
### logger.custom_style - 24-02-2025 14:30 - INFO     - test INFO
### logger.custom_style - 24-02-2025 14:30 - WARNING  - test warning
### logger.custom_style - 24-02-2025 14:30 - ERROR    - test error
### logger.custom_style - 24-02-2025 14:30 - CRITICAL - test critical

关键知识点

  1. 关闭日志传播:每个自定义日志器设置logger.propagate = False,这样日志就不会向上传给父级日志器(包括root),从根源上避免重复输出。
  2. 独立配置每个日志器:不要依赖logging.basicConfig(),而是给每个日志器手动添加Handler、设置Formatter和级别,完全隔离各个日志器的配置。
  3. 避免直接使用logging.debug()等方法:这些方法本质是调用root日志器,如果你不需要root日志器,就完全用自定义日志器来输出。

针对你后来更新的代码的修正

你后来更新的代码里还是有重复,是因为没有设置propagate=False,而且root日志器的默认Handler还在。只要给logger1logger2都加上以下代码,就能解决重复问题:

logger1.propagate = False
logger2.propagate = False

这样就不会再出现WARNING:root:test warning这种重复的输出了。

备注:内容来源于stack exchange,提问作者averlon

火山引擎 最新活动