Python接口日志必须标准化:统一打什么、怎么打、打到哪;用logging替代print;所有入口、分支、异常路径强制记录;每条日志含trace_id/request_id;结构化JSON格式,精简必留字段;分级采样落盘,避免全量DEBUG或ERROR。

Python接口日志不标准化,会导致问题定位慢、上下游排查扯皮、线上故障复盘无从下手。核心不是“要不要打日志”,而是“打什么、怎么打、打到哪”必须统一。
用 logging 替代 print 是底线
直接写 print 无法控制输出级别、格式、目标(文件/网络/标准输出),也进不了日志采集系统(如 ELK、Sentry)。所有接口入口、关键分支、异常路径都必须走 logging。
- 全局配置一次
logging.basicConfig()或用dictConfig,避免每个模块重复初始化 - 每个模块用
logging.getLogger(__name__)获取 logger,保证层级可追溯 - 禁止在生产环境保留
logging.debug(),但开发阶段建议在请求头带X-Debug: true时动态开启 DEBUG 级别日志
每条日志必须含 trace_id 和 request_id
没有唯一请求标识的日志等于没日志。HTTP 接口需从请求中提取或生成 trace_id(如来自 X-Trace-ID 头),并透传至下游;内部调用则用 uuid.uuid4().hex 生成 request_id。
import logging import uuid from flask import requestlogger = logging.getLogger(name)
立即学习“Python免费学习笔记(深入)”;
@app.before_request def set_request_id(): trace_id = request.headers.get('X-Trace-ID', uuid.uuid4().hex) request.request_id = trace_id # 挂载到 request 对象
- 日志格式中强制包含
%(request_id)s字段,通过自定义Formatter注入 - 不要用时间戳代替 trace_id —— 高并发下毫秒级时间可能重复,且跨服务无法串联
- gRPC 或异步任务(Celery)需手动传递 trace_id,否则子任务日志会丢失上下文
结构化日志字段要精简且可索引
JSON 格式日志是标配,但字段不是越多越好。Elasticsearch 等后端对嵌套过深、字段数超限、值过长的文档会丢弃或截断。
- 必留字段:
level、timestamp、request_id、endpoint(如POST /api/v1/user)、status_code、duration_ms、error_type(仅异常时)、error_msg(仅异常时) - 禁用字段:
__dict__全量 dump、原始 request body(敏感且膨胀)、堆栈全路径(用exc_info=True让 logging 自动处理即可) - 用
extra参数注入业务字段,例如:logger.info("user created", extra={"user_id": 123, "plan": "pro"})
日志采样和分级落盘不能省
全量 DEBUG 日志写磁盘,不出三天磁盘告警;全量 ERROR 不采样,Sentry 被打爆。得按场景分流:
- INFO 及以上:写本地文件 + 轮转(
RotatingFileHandler),保留 7 天 - WARNING:同步推送到日志中心(如 Logstash),加
queue缓冲防阻塞 - ERROR:100% 上报 + 触发告警;同时启用采样(如每 100 条 ERROR 记 1 条完整堆栈,其余只记摘要)
- DEBUG:只在 debug 模式下输出到 console,不落盘、不上报
最常被忽略的是:日志 handler 的 level 和 logger 的 level 是两层过滤,漏配一层就导致该写的没写、不该写的刷屏。










