golang gin完美接入skywalking

687 阅读2分钟

本文已参与「新人创作礼」活动,一起开启掘金创作之路。

1.新建tracer包

作为skywalking的逻辑在gin初始化的逻辑后, 用InitSwMiddlewaresCustomize方法进行初始化。

package tracer

import (
   "github.com/SkyAPM/go2sky"
   "github.com/SkyAPM/go2sky-plugins/kafkareporter"
   "strings"
   "github.com/SkyAPM/go2sky"
   v3 "github.com/SkyAPM/go2sky-plugins/gin/v3"
   "github.com/gin-gonic/gin"
   "github.com/pkg/errors"
   "os"
)

type skywalking struct {
   tracer  *go2sky.Tracer
   Setting *Setting
}

type Setting struct {
   enable      bool
   GroupName   string
   ServiceName string
   // kafka 0\http 1\grpc 2
   SendType int
   // kafka \http\grpc url
   SendUrl string
}


var skTracer = new(skywalking)


func InitSwMiddlewaresCustomize(e *gin.Engine, setting *Setting) {
   initSkyWalking(setting)
   _, err := GetTracer()

   e.Use(v3.Middleware(e, go2sky.GetGlobalTracer()))
}

func initSkyWalking(setting *Setting) {
   skTracer.Setting = setting

   rep, err := kafkareporter.New(strings.Split(setting.SendUrl, ","))
   if err != nil {
      app.App.GetLogger().Fatalf("new reporter error %v \n", err)
      panic(err)
   }
   groupname := setting.GroupName
   servername := setting.ServiceName

   tracer, err := go2sky.NewTracer(groupname+"::"+servername, go2sky.WithReporter(rep))
   if err != nil {
      app.App.GetLogger().Fatalf("new report race err %v \n", err)
      panic(err)
   }
   go2sky.SetGlobalTracer(tracer)
   skTracer.tracer = tracer
}


// 将请求方式和完整地址拼在一起作为端点
func getOperationName(c *gin.Context) string {
   return fmt.Sprintf("/%s%s", c.Request.Method, c.FullPath())
}

2. 新建main启动包

package main

func main() {
	e := gin.New()
        var setting = new(Setting)
        // 填充setting相关参数
        InitSwMiddlewaresCustomize(e, setting)
	e.Run(":7001")
}

3. 用tracer去发送span

client -> serviceA -> serviceB

Span有三种类型:LocalSpan、EntrySpan、ExitSpan。 LocalSpan:可以用来表示本程序内的一次调用。 EntrySpan:用来从上游服务提取trace埋点,header里面有个SW-XXXX【具体我也忘了】 的请求头 ExitSpan: 向下游写trace埋点

image.png

创建span的时候里面都需要传入一个context,同一个服务里面如果想让埋点串起来,必须上一个环节生成的context必须被下个span使用

image.png

// 自定义span
span.Tag()
// 打印日志
span.Log(time.Now(), "test log info")
// 节点会变红
span.Error(time.Now(), "test log error")

在实际应用中,我们不可能将参数ctx到处去传参,这会破坏整个项目,所以这个ctx需要做到全局缓存,那么存储的key是什么呢?在Gin中,一个请求过来是由一个Goroutine来处理的,我们可以将GoroutineID作为key,并使用并发安全的sync.Map。使用这种方法的时候你需要明确每个协程的边界。

func goID() uint64 {
	b := make([]byte, 64)
	b = b[:runtime.Stack(b, false)]
	b = bytes.TrimPrefix(b, []byte("goroutine "))
	b = b[:bytes.IndexByte(b, ' ')]
	n, _ := strconv.ParseUint(string(b), 10, 64)
	return n
}

除了上述几种方式去手动埋点,还可以用go2sky插件里面封装过的库去执行请求,就会自动带上。 github.com/SkyAPM/go2s…