第61章|可观测性 1:日志(Logging)体系与结构化日志

指标告诉你“哪里痛”,日志告诉你“为什么痛”。 当一次发布让错误率上升,真正决定排障速度的,不是你有多少日志行,而是这些日志是否 结构化、可关联、可追溯。本章从日志架构、采集链路、字段规范、采样与保留策略讲起, 帮你把“碎片化文本”升级成可用于故障定位和审计取证的工程资产。

Schema

Structured logs

  • timestamp / level / service
  • trace_id / span_id
  • event_name / error_code
Pipeline

Collect → transform → store

  • agent shipping
  • parse/enrich/filter
  • index / object storage
Governance

Cost, retention, audit

  • tiered retention
  • PII masking
  • query guardrails

1. 为什么“能打印日志”不等于“可观测”

最常见的误区是把日志当作调试副产物:每个模块随意输出一段文本。 这种日志在本地看似有用,一旦进入分布式环境就会失效——你无法按请求关联、无法按服务聚合、 无法精确过滤某类错误,最终只能“人肉翻全文”。可观测日志的目标是:在事故发生的分钟级窗口里, 让工程师快速回答三个问题:哪条链路失败、失败原因是什么、影响范围多大

Log pipeline: app stdout → collector → processing → storage/query App Pods JSON logs to stdout trace_id included source events Collector Fluent Bit / Vector batch + backpressure parse & enrich k8s labels, cluster Processor PII redaction drop noisy logs routing by severity Store Loki / Elasticsearch hot + cold tiers query layer
图 1:日志体系是“数据流水线”,不是“打印字符串”。

2. 结构化日志(Structured Logging):字段规范先于工具选型

工具可换,字段规范不能乱。建议至少固定这些字段:`timestamp`、`level`、`service`、`env`、 `trace_id`、`span_id`、`event_name`、`error_code`、`message`、`request_id`。 这样你的日志才能跨服务聚合、跨平台搜索,并与 tracing/metrics 建立联动。

Field Purpose Example
trace_id 关联同一请求链路 c3b6f...e9
event_name 语义化事件分类 checkout.payment.failed
error_code 稳定错误枚举,便于聚合 PAYMENT_TIMEOUT
{
  "timestamp": "2026-03-18T12:34:56.789Z",
  "level": "ERROR",
  "service": "payments-api",
  "env": "prod",
  "trace_id": "6f7259c2f4f9414bbf1d5e5b6f2e85c1",
  "span_id": "0f4e9d8f4b50a2ce",
  "request_id": "req-4dca",
  "event_name": "checkout.payment.failed",
  "error_code": "PAYMENT_TIMEOUT",
  "message": "provider timeout after 3000ms"
}
底线:日志字段命名要有版本规范,不要今天写 `traceId` 明天写 `trace_id`。字段漂移会直接摧毁查询稳定性。

3. 采集与索引:如何在“可查”与“可负担”之间平衡

日志成本通常由三个量级决定:吞吐、保留期、索引粒度。你需要按业务价值分层: `hot` 层用于近期排障(高索引、快查询),`cold` 层用于审计回溯(低成本、慢查询)。 同时要尽量把高基数字段(如 user_id)从默认索引里移出,以避免爆炸性成本增长。

Retention tiers: hot (fast) → warm → cold (cheap) Hot (0-7 days) high index granularity incident troubleshooting Warm (8-30 days) reduced index fields weekly forensics Cold (31+ days) object storage archive audit / compliance
图 2:日志成本治理靠“分层保留 + 索引裁剪”。

4. 与发布治理联动:让日志成为回滚与审计证据

日志体系要服务发布治理。建议给每次发布打 `release_id`、`commit_sha`、`pipeline_run_id`, 并在回滚时也写对应事件。这样你在事故复盘时可以直接回答: “哪次发布后出现异常、异常发生在什么服务、回滚是否恢复、恢复耗时多久”。

{
  "timestamp": "2026-03-18T13:00:00.000Z",
  "level": "INFO",
  "service": "deploy-controller",
  "event_name": "release.promoted",
  "release_id": "rel-20260318-42",
  "commit_sha": "9f3baf2",
  "pipeline_run_id": "gha-18283910",
  "env": "prod",
  "message": "promoted canary to 100%"
}
Release markers in logs: correlate deployment events with incidents time release.promoted error spike rollback.started recovery.confirmed
图 3:把发布标记写进日志,事故定位和复盘会快一个数量级。

5. 安全与隐私:日志不是“可无限复制的明文仓库”

日志里最容易泄露的数据包括 token、手机号、邮箱、身份证号、银行卡号以及内部密钥片段。 你的日志管道必须在入口处做脱敏/掩码(redaction/masking),并限制谁能查什么。 同时要给审计查询留痕:谁在何时查询了哪些索引、导出过哪些数据。

底线:禁止把完整凭据写进日志。出现泄露后,先轮转密钥,再处理历史日志清理和访问审计。

6. 本章清单

  1. 统一结构化日志字段规范,并固定命名风格(snake_case 或 camelCase 选一种)。
  2. 打通日志流水线:采集、解析、增强、过滤、分层存储与查询。
  3. 为发布与回滚增加 release markers(release_id、commit_sha、pipeline_run_id)。
  4. 建立热温冷保留策略,控制索引字段和高基数成本。
  5. 对敏感字段做入口脱敏,并给日志查询加 RBAC 与审计。
  6. 预告下一章:指标(Metrics)与 SLO/SLI,解决“问题规模和优先级”判定。
← 上一章:跨平台对照 2 下一章:可观测性 2 →