文本日志与结构化日志
下面这条文本日志与其下方的结构化日志包含相同的信息。message 和 order_id 筛选即可。每个订单的消息都相同,所以还能统计次数。
选择日志格式
使用 JSON,每行 1 个对象。在所有服务中使用相同的字段名。下表列出基础字段,以及它们在 OpenTelemetry 日志数据模型和 LogBrew 中对应的名称。
OpenTelemetry 的严重程度数值范围是 1 到 24。
INFO 从 9 开始,WARN 从 13 开始,ERROR 从 17 开始,FATAL 从 21 开始。LogBrew 直接接收 OTLP 日志。参见把 OpenTelemetry 数据发送到 LogBrew。
日志最佳实践
保持消息固定
写"payment failed",把订单 ID 放进字段。消息固定后,你就能把它当作 1 类日志来分组、计数和设置告警。
每个字段只用 1 个名称
在order_id 和 orderId 中选定一个,并在所有服务中使用。常见字段使用 OpenTelemetry 语义约定中的名称,例如 http.response.status_code。
按所需的处理动作选择级别
error 表示操作失败。warning 表示程序已经恢复。info 确认工作正常。只在查找故障时使用 debug。
用 UTC 记录时间
使用带毫秒和时区偏移的 RFC 3339,例如2026-11-07T14:21:19.773+00:00。缺少 UTC 和毫秒时,来自不同时区的日志或同一秒内的日志会排错顺序。
添加 Trace ID 和 Span ID
有了这两个 ID,你就能跨服务读取 1 个请求的所有日志。只设置一次服务、环境和版本
在启动时配置它们,而不是在每次调用时配置。缺少版本时,你无法知道是哪次部署引起了变化。在处理错误的地方只记录一次
加上错误类型和错误消息。不要在每一层重复记录同一个错误。不要记录机密信息和个人信息
不要记录密码、令牌、Cookie、请求体或带查询字符串的完整 URL。使用记录器的敏感字段隐藏功能。参见日志脱敏。使用固定的字段名
不要把值用作字段名,例如{"ord_1001": "failed"}。否则每个新值都会新增一个字段,1 个筛选条件就无法找出所有订单。
生产环境向标准输出写 JSON
只在开发环境中使用易读的格式。Python 中的结构化日志
标准logging 模块没有 JSON 格式器。下面的格式器会写出基础字段以及 extra={"fields": {...}} 中的值。
LogBrewLoggingHandler。它会把消息、级别和记录器作为字段发送,并把 extra 中的基本类型值作为元数据发送。参见 Python 日志。
Node.js 中的结构化日志
Pino 默认为每条记录写 1 行 JSON。Winston 通过winston.format.json() 写 JSON。两者都会保留调用时传入的字段和子记录器的字段。两种配置方式以及 Express 日志中的 Trace ID,参见 Node.js 日志。
