python结构化日志设计需兼顾可读性与可解析性,核心是统一记录方式、字段语义和序列化机制;推荐用structlog替代原生logging,通过processor链实现上下文绑定、延迟序列化及json输出,并遵循字段命名规范与敏感信息过滤原则。

Python日志格式设计的核心,是让每条日志既可读、又可解析,便于排查问题和接入日志系统(如ELK、Loki、Datadog)。结构化日志不是简单加个 JSON 字符串,而是从记录方式、字段语义、序列化机制三方面统一设计。
用 logging.Logger + json 模块手动生成结构化日志
这是最直接可控的方式:不依赖第三方库,适合对日志字段有强控制需求的场景。关键点是重写 Logger.makeRecord() 或更常用的是自定义 Handler.emit(),把 LogRecord 的属性转成字典再序列化。
- 固定字段建议包含:
timestamp(ISO8601)、level、logger_name、message、module、funcName、lineno - 业务字段通过
extra参数注入,例如logger.info("user login", extra={"user_id": 123, "ip": "192.168.1.1"}) - 避免在
message中拼接结构化数据(如"user_id=123, status=ok"),应全部落到 JSON 字段里
用 structlog 替代原生 logging(推荐)
structlog 是 Python 结构化日志的事实标准,它不替换 logging,而是在其之上提供键值对式日志构造能力,天然支持绑定上下文、延迟序列化、多格式输出。
- 初始化示例:
import structlog structlog.configure( processors=[ structlog.stdlib.filter_by_level, structlog.stdlib.add_logger_name, structlog.stdlib.add_log_level, structlog.stdlib.PositionalArgumentsFormatter(), structlog.processors.TimeStamper(fmt="iso"), structlog.processors.StackInfoRenderer(), structlog.processors.format_exc_info, structlog.processors.JSONRenderer() # 输出纯 JSON 行 ], context_class=dict, logger_factory=structlog.stdlib.LoggerFactory(), ) - 使用时直接传关键字参数:
log.info("db_query_finished", query_time=0.12, rows=42, table="orders") - 支持绑定全局/局部上下文,比如请求 ID:
log = log.bind(request_id="req-abc123"),后续所有日志自动带上该字段
字段命名与语义规范(避免踩坑)
结构化日志的价值高度依赖字段的一致性。同一业务含义必须用同一字段名,否则聚合分析会失效。
立即学习“Python免费学习笔记(深入)”;
- 时间统一用
timestamp(ISO8601 字符串)或@timestamp(兼容 Elastic Common Schema) - 错误信息优先用
error.type(异常类名)、error.message、error.stacktrace,而非塞进message - 用户相关字段统一前缀
user.:如user.id、user.email;请求相关用http.:如http.method、http.status_code - 避免模糊字段名:不用
data、info、extra,而用具体语义名,如payment.amount、cache.hit
日志输出与接入注意事项
结构化日志最终要能被采集系统正确解析,输出格式和分隔方式很关键。
- 单行 JSON 是最稳妥选择(每行一个合法 JSON 对象),避免换行符出现在 message 或 stacktrace 中导致解析断裂
- 若需兼容传统文本日志查看,可用
structlog.dev.ConsoleRenderer()做开发环境美化,生产环境切回JSONRenderer - 禁止在日志中打印敏感字段(如密码、token、身份证号),应在写入前通过 processor 过滤或脱敏(
structlog.processors.CallsiteParameterAdder可辅助定位但不解决隐私) - 考虑日志体积:大对象(如整个 request body)不要直接打日志,应采样或只记录摘要(hash、size、keys)










