3. 数据采集与标准化:日志、Metrics、Tracing 中的 Errors 数据采集规范

在可观测性体系中,Errors 数据分散在日志(Logs)、指标(Metrics)和链路(Tracing)三大信号中。若各信号采用不同的采集粒度、字段命名和严重级别定义,将导致聚合结果不一致、告警重复或遗漏。本章定义一套跨信号、可落地的 Errors 数据采集规范,确保后续聚合与降噪有统一的数据基础。

3.1 三大信号中 Errors 的语义差异与统一模型

日志、指标、链路对“错误”的表述各有侧重,但必须映射到同一个抽象模型才能实现关联分析。下表列出各信号中 Errors 的核心差异:

信号类型 Errors 原始形态 典型粒度 时间维度 关联键
Logs 结构化日志中的 level=ERROR 或 level=FATAL 条目 单条事件 精确时间戳(毫秒/微秒) trace_id、service.name
Metrics Counter 或 Gauge 中的错误计数、错误率、错误持续时间 聚合时间窗口(如 1min、5min) 窗口起始时间 service、error_type、status_code
Tracing Span 中的 status.code = ERROR 或 error=true 属性 单个 Span / 整条 Trace Span 开始时间 + 持续时间 trace_id、span_id、parent_span_id
统一抽象模型: 建议将每个 Error 事件抽象为 { timestamp, service, error_type, error_message, severity, trace_id, span_id, resource_attributes }。日志和链路直接填充该模型;指标则通过聚合窗口内的计数和比率间接映射。

3.2 日志 Errors 采集规范

日志是 Errors 最原始、最详细的来源。采集规范应覆盖字段定义、级别映射和上下文注入三个层面。

3.2.1 必选字段与推荐字段

字段 类型 必选/可选 说明
timestamp RFC3339Nano 必选 事件发生时间,精度到纳秒
level string 必选 仅允许 ERROR、FATAL;禁止使用 WARN 或 INFO 表示错误
error.type string 必选 如 DBConnectionTimeout、ValidationError
error.message string 必选 人类可读的错误描述,禁止包含敏感信息
service.name string 必选 产生该日志的服务名
trace_id string 强烈推荐 关联到分布式链路,用于后续聚合
error.stacktrace string 可选 异常堆栈,用于根因分析

3.2.2 级别映射规则

  • ERROR:可恢复但需要告警的错误,如请求超时、下游服务返回 5xx。
  • FATAL:不可恢复、导致进程或请求立即终止的错误,如内存溢出、配置加载失败。
  • 禁止:将业务逻辑异常(如用户输入校验失败)打印为 ERROR,除非该异常导致系统状态异常。
常见陷阱: 许多团队将 WARN 级别的日志也纳入 Errors 聚合,导致告警量膨胀。规范要求:只有 ERROR 和 FATAL 才进入 Errors 数据管道。WARN 仅用于运营分析,不触发告警。

3.3 Metrics Errors 采集规范

指标层面的 Errors 数据用于趋势监控和告警阈值计算。核心原则是:计数与比率分离,标签维度可控。

3.3.1 标准指标定义

指标名 类型 标签(Labels) 说明
errors_total Counter service, error_type, severity 累计错误计数,单调递增
errors_per_second Gauge service, error_type 每秒错误速率,由 errors_total 计算得出
error_ratio Gauge service, endpoint 错误请求数 / 总请求数,通常取 5min 窗口
error_duration_seconds Histogram service, error_type 错误持续时间的分布,用于检测慢错误

3.3.2 标签基数控制

  • 禁止:将 user_id、request_id、ip 等高基数标签放入 Metrics。
  • 推荐:标签维度不超过 5 个,且每个标签的取值数量应小于 1000。
  • 降维策略:若需要按用户维度分析错误,应通过日志或链路查询,而非 Metrics。

3.4 Tracing Errors 采集规范

链路中的 Errors 信息用于定位错误在分布式调用链中的精确位置。规范聚焦于 Span 状态设置和错误属性传递。

3.4.1 Span 状态码规范

状态码 含义 使用场景
STATUS_CODE_UNSET 未设置(默认) Span 正常完成,无需特殊标记
STATUS_CODE_OK 成功 Span 按预期完成,无错误
STATUS_CODE_ERROR 错误 Span 内发生异常或返回错误响应

3.4.2 错误属性注入

当 Span 状态设为 ERROR 时,必须注入以下属性:

span.set_attribute("error.type", "HTTPRequestFailed")
span.set_attribute("error.message", "GET /api/users returned 503")
span.set_attribute("error.stacktrace", "com.example.Service.call(Service.java:42)")
span.set_attribute("http.status_code", 503)
关键原则: 链路中的错误属性必须与日志中的 error.type 和 error.message 保持一致。建议使用统一的常量类或枚举定义错误类型,避免拼写差异导致关联失败。

3.5 跨信号 Errors 关联架构

下图展示日志、指标、链路中 Errors 数据的采集路径与关联方式:

Errors 数据采集与关联架构 Errors 数据采集与关联架构 Logs level=ERROR / FATAL Metrics errors_total / error_ratio Tracing status.code=ERROR 采集代理 / SDK(统一字段映射) timestamp | service | error_type | error_message | trace_id 统一 Errors 存储(Elasticsearch / Loki / Tempo) 通过 trace_id 和 service.name 关联 Errors 聚合引擎 + 告警降噪 窗口聚合 | 指纹计算 | 抑制规则 说明:采集代理负责将日志、指标、链路中的 Errors 字段统一为规范格式,确保后续聚合时数据口径一致。

3.6 采集规范落地检查清单

在实施采集规范时,建议按以下清单逐项验收:

  1. 日志侧:所有服务是否统一使用 ERROR / FATAL 级别?是否注入 trace_id?
  2. 指标侧:errors_total 是否包含 error_type 标签?标签基数是否控制在 1000 以内?
  3. 链路侧:所有 HTTP/gRPC 客户端是否在收到 5xx 响应时设置 STATUS_CODE_ERROR?
  4. 跨信号:日志中的 error.type 与链路中的 error.type 是否使用同一枚举值?
  5. 采集代理:是否在采集侧完成字段映射,避免在存储层再做二次转换?
推荐工具: 使用 OpenTelemetry Collector 作为统一的采集代理,通过 transform 处理器对日志、指标、链路中的 Errors 字段进行标准化。例如,将日志中的 severity 字段映射为 error.severity,将链路中的 status.code 转换为 error.type。

3.7 本章小结