本文已参与「新人创作礼」活动,一起开启掘金创作之路。
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埋点
创建span的时候里面都需要传入一个context,同一个服务里面如果想让埋点串起来,必须上一个环节生成的context必须被下个span使用
// 自定义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…