Python日志格式需兼顾人可读与机器可解析,开发用彩色精简格式(asctime、levelname首字母、name、message),生产用ISO时间JSON格式并统一字段命名。

Python 日志格式不是越花哨越好,关键在两点:人一眼能看懂,机器容易切分解析。默认的 %(message)s 太简陋,但加一堆字段又让终端日志臃肿难读。平衡点在于「按场景分层设计」——开发时用可读格式,生产时用结构化格式,且两者字段对齐。
开发环境用彩色 + 精简字段(logging.basicConfig 直接生效)
终端调试最怕翻屏找时间、看不出哪条是 ERROR、分不清模块来源。推荐用 colorlog 配合 4 个核心字段:
-
%(asctime)s:带毫秒,格式设为%H:%M:%S(不显日期,避免行太长) -
%(levelname).1s:只取首字母(E/W/I),配合颜色更直观 -
%(name)s:模块名,不带完整路径(避免myproject.api.v2.handlers.user这种长串) -
%(message)s:消息主体,不加前缀
示例配置:
import logging import colorloghandler = colorlog.StreamHandler() handler.setFormatter(colorlog.ColoredFormatter( '%(log_color)s%(asctime)s %(levelname).1s %(name)s: %(message)s', datefmt='%H:%M:%S', log_colors={'DEBUG': 'cyan', 'INFO': 'green', 'WARNING': 'yellow', 'ERROR': 'red', 'CRITICAL': 'bold_red'} )) logging.basicConfig(level=logging.INFO, handlers=[handler])
生产环境必须用 JSON 格式(json.dumps 输出到文件)
日志进 ELK 或 Loki 后,字段必须可提取、可聚合、无歧义。文本日志靠正则硬切,一改格式就崩。JSON 是唯一稳妥选择,但要注意三点:
立即学习“Python免费学习笔记(深入)”;
- 时间必须用 ISO 8601 字符串(
%(asctime)s默认不是,得用%(created)f+ 自定义 formatter 转) - 不能直接用
%(message)s,要保留原始args和exc_info结构,否则无法还原异常上下文 - 字段名统一小写+下划线(如
log_level而非levelname),避免和不同采集器默认字段冲突
关键字段建议: timestamp、log_level、logger_name、message、module、function、line、traceback(仅 ERROR 及以上才填)
别让 %(pathname)s 暴露绝对路径(安全 & 可移植性)
日志里出现 /home/deploy/app/src/api/handler.py 有风险:暴露部署结构、换服务器路径就变、本地开发和容器环境不一致。解决方法只有两个:
- 用
%(filename)s替代%(pathname)s(只留文件名,丢掉路径) - 如果真需要相对路径,启动时设置
LOG_ROOT = Path(__file__).parent.parent,然后在 formatter 中用str(pathlib.Path(record.pathname).relative_to(LOG_ROOT))
注意:%(funcName)s 和 %(lineno)d 安全可用,它们不带路径信息。
自定义 LogRecord 字段要注册,否则 extra 会丢
想加 request_id 或 user_id?不能只靠 logger.info("msg", extra={"request_id": "abc"})。因为默认 LogRecord 类不认识这些 key,输出时会被过滤。必须提前注册:
import logging注册新字段(只做一次)
for key in ['request_id', 'user_id']: if not hasattr(logging.LogRecord, key): logging.LogRecord.dict[key] = None
然后在 Formatter 中就能用 %(request_id)s
更稳妥的做法是继承 logging.Formatter,重写 format() 方法,在里面动态注入字段,避免污染全局 LogRecord。
最常被忽略的是:日志格式变更后,旧日志解析规则立刻失效。哪怕只是多加一个空格,Logstash 的 grok 模式就匹配不上。上线前务必拿真实日志样本跑一遍解析链路。










