
loguru 默认将所有匹配级别的日志广播至所有已注册的 handler;若需让 error 日志仅写入 error.log、info 日志仅写入 info.log,必须通过 filter 参数为每个 handler 显式定义日志路由规则,而非仅依赖 level 参数。
Loguru 的核心设计原则是:所有 handler(即通过 .add() 添加的输出目标)都挂载在同一个全局 logger 实例上,且日志消息一旦满足某 handler 的 level,就会被无差别地分发给所有“级别达标”的 handler。这正是原代码中 loggerEven.error("Uneven") 同时写入 Even.txt 和 UnEven.txt 的根本原因——因为 UnEven.txt 的 level 设为 "ERROR",而 error() 发出的日志级别为 ERROR,自然触发该 sink;同时 Even.txt 的 level 是 "INFO"(ERROR ≥ INFO),因此也一并接收。
关键误区在于:level 控制的是「最低准入门槛」,而非「独占路由」。要实现精准分流,必须使用 filter 参数——它支持函数或字符串形式,用于对每条日志进行细粒度判断,返回 True 才允许该日志进入当前 handler。
✅ 正确做法如下(推荐函数式 filter):
from loguru import logger
import random
# 清空默认 handler,避免干扰
logger.remove()
# 只接收 INFO 级别且不包含 ERROR/CRITICAL 的日志
logger.add("Even.txt", level="INFO", filter=lambda record: record["level"].no <= 20) # INFO 的 no 是 20
# 只接收 ERROR 及以上级别(ERROR=40, CRITICAL=50)
logger.add("UnEven.txt", level="ERROR", filter=lambda record: record["level"].no >= 40)
x = random.randint(0, 11)
print(x)
if x % 2 == 1:
logger.error("Uneven") # ✅ 仅写入 UnEven.txt
else:
logger.info("Even") # ✅ 仅写入 Even.txt⚠️ 注意事项:
- logger.remove() 在添加自定义 handler 前调用,防止日志重复输出到控制台或旧文件;
- filter 函数接收 record 字典(含 level, message, extra 等字段),务必返回布尔值;
- 若需更灵活控制(如按模块名、自定义标签分流),可结合 record["extra"] 使用:
logger.bind(category="auth").error("Login failed") logger.add("auth.log", filter=lambda r: r["extra"].get("category") == "auth")
总结:Loguru 的 level 是“闸门高度”,filter 才是“定向阀门”。要实现单日志单路径的精确落盘,filter 不可替代——这是 Loguru 实现多维度日志路由的标准且唯一可靠方式。










