
本文详解如何在 Python logging 模块中创建多个独立 Logger,各自拥有专属格式并输出到 stdout,关键在于禁用 propagate 以防止日志向上冒泡至 root logger 导致重复。
本文详解如何在 python logging 模块中创建多个独立 logger,各自拥有专属格式并输出到 stdout,关键在于禁用 `propagate` 以防止日志向上冒泡至 root logger 导致重复。
在 Python 日志系统中,每个 logger(除 root 外)默认启用 propagate=True —— 即当它处理完一条日志后,会自动将该日志向上传递给其父 logger(最终到达 root logger)。若同时调用了 logging.basicConfig(),root logger 就会附加一个默认的 StreamHandler,从而造成同一日志被打印两次:一次由自定义 handler 格式化输出,另一次由 root handler(如 basicConfig 配置的)再次输出。
要实现「两个 logger 各自独立、格式互不干扰、且不重复」,核心解决方案是:显式关闭 propagate,并为每个 logger 独立配置 handler 和 formatter。
以下是一个清晰、可复用的完整示例:
import logging
# ✅ 全局基础配置(可选):仅影响 root logger,但需注意后续 propagate 控制
logging.basicConfig(
level=logging.WARNING, # 仅 root 处理 WARNING 及以上
format='%(levelname)s:%(name)s:%(message)s',
force=True # Python 3.8+ 推荐,确保覆盖之前配置
)
# ? 创建两个独立 logger
logger_a = logging.getLogger('app.core')
logger_b = logging.getLogger('app.api')
# ? 分别创建 StreamHandler(都输出到 stdout)
handler_a = logging.StreamHandler()
handler_b = logging.StreamHandler()
# ? 定义不同格式
formatter_a = logging.Formatter(
'⚡ [%(levelname)-8s] %(message)s'
)
formatter_b = logging.Formatter(
'? %(asctime)s | %(name)s | %(levelname)-8s | %(message)s',
datefmt='%H:%M:%S'
)
handler_a.setFormatter(formatter_a)
handler_b.setFormatter(formatter_b)
# ? 绑定 handler 并设置日志级别
logger_a.addHandler(handler_a)
logger_b.addHandler(handler_b)
logger_a.setLevel(logging.DEBUG) # 启用 DEBUG 级别输出
logger_b.setLevel(logging.INFO)
# ⚠️ 关键一步:禁用传播,避免日志“泄露”到 root logger
logger_a.propagate = False
logger_b.propagate = False
# ✅ 测试输出
print("=== logger_a 输出 ===")
logger_a.debug("调试信息(仅⚡格式)")
logger_a.info("常规操作")
logger_a.warning("潜在问题")
print("\n=== logger_b 输出 ===")
logger_b.info("API 请求开始")
logger_b.error("请求超时")
预期输出效果:
=== logger_a 输出 === ⚡ [DEBUG ] 调试信息(仅⚡格式) ⚡ [INFO ] 常规操作 ⚡ [WARNING ] 潜在问题 === logger_b 输出 === ? 14:22:05 | app.api | INFO | API 请求开始 ? 14:22:05 | app.api | ERROR | 请求超时
✅ 注意事项总结:
- 不要混用
basicConfig()和手动 handler 配置而不控制propagate,否则极易重复; -
force=True(Python 3.8+)可安全重置 root logger 配置,避免多次调用basicConfig失效; - 每个 logger 的
level控制「自身是否处理该日志」,而 handler 的level(可通过handler.setLevel()设置)可进一步做二次过滤; - 若需同时输出到文件和控制台,只需为同一 logger 添加多个 handler(各配不同 formatter);
-
getLogger(name)是单例模式:相同 name 返回同一对象,适合跨模块共享 logger。
通过合理组合 propagate=False、独立 handler 与 formatter,你就能构建灵活、无干扰、高可维护的日志体系。
Python免费学习笔记(深入):立即使用
在学习笔记中,你将探索 Python 的核心概念和高级技巧!











