Micrometer 系列【41】链路追踪:Micrometer Tracer 接口
文章目录
- 1. Tracer 接口
- 1.1 核心定义
- 1.2 方法定义
- 1.2.1 创建 Span
- 1.2.2 作用域管理
- 1.2.3 上下文获取
- 1.2.4 Baggage 行李透传
- 1.3 内部类 / 内部接口
- 1.3.1 NOOP
- 1.3.2 SpanInScope
- 2. OtelTracer
- 2.1 核心定义
- 2.2 方法定义
- 2.2.1 构造方法
- 2.2.2 方法实现
- 2.3 内部类 / 内部接口
- 2.3.1 EventPublisher 内部接口
- 2.3.2 WrappedSpanInScope
1. Tracer 接口
1.1 核心定义
Tracer是分布式追踪顶层入口API,大量借鉴OpenZipkin Brave设计。
作用:创建Span、管理链路上下文、控制Span作用域、提供Baggage透传能力,继承BaggageManager行李数据管理接口。
相关核心概念:
Trace:一次完整分布式请求链路;Span:链路内一段独立操作单元;Scope(作用域):将Span绑定在线程上下文,让下游代码(日志、拦截器)获取链路信息;TraceContext:存储traceId/spanId/parentSpanId等链路标识;NOOP:无操作空实现,关闭追踪时使用,避免大量if追踪开关判断。
1.2 方法定义
1.2.1 创建 Span
Span nextSpan():根据当前作用域Span生成子Span;无上下文时新建一条Trace(根Span)。@Nullable Span nextSpan(@Nullable Span parent):指定父Span创建子Span;parent为null时等价于无参nextSpan()。Span.Builder spanBuilder():获取Span构建器。需要在Span启动前批量配置属性(启动后无法修改部分字段),常用于Propagator提取上下文后构造Span。ScopedSpan startScopedSpan(String name):简易API。创建Span并自动绑定至当前线程作用域,返回ScopedSpan;调用end()同时关闭作用域。适合单线程同步业务代码。
1.2.2 作用域管理
SpanInScope withSpan(@Nullable Span span):手动将Span置入线程作用域,返回SpanInScope;
⚠️重要区分:
close()只会退出作用域,不会结束Span生命周期,Span必须手动调用end()。
推荐搭配try-with-resources使用。传参null可以清空当前作用域。
1.2.3 上下文获取
CurrentTraceContext currentTraceContext():获取全局链路上下文管理器,负责在线程内读写TraceContext。@Nullable Span currentSpan():获取当前线程作用域内生效的Span,无则返回null。@Nullable SpanCustomizer currentSpanCustomizer():获取当前Span定制器,无需持有Span对象即可添加Tag、事件。TraceContext.Builder traceContextBuilder():构造TraceContext构建器,手动组装链路ID上下文。
1.2.4 Baggage 行李透传
继承自BaggageManager提供跨线程/跨服务透传自定义业务字段能力:
getAllBaggage()getBaggage()createBaggage()
1.3 内部类 / 内部接口
1.3.1 NOOP
追踪关闭时使用的空实现实例,所有方法调用均不产生真实埋点。
TracerNOOP=newTracer(){...};1.3.2 SpanInScope
Span作用域资源对象。
- 职责:绑定/解绑线程上下文;
- 必须执行
close:清理MDC、释放上下文资源,防止上下文泄漏; close不终止Span,仅脱离作用域。
interfaceSpanInScopeextendsCloseable{@Overridevoidclose();}2. OtelTracer
来自micrometer-tracing-bridge-otel模块
2.1 核心定义
OtelTracer是Tracer接口基于OpenTelemetry的桥接实现(bridge)。
上层业务面向micrometer-tracing统一API编程,底层委托OpenTelemetry SDK完成链路创建、上下文管理、Baggage透传,实现可观测层框架与OTel SDK解耦切换。
成员变量:
io.opentelemetry.api.trace.Tracer tracer:原生OpenTelemetry追踪器实例,底层真正创建OTelSpanBaggageManager otelBaggageManager:Baggage行李数据管理器,负责跨上下文业务字段透传OtelCurrentTraceContext otelCurrentTraceContext:链路上下文管理器,维护线程内TraceContextEventPublisher publisher:事件发布器,用于上下文关闭时推送事件
核心映射关系:
| Micrometer Tracing 抽象 | 底层 OpenTelemetry 实体 |
|---|---|
Span | OtelSpan(包装io.opentelemetry.api.trace.Span) |
TraceContext | OtelTraceContext(包装 OTelContext) |
ScopedSpan | OtelScopedSpan |
Span.Builder | OtelSpanBuilder |
Tracer.SpanInScope | WrappedSpanInScope(包装CurrentTraceContext.Scope) |
上层面向抽象,底层切换Otel实现:
- 业务代码只依赖
io.micrometer.tracing.Tracer,不直接依赖OTel原生API; - 底层通过
OtelTracer桥接OpenTelemetry,如果需要可替换为Brave实现,业务无需改动。
补充关键注意点:
OtelTracer属于适配桥接层,业务禁止直接new构造;由micrometer-tracing自动装配;nextSpan(parent)内部存在临时Scope切换逻辑,用来兼容父上下文不在当前线程的场景;Baggage能力全部委派,如需开启跨服务透传,需要正确配置otelBaggageManager;OTel无效Span(Span.getInvalid())统一对外返回null,对齐micrometer-tracing语义。
2.2 方法定义
2.2.1 构造方法
OtelTracer(io.opentelemetry.api.trace.Tracer, OtelCurrentTraceContext, EventPublisher, BaggageManager):完整构造器,可自定义BaggageManager,支持行李透传功能。OtelTracer(io.opentelemetry.api.trace.Tracer, OtelCurrentTraceContext, EventPublisher):简化构造器,内部使用NOOP空实现BaggageManager,关闭行李透传。
2.2.2 方法实现
实现了Micrometer Tracer接口定义的所有方法:
Span nextSpan()Span nextSpan(@Nullable Span parent)ScopedSpan startScopedSpan(String name)Span.Builder spanBuilder()TraceContext.Builder traceContextBuilder()Tracer.SpanInScope withSpan(@Nullable Span span)@Nullable Span currentSpan()SpanCustomizer currentSpanCustomizer()CurrentTraceContext currentTraceContext()
Baggage行李透传(实现BaggageManager)全部方法直接委派otelBaggageManager:
getAllBaggage()/getAllBaggage(TraceContext)getBaggage(String name)/getBaggage(TraceContext, String name)createBaggage(...)标记@Deprecated(推荐使用createBaggageInScope)createBaggageInScope(...)创建绑定作用域的行李数据getBaggageFields()获取允许透传的行李字段列表
2.3 内部类 / 内部接口
2.3.1 EventPublisher 内部接口
事件发布接口,链路上下文关闭时推送事件。
publicinterfaceEventPublisher{voidpublishEvent(Objectevent);}2.3.2 WrappedSpanInScope
SpanInScope实现类,包装CurrentTraceContext.Scope。调用close()时委托释放上下文作用域。
staticclassWrappedSpanInScopeimplementsSpanInScope{finalCurrentTraceContext.Scopescope;@Overridepublicvoidclose(){this.scope.close();}}