• 【GO】LGTM_Grafana_gin_trace中间件(3)_代码实操


    最近在尝试用 LGTM 来实现 Go 微服务的可观测性,就顺便整理一下文档。

    Tempo 会分为 4 篇文章:

    1. Tempo 的架构
    2. 官网测试实操跑通
    3. gin 框架发送 trace 数据到 tempo
    4. go-zero 微服务框架使用发送数据到 tempo

    本文就是写一下如何在 gin server 里面加入 trace 的逻辑

    代码地址:lgtm/example/gin-lgtm at main · zxmfke/lgtm (github.com)


    gin server 接入 trace,是比较简单的,只需要封装一个 tracer 的初始化和中间件就可以了。直接看代码。

    Tracer Init

    初始化一个 tracerProvider,并把这个 tracerProvider 设置为全局的 provider。

    func InitTracer(c Config) error {
    	var err error
    
    	err = tracerProvider(c)
    	...
    	otel.SetTracerProvider(tp)
    
    	return nil
    }
    
    func createExporter(c Config) (tracesdk.SpanExporter, error) {
    	switch c.Batcher {
    	case kindZipKin:
    		return zipkin.New(c.Endpoint)
    	case kindOtlphttp:
    		opts := []otlptracehttp.Option{
    			otlptracehttp.WithInsecure(),
    			otlptracehttp.WithEndpoint(c.Endpoint),
    		}
    		return otlptracehttp.New(context.Background(), opts...)
    
    	case kindOtlpgrpc:
    
    		opts := []otlptracegrpc.Option{
    			otlptracegrpc.WithInsecure(),
    			otlptracegrpc.WithEndpoint(c.Endpoint),
    		}
    		return otlptracegrpc.New(context.Background(), opts...)
    
    	default:
    		return nil, fmt.Errorf("unknown exporter: %s", c.Batcher)
    	}
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    Tracer Middleware

    利用 gin 路由的中间件模式,添加一个 tracer 的中间件,把要 trace 的路由的信息,在请求前记录并在请求结束后发送到 tempo。

    func Trace(ctx *gin.Context) {
    
    	newSpan := Extract(ctx.Request, "trace-middleware")
    
    	defer newSpan.End()
    
    	ctx.Set(HeaderTraceContextKey, newSpan.spanCtx)
    	ctx.Set(HeaderTraceIDKey, newSpan.SpanID())
    
    	newSpan.Inject(ctx.Request)
    
    	ctx.Next()
    
    	newSpan.SetIntTag("http.status_code", ctx.Writer.Status())
    	if ctx.Writer.Status() == http.StatusOK {
    		newSpan.SetStatus(codes.Ok, "well done")
    		return
    	}
    	newSpan.SetStatus(codes.Error, "something goes wrong")
    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    Main

    在代码仓库的 main.go 逻辑就是初始化,并把 tracer middleware 加入到 router 里面。

    func main() {
    
    	if err := tracer.InitTracer(tracer.Config{
    		ServiceName: "tracer-demo",
    		Endpoint:    "127.0.0.1:4318",
    		Sampler:     1.0,
    		Batcher:     "otlphttp",
    	}); err != nil {
    		fmt.Println(fmt.Errorf("%s", err.Error()))
    		return
    	}
    
    	r := gin.Default()
    
    	r.Use(tracer.Trace)
    	r.GET("/ping", func(ctx *gin.Context) {
    		ctx.JSON(http.StatusOK, gin.H{
    			"message": "pong",
    		})
    	})
    
    	r.POST("/test", func(ctx *gin.Context) {
    
    		Sub(ctx)
    
    		ctx.JSON(http.StatusOK, gin.H{
    			"code": 0,
    			"msg":  "success",
    		})
    
    	})
    
    	r.Run() // listen and serve on 0.0.0.0:8080 (for windows "localhost:8080")
    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35

    请求接口后,可以通过 Grafana Tempo 里面查看

    在这里插入图片描述

  • 相关阅读:
    优思学院|六西格玛将烹饪和美味提升至极致
    在线通过dd命令备份分区
    运行手写数字识别例程出现cuDNN Error: cudnnConvolutionForward failed
    ELK日志收集系统
    石油化工行业商业供应链管理系统:标准化供应商管理,优化企业供应链采购流程
    Linux基本指令——综合操作
    03.分支语句和循环语句
    GBASE 8s基本命令:onstat -k讲解
    【Fabric】libfabric
    高压配电柜电力安全监控解决方案
  • 原文地址:https://blog.csdn.net/weixin_40242845/article/details/133152584