3. OpenTelemetry 核心概念:Trace、Span、Context 传播与 Resource/Attribute

在构建可观测性体系时,OpenTelemetry(OTel)已成为链路数据采集的事实标准。要理解如何将 Loki 日志标签与链路关联,必须先掌握 OTel 的四大核心抽象:Trace、Span、Context 传播机制,以及 Resource 与 Attribute 的作用。本节将逐一拆解这些概念,并说明它们在日志-链路关联中的位置。

3.1 Trace 与 Span:链路的基本单元

Trace 代表一次完整的请求生命周期,从入口到所有下游依赖返回。它由一组具有相同 Trace ID 的 Span 组成。Span 是链路中的最小工作单元,记录一个操作(如 HTTP 请求、数据库查询、函数调用)的开始、结束、状态和元数据。

概念 定义 关键字段 在关联中的角色
Trace 端到端请求的完整路径 TraceID(全局唯一) 作为日志与链路的关联键
Span 单个操作的时间片 SpanID、ParentSpanID、StartTime、EndTime 提供操作级上下文与耗时
SpanContext Span 的可传播标识 TraceID、SpanID、TraceFlags、TraceState 跨进程传递关联信息
关键认知:TraceID 是连接日志与链路的“万能钥匙”。在日志中注入 TraceID,即可在 Loki 中通过标签快速跳转到对应的链路详情页。

3.2 Context 传播机制:跨进程的“隐形线”

Context 传播是 OTel 最核心的机制之一。它确保 TraceID 和 SpanID 能在微服务之间、线程之间、异步回调之间无缝传递,从而将分散的 Span 串联成完整的 Trace。

传播分为两个层面:

  • 进程内传播:通过语言运行时上下文(如 Go 的 context.Context、Java 的 ThreadLocal)传递 SpanContext。
  • 进程间传播:通过协议头(如 HTTP 的 traceparent、tracestate)或消息队列元数据传递 SpanContext。
实战要点:在日志采集时,必须从当前 Context 中提取 TraceID。如果 Context 传播链路断裂(例如异步任务未正确传递 Context),日志将丢失 TraceID,导致关联失败。

下图展示了 Context 如何在三个微服务之间传播,并最终将 TraceID 注入日志:

Context 传播与日志注入流程 服务 A 生成 TraceID: abc123 服务 B 接收 TraceID: abc123 服务 C 接收 TraceID: abc123 traceparent traceparent 日志输出(Loki 采集) [服务 A] traceID=abc123 spanID=span1 user=alice action=login [服务 B] traceID=abc123 spanID=span2 db.query=SELECT * FROM users [服务 C] traceID=abc123 spanID=span3 cache.hit=true ttl=3600

3.3 Resource 与 Attribute:元数据的结构化承载

在 OTel 中,Resource 和 Attribute 是附加在 Trace、Span、Metrics 和 Logs 上的元数据。它们为可观测性数据提供上下文,是后续过滤、聚合和关联的基础。

3.3.1 Resource(资源)

Resource 描述产生数据的实体,通常是基础设施或服务实例。它属于静态元数据,在进程生命周期内保持不变。

  • 常见字段:service.name、service.version、host.name、cloud.region、deployment.environment
  • 在 Loki 关联中的作用:Resource 中的 service.name 和 deployment.environment 可直接映射为 Loki 的日志标签,实现服务级和环境的快速筛选。

3.3.2 Attribute(属性)

Attribute 描述 Span 或 Log Record 的动态细节,每个 Span/Log 可以携带不同的 Attribute 集合。

  • 常见字段:http.method、http.status_code、db.system、user.id、error.message
  • 在 Loki 关联中的作用:Attribute 中的高基数字段(如 user.id、order.id)不适合直接作为 Loki 标签,但可以存储在日志正文中,通过 TraceID 关联后按需查询。
维度 Resource Attribute
生命周期 进程级,静态 Span/Log 级,动态
基数 低(服务名、环境等) 高(用户 ID、订单 ID 等)
Loki 标签适用性 非常适合 仅低基数属性适合
关联用途 服务级过滤与分组 操作级细节补充
避坑指南:不要将高基数 Attribute(如 requestId、sessionId)直接设置为 Loki 标签。这会导致标签爆炸,严重降低 Loki 的查询性能。正确做法是将它们保留在日志行内,通过 TraceID 关联后从链路系统获取。

3.4 三者协同:从 Trace 到日志的元数据流动

下图展示了 Resource、Attribute 和 Context 如何在一次请求中协同工作,最终形成可关联的日志与链路数据:

Resource / Attribute / Context 协同架构 Resource 层(进程级静态元数据) service.name=order-service | deployment.environment=production | host.name=ip-10-0-1-23 Span 层(携带 Context 与 Attribute) SpanContext: TraceID=abc123, SpanID=span1 Attribute: http.method=POST, http.status_code=200, user.id=u_9876 Log 层(注入 TraceID + Resource 标签) 日志行: [order-service] traceID=abc123 spanID=span1 | user=u_9876 | order_created

3.5 本节小结

  • Trace / Span 提供请求的完整拓扑与时间线,TraceID 是关联的核心键。
  • Context 传播 确保 TraceID 跨服务、跨线程传递,是日志注入 TraceID 的前提。
  • Resource 提供低基数、静态的服务元数据,适合直接映射为 Loki 标签。
  • Attribute 提供高基数、动态的操作细节,应保留在日志正文中,通过 TraceID 按需查询。
下一阶段准备:在掌握 OTel 核心概念后,第 4 章将深入讲解如何通过 OTel SDK 在日志中自动注入 TraceID,并配置 Loki 标签提取规则,实现日志与链路的实时关联。