Go中如何让otelgin与otelgrpc共用同一TraceId实现链路追踪?
解决otelgin TraceId无法传递到otelgrpc的问题
核心问题是你在Gin调用gRPC时,没把包含追踪信息的上下文正确传递过去,导致gRPC请求重新生成了新的链路。按下面步骤排查修复:
1. 确保Gin侧正确传递上下文
otelgin中间件已经把TraceId等追踪数据注入到*gin.Context的Request Context里了,调用gRPC时绝对不能用context.Background(),必须传c.Request.Context():
func yourGinHandler(c *gin.Context) { // 正确做法:使用Gin请求上下文 ctx := c.Request.Context() resp, err := client.CallGRPCMethod(ctx, req) if err != nil { c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()}) return } c.JSON(http.StatusOK, resp) }
2. 配置gRPC客户端的otel拦截器
创建gRPC客户端时,必须添加otelgrpc的客户端拦截器,这样才能把上下文里的追踪信息编码到gRPC请求的元数据中:
import ( "google.golang.org/grpc" "go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc" ) func newGRPCClient() YourGRPCClient { conn, err := grpc.Dial( "grpc-server:50051", grpc.WithInsecure(), // 生产环境替换为TLS配置 // 关键:添加otelgrpc客户端拦截器 grpc.WithUnaryInterceptor(otelgrpc.UnaryClientInterceptor()), // 若使用流式请求,需额外添加流式拦截器 // grpc.WithStreamInterceptor(otelgrpc.StreamClientInterceptor()), ) if err != nil { panic(err) } return NewYourGRPCClient(conn) }
3. 确保gRPC服务端配置了otel拦截器
gRPC服务端也要配置otelgrpc的服务端拦截器,才能解析请求元数据里的追踪信息,关联到同一个链路:
func startGRPCServer() { server := grpc.NewServer( grpc.UnaryInterceptor(otelgrpc.UnaryServerInterceptor()), grpc.StreamInterceptor(otelgrpc.StreamServerInterceptor()), ) RegisterYourGRPCServiceServer(server, &yourService{}) lis, err := net.Listen("tcp", ":50051") if err != nil { panic(err) } if err := server.Serve(lis); err != nil { panic(err) } }
额外检查点
- 确认OpenTelemetry TracerProvider是全局共享的,Gin和gRPC客户端/服务端都使用同一个实例(未显式设置时默认全局实例即可)
- 排查是否有自定义中间件或代码修改了Request Context,导致追踪信息丢失
内容的提问来源于stack exchange,提问作者hei-jack
相关产品推荐
相关产品推荐

