Python 日志
logging 模块分层:logger/handler/formatter;用级别与上下文支撑运维,而不是 print。
#type / concept
#status / growing
#tech / dev
#resource / python
#tech / lang / python
[!info] 关联笔记
Python 日志
这个概念为什么出现
print 无法分级、无法统一格式、难以在库中关闭。logging 提供可配置的诊断通道。
[!abstract] 一句话理解 业务代码拿 logger 打点;handler 决定输出到哪,formatter 决定长什么样,级别控制噪声。
最小可运行示例
先把示例放进业务场景,再看代码:
场景:下单路径记录 info 与错误
# order_logging_demo.py
# 业务意图:用标准 logging 记录下单成功/失败。
# 教学点:
# - getLogger;
# - basicConfig;
# - 异常日志。
import logging
logger = logging.getLogger("billing.order")
def place_order(user_id: str, ok: bool) -> None:
logger.info("placing order user=%s", user_id)
if not ok:
try:
raise RuntimeError("payment declined")
except RuntimeError:
logger.exception("order failed user=%s", user_id)
raise
logger.info("order ok user=%s", user_id)
def main() -> None:
logging.basicConfig(level=logging.INFO, format="%(levelname)s %(name)s: %(message)s")
place_order("u1", True)
try:
place_order("u2", False)
except RuntimeError:
pass
if __name__ == "__main__":
main()
建议运行:
python order_logging_demo.py
期望输出(含 traceback 片段):
INFO billing.order: placing order user=u1
INFO billing.order: order ok user=u1
INFO billing.order: placing order user=u2
ERROR billing.order: order failed user=u2
Traceback (most recent call last):
...
RuntimeError: payment declined
结合场景再看三个关注点
- 库用 getLogger(name),应用配置 handler。
- exception 带堆栈。
- 结构化字段(JSON logs)在生产更易检索。
核心概念与准确模型
- Logger → Handler → Formatter
- 级别:DEBUG/INFO/WARNING/ERROR/CRITICAL
- 传播 propagate
- 过滤器 Filter
边界情况与反直觉行为
- 未配置时 “最后手段” handler 行为。
- 多进程日志 文件写入要小心。
- 敏感数据 脱敏。
常见误区
[!warning] 常见误区:库里 basicConfig 错误理解:方便。
正确模型:库只打点,应用配置。
工程实践
- 请求 ID 写入上下文
- 级别可动态调
- 与指标/追踪关联
本节总结
日志是运行时叙事。设计字段与级别,比堆 print 重要。
自测题
- 为何用
%s惰性格式化? - 库为何不 basicConfig?
参考答案
- 未启用该级别时可避免格式化开销(经典建议)。
- 避免抢占应用的全局日志策略。
延伸阅读与资料来源
| 资料 | 类型 | 支撑内容 |
|---|---|---|
| logging | 文档 | 标准库 |
| Logging HOWTO | HOWTO | 实践 |