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
关键知识点
- 关闭日志传播:每个自定义日志器设置
logger.propagate = False,这样日志就不会向上传给父级日志器(包括root),从根源上避免重复输出。 - 独立配置每个日志器:不要依赖
logging.basicConfig(),而是给每个日志器手动添加Handler、设置Formatter和级别,完全隔离各个日志器的配置。 - 避免直接使用
logging.debug()等方法:这些方法本质是调用root日志器,如果你不需要root日志器,就完全用自定义日志器来输出。
针对你后来更新的代码的修正
你后来更新的代码里还是有重复,是因为没有设置propagate=False,而且root日志器的默认Handler还在。只要给logger1和logger2都加上以下代码,就能解决重复问题:
logger1.propagate = False logger2.propagate = False
这样就不会再出现WARNING:root:test warning这种重复的输出了。
备注:内容来源于stack exchange,提问作者averlon




