Baggage 不自动跨服务传递,需显式配置 propagator;Kratos tracing.Client() 默认仅传 traceparent 和 tracestate,须添加 propagation.Baggage{} 且必须与 propagation.TraceContext{} 共同使用,否则链路中断;HTTP 与 gRPC 编码格式不同,下游需兼容 OTel SDK;Baggage 值需 URL 编码防截断;context.WithValue 不等价于 Baggage,须用 baggage.ContextWithValues() 显式声明;单个项限 8KB、总量限 128KB,超限静默截断,建议精简字段并启用采样。

Baggage 不自动跨服务传递,必须显式配置 propagator
Kratos 的 tracing.Client() 默认只传 traceparent 和 tracestate,baggage 不在默认传播列表里——哪怕你调用 baggage.ContextWithValues(ctx, "k1", "v1"),下游也收不到。根本原因是 OpenTelemetry 的 propagator 默认不启用 Baggage,Kratos 也没做额外封装。
要让 Baggage 穿透,必须在 client 中间件里显式注入完整 propagator:
tracing.Client(tracing.WithPropagators(propagation.TraceContext{}, propagation.Baggage{}))- 注意:不能只写
propagation.Baggage{},必须和TraceContext{}一起传,否则 trace 链会断 - 这个配置要加在每个发起 outbound 调用的 client 初始化处,比如
http.NewClient()或grpc.Dial()的 middleware 参数里
HTTP 和 gRPC 的 Baggage 传输格式不一致,下游解析可能失败
OpenTelemetry 规范里,Baggage 在 HTTP 和 gRPC 上的编码方式不同:baggage header 是文本格式(如 key1=value1;key2=value2),而 gRPC 是 binary metadata。Kratos 的 tracing.Client() 会自动处理,但前提是下游服务也用了兼容的 OTel SDK(比如 Go 的 go.opentelemetry.io/otel)。
常见踩坑点:
- 下游是旧版 Zipkin 或 Jaeger SDK(非 OTel 原生)→ 它们根本不识别
baggageheader,直接忽略 - 下游用了 OTel 但 propagator 没配全(比如漏了
propagation.Baggage{})→ 收不到,且无任何日志提示 - Baggage value 含空格或特殊字符(如
user name=foo bar)→ HTTP header 会因未 URL 编码而被截断,建议用url.PathEscape包一层再塞进 context
Baggage 和 Context.Value 混用导致值丢失
很多人习惯先用 context.WithValue(ctx, key, val) 存业务参数,再期望它自动变成 Baggage 透传——这是错的。context.Value 是纯内存绑定,不会序列化到 wire 上;Baggage 必须通过 baggage.ContextWithValues() 显式声明。
正确姿势:
- 上游:用
baggage.ContextWithValues(ctx, "tenant_id", "t-123", "env", "prod")替代context.WithValue - 下游:用
baggage.FromContext(ctx)取,不是ctx.Value() - 如果已有大量
context.WithValue代码,可写个中间层函数,在 outbound 前批量把已知 key 提取出来补进 Baggage,但别指望框架自动做
Baggage 大小限制和性能影响容易被忽略
OTLP exporter 默认对单个 Baggage 项限制 8KB,总大小限制 128KB;超出部分会被静默截断——你 log 出来有,下游收到却是空的。更隐蔽的是,Baggage 会在每次 RPC 调用时被序列化、解析、复制,高频小包场景下 CPU 开销明显上升。
建议做法:
- 只传必要字段(如
tenant_id、ab_test_group),避免塞 JSON 或大字符串 - 高并发服务务必开启采样控制:
tracing.Client(tracing.WithSampler(sampling.ParentBased(sampling.TraceIDRatioBased(0.01)))) - 用
otel.SetErrorHandler()注册一个自定义 handler,捕获dropped baggage item类错误,方便及时发现超限











