kratos 框架需显式启用 tracing.server()/client() 中间件并配置 opentelemetry exporter(如 otlp/jaeger),否则 trace 数据不发出;默认使用 nooptracerprovider,须在 main() 早期调用 otel.settracerprovider() 注册真实 provider。

Kratos 框架原生支持 OpenTelemetry,无需额外 SDK 或手动埋点,但必须显式启用 tracing 中间件并配置 exporter,否则 trace 数据不会发出。
kratos 的 tracing 中间件怎么启用
Kratos 的链路追踪能力封装在 middleware/tracing 包中,它不是默认开启的中间件。你需要在 server 初始化时主动注入:
- HTTP server:在
http.Server构造时,把tracing.Server()加入middleware切片 - gRPC server:同理,将
tracing.Server()传给grpc.Server的middleware参数 - 注意:client 端也要配
tracing.Client(),否则跨服务调用会断链
示例(HTTP):
srv := http.NewServer(
http.Address(":8000"),
http.Middleware(
tracing.Server(), // ← 关键一行
recovery.Recovery(),
),
)
为什么配置了中间件却看不到 trace 数据
常见原因不是中间件没启,而是 exporter 没配或配置错误,导致 span 被创建后直接丢弃:
-
tracing.Server()默认使用NoopTracerProvider,即“什么也不做”——这是安全默认值,防止未配置时打满日志或网络 - 必须调用
otel.SetTracerProvider(tp)提前注册一个真实 provider,且该 provider 需绑定 exporter(如 Jaeger、OTLP、Zipkin) - exporter 地址写错、端口不通、协议不匹配(如 OTLP/gRPC vs OTLP/HTTP)都会静默失败,无报错日志
- Kratos 不自动初始化全局 tracer provider,这一步必须由你控制,在
main()最早处完成
tracing.Server() 和 tracing.Client() 的参数差异
两者都接受 tracing.WithFilter() 和 tracing.WithPropagators(),但行为不同:
-
tracing.Server()的 filter 控制哪些请求生成 span(比如跳过健康检查路径/healthz),而 client 的 filter 控制哪些 outbound 请求注入 trace header -
tracing.Client()默认使用otel.GetTextMapPropagator()向下游传递 context,但若下游是旧版 Zipkin 或非 OTel 服务,需显式传propagation.TraceContext{} + propagation.Baggage{} - 两者都默认采样所有请求(
AlwaysSample),高负载服务务必改用ParentBased(TraceIDRatioBased(0.01))控制量级
跨服务调用断链的典型表现和修复点
现象是:A → B → C 链路里,A 和 B 有 span,B → C 的 span 缺失,或 C 的 trace_id 是全新生成的:
- 检查 B 服务是否在发起 HTTP/gRPC call 前,把当前 context 传给了 client 方法(例如
client.Call(ctx, ...)),漏传ctx是最常见断链原因 - 确认 B 的 client middleware 是否真的生效——
tracing.Client()必须作为第一个 middleware 注册,否则被其他 middleware(如 auth、retry)截断 context - 如果 C 是非 Kratos 服务(如 Spring Boot),确保它使用的是 OTel Java Agent 或兼容 OpenTelemetry Propagator 的 SDK,否则无法识别
traceparentheader
真正容易被忽略的是:Kratos 的 tracing 中间件只处理 transport 层(HTTP/gRPC 入口/出口),业务代码里自己起 goroutine 或发 HTTP request(比如用 http.DefaultClient)时,context 不会自动透传,必须手动用 otel.GetTextMapPropagator().Inject() 注入 header。











