Python日志系统核心是Logger、Handler、Formatter和Filter四大组件协同:Logger决定“记什么”和“往哪送”,Handler负责“怎么发”和“发给谁”,Formatter定义输出格式,Filter实现精细过滤。

Python日志系统的核心在于理解 logging 模块的四大组件如何协同工作:Logger(记录器)、Handler(处理器)、Formatter(格式器)和 Filter(过滤器)。不搞懂它们之间的关系,配置再复杂也容易出错。
Logger 是入口,决定“记什么”和“往哪送”
每个 Logger 都有日志级别(DEBUG、INFO、WARNING、ERROR、CRITICAL),只有 >= 当前级别的日志才会被处理。Logger 本身不输出日志,而是把日志对象(LogRecord)交给它绑定的 Handler。注意:Logger 可以有多个 Handler,也可以不输出(比如只做转发);子 Logger 默认会向父 Logger 传递日志(propagate=True),这是实现分级控制的关键。
- 用
logging.getLogger("a.b.c")获取命名 Logger,推荐按模块名组织,便于统一管理 - 避免直接用
logging.basicConfig(),它只影响 root Logger,掩盖了层级逻辑 - 设置
logger.setLevel(logging.DEBUG)控制本级过滤,但不阻止父级再次过滤
Handler 是出口,决定“怎么发”和“发给谁”
Handler 负责实际的输出动作。常见类型有 StreamHandler(打印到终端)、FileHandler(写入文件)、RotatingFileHandler(自动轮转)、TimedRotatingFileHandler(按时间切分)等。每个 Handler 也可设级别,形成二次过滤。
- 一个 Handler 只能绑定一个 Formatter,但多个 Handler 可共用同一个 Formatter
- 生产环境建议至少配两个 Handler:一个输出到文件(带时间轮转),一个输出到 stderr(用于快速排查)
- 自定义 Handler 很简单——继承
logging.Handler,重写emit()方法即可接入 Kafka、ES 或钉钉通知
Formatter 控制“长啥样”,Filter 控制“让不让过”
Formatter 定义日志字符串的结构,支持 %(asctime)s、%(name)s、%(levelname)s、%(message)s 等占位符;Filter 则是更精细的拦截逻辑,可基于 logger 名、消息内容、甚至自定义条件返回 True/False。
立即学习“Python免费学习笔记(深入)”;
- 推荐在 Formatter 中加入
%(pathname)s:%(lineno)d,方便定位问题代码行 - Filter 不仅能做白名单(如只放行某个模块的日志),还能动态修改 LogRecord 属性(例如脱敏手机号)
- Filter 可添加到 Logger 或 Handler 上,作用范围不同:加在 Logger 上影响所有下游 Handler,加在 Handler 上只影响该输出通道
实战案例:一个带分级输出与错误告警的配置
假设项目结构为 app/ 下有 main.py 和 utils/db.py,要求:
• INFO 及以上写入 daily.log(按天轮转)
• ERROR 及以上同时发邮件(模拟)
• db 模块单独 DEBUG 日志输出到 db_debug.log
- 创建独立 Logger:
db_logger = logging.getLogger("app.utils.db"),设 level=DEBUG - 为 db_logger 单独配 FileHandler + DEBUG Formatter,不 propagate 到 root
- root Logger 配 TimedRotatingFileHandler(level=INFO)和自定义 MailHandler(level=ERROR)
- MailHandler 中重写
emit(),调用 smtplib 发送摘要(注意异常捕获,避免日志系统崩溃)










