返回首页

结构化 JSON 日志:开发者指南

本文提供分布式系统中实现有效日志记录的实用指南。它涵盖 JSON 格式的结构化日志、使用 MDC 上下文传递业务标识符、错误和警告级别的正确分离,以及统一的入口点 (entrypoints) 日志模式。

如何正确编写日志:开发者完整指南
Advertisement 728x90

结构化 JSON 日志:开发者实用指南

日志记录是现代分布式系统中可观测性的核心组成部分。与指标和追踪不同,日志提供了最大的灵活性,用于分析应用事件。本指南提供具体的模式,帮助你使用结构化 JSON 格式、MDC 上下文以及清晰的错误级别分离,实现高效日志记录。

为什么结构化日志优于纯文本日志

传统纯文本日志在控制台阅读很方便,但自动化处理时却会带来巨大麻烦。解析需要复杂的正则表达式,提取特定数据很棘手,修改格式更是噩梦。在分布式系统中,事件发生时需要快速跨多个来源分析,这些问题就成了致命缺陷。

结构化 JSON 日志完美解决了这些痛点:

Google AdInline article slot
  • 简化按特定字段搜索和过滤
  • 支持搜索引擎的部分索引
  • 实现事件后数据提取自动化
  • 便于过滤个人信息并添加元数据

无效的纯文本日志示例:

2025-03-15 10:16:01.795 INFO 12345 --- [nio-8080-exec-1] c.e.UserController : User saved to DB: User{id=123, [email protected], role=USER}

结构化 JSON 日志示例:

{
  "timestamp": "2025-03-22T10:15:30.123Z",
  "level": "ERROR",
  "service": "auth-service",
  "traceId": "1fd7a997-6517-4b63-9baa-4238f8012734",
  "entrypoint": "HTTP request POST /api/user/auth",
  "message": "Failed to authenticate user",
  "user_id": "user-789",
  "error": {
    "type": "InvalidCredentials",
    "details": "Provided password does not match"
  }
}

MDC 实现端到端追踪

SLF4J 中的 Mapped Diagnostic Context (MDC) 解决了在调用链中传递上下文信息的难题。不用手动在每个方法中穿插 ID,MDC 将数据绑定到当前执行线程。

Google AdInline article slot

MDC 关键用法:

  • 业务标识符 — user_id、order_id、transaction_id
  • 技术上下文 — traceId、spanId 用于追踪
  • 入口点元数据 — 入口类型、重试次数
  • 自动清理 — 请求处理后始终清除上下文

MDC 在入口点大放异彩,这里业务 ID 需要从一开始就可用——通常从请求头中提取,早于读取负载。

入口点及其日志记录

入口点 (EP) 是启动业务逻辑执行的抽象。现代应用常见类型:

Google AdInline article slot
  • HTTP/REST 服务端
  • gRPC 服务端
  • Kafka 消费者
  • 定时任务和计划作业
  • 消息队列监听器

每个 EP 应遵循一致的日志模式:

  • 输入 — 请求元数据和负载
  • 执行上下文 — 业务 ID、技术参数
  • 输出 — 处理结果或错误
  • 状态 — 成功/失败(考虑重试)

分布式系统中错误与警告的分离

分布式系统中重试是可靠性标准,直接影响日志策略:

使用 WARN 级别记录:

  • 中间重试尝试的错误
  • 可通过重试修复的瞬时故障
  • 不需立即运维关注的问题

保留 ERROR 级别用于:

  • 最终失败尝试
  • 进一步重试无意义的严重错误
  • 需要立即干预的情况

重试次数从高到低编号(如 2 → 1 → 0),0 表示最后一次尝试。这样过滤最终错误就很简单了。

使用拦截器实现实战

现代框架提供拦截器处理横切关注点。通过拦截器实现入口点日志流程:

  • 上下文初始化 — 在 MDC 中设置 traceId、spanId
  • 记录入口 — 捕获元数据和输入
  • 处理请求 — 执行业务逻辑,MDC 自动传播
  • 记录出口 — 记录结果或错误
  • 清理上下文 — 清除所有 MDC 数据

关键实现组件:

  • 按 EP 类型设置入口/出口日志拦截器
  • 追踪集成(Jaeger、Zipkin)
  • 从请求头自动提取业务 ID
  • 一致的 JSON 日志序列化

结构化日志的必填字段

为确保一致性和易分析,每条日志必须包含:

  • 核心技术字段

- ISO-8601 格式的时间戳

- 日志级别 (ERROR、WARN、INFO、DEBUG)

- 服务名称和版本

- 应用实例 ID

  • 执行上下文

- traceId 和 spanId 用于请求关联

- requestId

- 入口点类型和名称

- 重试次数

  • 业务上下文

- 关键业务 ID (user_id、order_id 等)

- 请求元数据 (HTTP 方法、端点、消费者组)

- 环境 (阶段、区域、集群)

  • 事件数据

- 人类可读消息

- 结构化事件详情

- 错误堆栈 (仅 ERROR)

- 持续时间 (EP 日志)

与可观测性生态集成

结构化日志不是孤立的——它是完整可观测性的一部分:

指标关联:

  • 日志与指标共享 ID
  • 将错误日志链接到错误率指标
  • 用日志为指标异常提供上下文

追踪集成:

  • 日志与追踪统一 traceId/spanId
  • 用日志详情丰富追踪
  • 通过日志调试特定 span

自动化处理:

  • 基于日志模式的告警
  • 事件管理系统钩子
  • 自动提取恢复数据

关键要点

  • JSON 结构化日志 提供机器可读格式,实现无缝自动化处理和分析。
  • MDC 上下文 无需修改方法签名,即可在调用链中传播业务 ID。
  • 清晰的错误/警告分离 支持重试逻辑,减少监控噪音。
  • 统一的 EP 日志模式 确保分布式事务分析的一致性。
  • 标准字段集 实现事件关联和高效搜索。

— Editorial Team

Advertisement 728x90

继续阅读