使用otgrpc配合jaeger在grpc调用链中实现链路追踪

使用otgrpc配合jaeger在grpc调用链中实现追踪


1.下载otgrpc源码:

otgrpc.zip


2.修改源码:在client.go文件48行加入

ginContext := ctx.Value("ginContext")
switch ginContext.(type) {
case *gin.Context:
   if itracer, ok := ginContext.(*gin.Context).Get("tracer"); ok {
      tracer = itracer.(opentracing.Tracer)
   }
   if parentSpan, ok := ginContext.(*gin.Context).Get("parentSpan"); ok {
      parentCtx = parentSpan.(*jaeger.Span).Context()
   }
}


   在server.go文件36行加入

if info.FullMethod != "/grpc.health.v1.Health/Check" {

  在server.go文件72行加入

} else {
   resp, err = handler(ctx, req)
   return resp, err
}


在 gin 中添加中间件:

package middlewares

import (
   "github.com/gin-gonic/gin"
   "github.com/uber/jaeger-client-go"
   jaegercfg "github.com/uber/jaeger-client-go/config"
)

func Trac() gin.HandlerFunc {
   return func(c *gin.Context) {
      cfg := jaegercfg.Configuration{
         Sampler: &jaegercfg.SamplerConfig{
            Type:  jaeger.SamplerTypeConst,
            Param: 1,
         },
         Reporter: &jaegercfg.ReporterConfig{
            LogSpans:           true,
            LocalAgentHostPort: "192.168.0.104:6831",
         },
         ServiceName: "mxshop",
      }

      tracer, closer, err := cfg.NewTracer(jaegercfg.Logger(jaeger.StdLogger))
      if err != nil {
         return
      }
      defer closer.Close()

      startSpan := tracer.StartSpan(c.Request.URL.Path)
      defer startSpan.Finish()

      c.Set("tracer", tracer)
      c.Set("parentSpan", startSpan)
      c.Next()
   }
}
func InitGoodsRouter(Router *gin.RouterGroup) {
   r := Router.Group("/goods").Use(middlewares.Trac()) //修改此处
   {
      r.GET("/list", goods.List)
      r.GET("/detail/:id", goods.Detail)
      r.POST("/batch", goods.Batch)
      r.POST("/create", middlewares.JWTAuth(), middlewares.IsAdmin(), goods.Create)

      r.DELETE("/:id", middlewares.JWTAuth(), middlewares.IsAdmin(), goods.Delete)
      r.PUT("/:id", middlewares.JWTAuth(), middlewares.IsAdmin(), goods.Update)
      r.PATCH("/:id", middlewares.JWTAuth(), middlewares.IsAdmin(), goods.UpdateStatus)
   }
}

在连接grpc服务端处添加一个拦截器:

conn, err := grpc.Dial(fmt.Sprintf("consul://%s:%d/%s?wait=1s", host, port, global.ServerConfig.Goods.Name),
   grpc.WithInsecure(),
   grpc.WithDefaultServiceConfig(`{"loadBalancingPolicy":"round_robin"}`),
   grpc.WithUnaryInterceptor(otgrpc.OpenTracingClientInterceptor(opentracing.GlobalTracer())), //这一行是添加的拦截器代码
)
closeAllClientConn()

在调用grpc服务端方法处修改context:

list, err := global.GoodsClient.GoodsList(context.WithValue(context.Background(), "ginContext", ctx), &req)  //目的是将gin的*gin.context对象传入context中 context.WithValue(context.Background(), "ginContext", ctx)


在grpc服务端NewServer时添加一个拦截器:

cfg := jaegercfg.Configuration{
   Sampler: &jaegercfg.SamplerConfig{
      Type:  jaeger.SamplerTypeConst,
      Param: 1,
   },
   Reporter: &jaegercfg.ReporterConfig{
      LogSpans:           true,
      LocalAgentHostPort: "192.168.0.104:6831",
   },
   ServiceName: "mxshop",
}

tracer, closer, err := cfg.NewTracer(jaegercfg.Logger(jaeger.StdLogger))
if err != nil {
   return
}
defer closer.Close()

server := grpc.NewServer(grpc.UnaryInterceptor(otgrpc.OpenTracingServerInterceptor(tracer)))  //这里把上面生成的tracer传入


在grpc服务端方法中获取父span:

import "github.com/opentracing/opentracing-go"  //需要把这个玩意引入进来
...
parentSpan := opentracing.SpanFromContext(o.Ctx)  //此处的ctx就是 grpc方法中的(ctx context.Context)参数


在grpc服务端方法中添加子span:

goodsSpan := opentracing.GlobalTracer().StartSpan("goods_span", opentracing.ChildOf(parentSpan.Context())) //指明父span
goods, err := global.GoodsClient.BatchGetGoods(context.Background(), &protoGoods.BatchGoodsIdInfo{    //grpc调用其他微服务
   Id: goodsIds,
})
goodsSpan.Finish() //调用完毕之后要及时 Finish


访问gin路由网址之后,我们来查看jaegerUI界面:

使用otgrpc配合jaeger在grpc调用链中实现追踪

最后编辑于:2022/03/02作者: 牛逼PHP

发表评论