kratos默认不开启链路追踪,需手动集成opentelemetry:显式引入sdk、配置otlp exporter连接otel-collector、在server/client中分别启用otelhttp.newhandler或otelgrpc.unaryserverinterceptor中间件,并确保context与header中traceparent正确传递。

Kratos 默认不开启链路追踪,必须手动集成 OpenTracing 或 OpenTelemetry
Kratos 本身不内置链路追踪能力,v2.x 后主要适配 OpenTelemetry(OTel),而早期项目可能还在用 OpenTracing(已归档)。直接跑 kratos run 不会产生 span,也不会自动注入 trace-id。你需要显式引入 SDK、配置 exporter,并在 server/client 中启用中间件。
常见错误现象:otel-collector 收不到数据、trace_id 在日志里始终为空、HTTP header 中缺失 traceparent。
- 确认 Kratos 版本:v2.5+ 推荐用
go.opentelemetry.io/otel,避免混用github.com/opentracing - 不要只改
app.go—— server 和 client 的 tracer 初始化是分开的,漏掉任意一端都会断链 - 若用
grpc,需额外注册otelgrpc.Interceptor,HTTP 则用otelhttp.NewHandler包裹 handler
如何配置 OpenTelemetry Exporter 并连接 otel-collector
本地开发最常用的是将 span 推送到 otel-collector(通过 OTLP 协议),而不是直连 Jaeger 或 Zipkin。Kratos 自身不管理 exporter 生命周期,得自己写初始化逻辑。
关键点在于:exporter 必须在 tracing.Init 前创建,且全局 otel.Tracer 需复用同一个 provider 实例,否则 span 会丢失 parent context。
- 启动 collector:用官方
otel-collector-contrib镜像,配置otlpreceiver +logging或jaegerexporter - 代码中调用
otlpgrpc.NewClient时,设WithInsecure()(开发环境)或WithTLSCredentials(生产) - 务必调用
provider.ForceFlush(context.Background())和provider.Shutdown(context.Background()),否则进程退出时 span 可能丢失
exp, err := otlpgrpc.NewClient(otlpgrpc.WithInsecure(), otlpgrpc.WithEndpoint("localhost:4317"))
if err != nil {
panic(err)
}
provider := sdktrace.NewTracerProvider(
sdktrace.WithBatcher(exp),
sdktrace.WithResource(resource.MustNewSchemaVersion(resource.SchemaUrl, semconv.ServiceNameKey.String("user-api"))),
)
Kratos HTTP 和 gRPC Server 如何注入 tracing 中间件
Kratos 的 http.Server 和 grpc.Server 都支持传入 middleware.Middleware 切片,但 tracing 中间件不能简单套用通用 middleware —— 它依赖底层 transport 的 context 传递能力。
HTTP 场景下,otelhttp.NewHandler 是 wrapper 而非 middleware,必须替换原始 http.Handler;gRPC 则需用 otelgrpc.UnaryInterceptor 注册为 interceptor。
- HTTP:不要把
otelhttp.NewHandler当作 middleware 丢进WithMiddleware,而是用它包裹server.HTTPHandler() - gRPC:传入
grpc.ServerOption,例如grpc_middleware.WithUnaryServerChain(otelgrpc.UnaryServerInterceptor()) - 确保 transport 层(如 HTTP header 或 gRPC metadata)携带了
traceparent,否则跨服务链路无法串联
为什么 client 端调用总是不带 trace 上下文
Kratos 的 client.Client 默认不传播 trace context,即使 server 端一切正常,下游服务也收不到 parent span。这不是 bug,是设计选择 —— 传播行为需显式启用。
根本原因是:client 发起请求时未从当前 context 提取 span 并注入到 transport header 中。Kratos 的 transport.GRPCClient 和 transport.HTTPClient 都支持 transport.WithClient 选项,但 tracing 注入要靠 OTel 的 propagator。
- 对 HTTP client:用
otelhttp.NewTransport包装底层http.RoundTripper,再传给http.Client - 对 gRPC client:用
otelgrpc.WithClientTrace创建 dial option,并确保调用时传入带 span 的context.Context - 检查
otel.GetTextMapPropagator().Inject()是否被执行 —— 如果 client 用的是自定义 transport 或跳过了 Kratos 的 transport 封装,就容易漏掉
复杂点在于:一个服务既作 server 又作 client 时,span 的 parent-child 关系极易错乱。最容易被忽略的是 context 传递路径 —— 比如在 goroutine 里忘了用 ctx 而用了 context.Background(),整个链路就断了。











