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 数据的采集路径与关联方式:
3.6 采集规范落地检查清单
在实施采集规范时,建议按以下清单逐项验收:
- 日志侧:所有服务是否统一使用
ERROR/FATAL级别?是否注入trace_id? - 指标侧:
errors_total是否包含error_type标签?标签基数是否控制在 1000 以内? - 链路侧:所有 HTTP/gRPC 客户端是否在收到 5xx 响应时设置
STATUS_CODE_ERROR? - 跨信号:日志中的
error.type与链路中的error.type是否使用同一枚举值? - 采集代理:是否在采集侧完成字段映射,避免在存储层再做二次转换?
推荐工具: 使用 OpenTelemetry Collector 作为统一的采集代理,通过
transform 处理器对日志、指标、链路中的 Errors 字段进行标准化。例如,将日志中的 severity 字段映射为 error.severity,将链路中的 status.code 转换为 error.type。