Loguru 日志重复打印是因为其 logger 默认向 root 传播且标准 logging 的 root logger 已启用,导致日志被两个 handler 同时处理;需清空 root handlers 并关闭 propagate 才能避免。

Loguru 能直接替代标准 logging,但必须移除 root logger 的所有 handler 并禁用 propagation,否则日志会重复输出两次。
为什么日志会重复打印?
标准 logging 的 root logger 默认启用,且 Loguru 的 logger 默认向 root 传播(propagate=True)。一旦你调用 logging.basicConfig() 或其他模块悄悄初始化了 root logger,Loguru 就会和它“共存”,导致每条日志打两遍。
常见错误现象:INFO | 2024-05-12 10:23:45 | main.py:12 - Hello 出现两次;或日志里混着 WARNING:root:xxx 这类格式混乱的输出。
- 启动时立即执行
logging.getLogger().handlers.clear()和logging.getLogger().propagate = False - 确保项目中任何地方都没调用
logging.basicConfig()、logging.getLogger("xxx").addHandler(...)等操作 - 第三方库如果内部用了
logging,可加logger.remove(); logger.add(sys.stderr, level="WARNING")临时压制其 DEBUG/INFO
如何按环境切换日志级别与输出目标?
Loguru 没有内置“环境变量驱动配置”,得靠手动判断。关键点是:每个 add() 返回一个 handler ID,后续要用它来 remove(),否则多次 reload 会叠加 handler。
立即学习“Python免费学习笔记(深入)”;
图片提示词生成器?不止如此。 马甲系统 —— 把脑海中的画面,翻译成AI能理解的专业表达。 用得越多,它越懂你:首次需要多问几句确认方向,用久了几乎一说就懂。 用得越多,它越快:缓存机制让后续对话越来越省。 RAG进化:成功案例持续入库,越跑越聪明。 输入「新手指南」查看完整功能介绍
使用场景:开发时输出到控制台并保留 DEBUG;生产时只写文件、关闭控制台、默认 INFO。
- 用
os.getenv("ENV", "dev")判断环境,而非硬编码 - 开发模式下:
logger.add(sys.stderr, level="DEBUG", format="{time} {level} {message}") - 生产模式下:
logger.add("logs/app.log", level="INFO", rotation="10 MB", retention="7 days", compression="zip") - 务必在重新 add 前先
logger.remove(handler_id),避免累积——这是最常被忽略的内存泄漏点
如何让 Loguru 兼容已有的 logging.Handler 子类?
Loguru 不接受原生 logging.Handler 实例,但提供 patch() 和 bind() 做上下文增强,真要复用 Handler(比如 SentryHandler、SysLogHandler),得包装一层。
性能影响:每次日志都要走一次 wrapper 调用,比原生 add 稍慢,但通常可忽略;兼容性上,只要 Handler 的 emit() 方法不依赖 logging.LogRecord 的特定属性,就能转。
- 写个简单 wrapper:
class LoguruHandler: def __init__(self, handler): self.handler = handler; def write(self, message): self.handler.emit(self._to_record(message)) - 然后
logger.add(LoguruHandler(sentry_handler), level="ERROR") - 注意
_to_record()需从message.record提取level、time、function等字段,映射成LogRecord所需结构
Loguru 的核心优势不在功能多,而在开箱即用的格式、线程安全的异步写入、以及对异常 traceback 的自动美化——但这些都建立在“干净接管”基础上。一旦和标准 logging 混用,第一层封装就塌了。

















