官方地址:https://www.jaegertracing.io/
[安装]
官方提供了两个安装方式,
1. 基于二进制(https://www.jaegertracing.io/download/#binaries)
2.使用docker
docker run -d --name jaeger \ -e COLLECTOR_ZIPKIN_HOST_PORT=:9411 \ -p 6831:6831/udp \ -p 6832:6832/udp \ -p 5778:5778 \ -p 16686:16686 \ -p 4317:4317 \ -p 4318:4318 \ -p 14250:14250 \ -p 14268:14268 \ -p 14269:14269 \ -p 9411:9411 \ jaegertracing/all-in-one:1.49
我是在windows下使用下载的二进制文件启动服务
注: 需要再终端中执行jaeger-all-in-one.exe即可启动服务
[golang接入]
实现gorm的CRUD的链路记录
Demo文件:
gormTracing.go
package gorm_trace import ( "github.com/opentracing/opentracing-go" tracerLog "github.com/opentracing/opentracing-go/log" "gorm.io/gorm" ) const ( gormSpanKey = "__gorm_span" callBackBeforeName = "opentracing:before" callBackAfterName = "opentracing:after" ) func before(db *gorm.DB) { // 先从父级spans生成子span span, _ := opentracing.StartSpanFromContext(db.Statement.Context, "gorm") // 利用db实例去传递span db.InstanceSet(gormSpanKey, span) return } func after(db *gorm.DB) { // 从GORM的DB实例中取出span _span, isExist := db.InstanceGet(gormSpanKey) if !isExist { return } // 断言进行类型转换 span, ok := _span.(opentracing.Span) if !ok { return } defer span.Finish() // Error if db.Error != nil { span.LogFields(tracerLog.Error(db.Error)) } // sql span.LogFields(tracerLog.String("sql", db.Dialector.Explain(db.Statement.SQL.String(), db.Statement.Vars...))) return } type OpentracingPlugin struct{} func (op *OpentracingPlugin) Name() string { return "opentracingPlugin" } func (op *OpentracingPlugin) Initialize(db *gorm.DB) (err error) { // 开始前 db.Callback().Create().Before("gorm:before_create").Register(callBackBeforeName, before) db.Callback().Query().Before("gorm:query").Register(callBackBeforeName, before) db.Callback().Delete().Before("gorm:before_delete").Register(callBackBeforeName, before) db.Callback().Update().Before("gorm:setup_reflect_value").Register(callBackBeforeName, before) db.Callback().Row().Before("gorm:row").Register(callBackBeforeName, before) db.Callback().Raw().Before("gorm:raw").Register(callBackBeforeName, before) // 结束后 db.Callback().Create().After("gorm:after_create").Register(callBackAfterName, after) db.Callback().Query().After("gorm:after_query").Register(callBackAfterName, after) db.Callback().Delete().After("gorm:after_delete").Register(callBackAfterName, after) db.Callback().Update().After("gorm:after_update").Register(callBackAfterName, after) db.Callback().Row().After("gorm:row").Register(callBackAfterName, after) db.Callback().Raw().After("gorm:raw").Register(callBackAfterName, after) return } var _ gorm.Plugin = &OpentracingPlugin{}
测试文件:
package gorm_trace import ( "context" "fmt" "github.com/opentracing/opentracing-go" "github.com/uber/jaeger-client-go" "github.com/uber/jaeger-client-go/config" "gorm.io/driver/mysql" "gorm.io/gorm" "io" "math/rand" "strconv" "sync" "testing" "time" ) const dsn = "root:123456@tcp(localhost:3306)/test?charset=utf8mb4&parseTime=True&loc=Local" func initJaeger() (closer io.Closer, err error) { // 根据配置初始化Tracer 返回Closer tracer, closer, err := (&config.Configuration{ ServiceName: "gormTracing", Disabled: false, Sampler: &config.SamplerConfig{ Type: jaeger.SamplerTypeConst, // param的值在0到1之间,设置为1则将所有的Operation输出到Reporter Param: 1, }, Reporter: &config.ReporterConfig{ LogSpans: true, LocalAgentHostPort: "localhost:6831", }, }).NewTracer() if err != nil { return } // 设置全局Tracer - 如果不设置将会导致上下文无法生成正确的Span opentracing.SetGlobalTracer(tracer) return } type Product struct { gorm.Model Code string Price uint } func Test_GormTracing(t *testing.T) { closer, err := initJaeger() if err != nil { t.Fatal(err) } defer closer.Close() db, err := gorm.Open(mysql.Open(dsn), &gorm.Config{}) if err != nil { t.Fatal(err) } _ = db.Use(&OpentracingPlugin{}) // 迁移 schema _ = db.AutoMigrate(&Product{}) // 生成新的Span - 注意将span结束掉,不然无法发送对应的结果 span := opentracing.StartSpan("gormTracing unit test") defer span.Finish() // 把生成的Root Span写入到Context上下文,获取一个子Context ctx := opentracing.ContextWithSpan(context.Background(), span) session := db.WithContext(ctx) // Create session.Create(&Product{Code: "D42", Price: 100}) // Read var product Product session.First(&product, 1) // 根据整形主键查找 session.First(&product, "code = ?", "D42") // 查找 code 字段值为 D42 的记录 // Update - 将 product 的 price 更新为 200 session.Model(&product).Update("Price", 200) // Update - 更新多个字段 session.Model(&product).Updates(Product{Price: 200, Code: "F42"}) // 仅更新非零值字段 session.Model(&product).Updates(map[string]interface{}{"Price": 200, "Code": "F42"}) // Delete - 删除 product session.Delete(&product, 1) } func Test_GormTracing2(t *testing.T) { closer, err := initJaeger() if err != nil { t.Fatal(err) } defer closer.Close() db, err := gorm.Open(mysql.Open(dsn), &gorm.Config{}) if err != nil { t.Fatal(err) } _ = db.Use(&OpentracingPlugin{}) rand.Seed(time.Now().UnixNano()) //num, wg := 1<<10, &sync.WaitGroup{} num, wg := 110, &sync.WaitGroup{} wg.Add(num) for i := 0; i < num; i++ { go func(t int) { span := opentracing.StartSpan(fmt.Sprintf("gormTracing unit test %d", t)) defer span.Finish() ctx := opentracing.ContextWithSpan(context.Background(), span) session := db.WithContext(ctx) p := &Product{Code: strconv.Itoa(t), Price: uint(rand.Intn(1 << 10))} session.Create(p) session.First(p, p.ID) session.Delete(p, p.ID) wg.Done() }(i) } wg.Wait() }
[使用]
打开浏览器: http://localhost:16686 即可查看
进行筛选,查看上报的追踪信息
参考:
- https://github.com/avtion/gormTracing
标签:span,err,Jaeger,Register,db,opentracing,链路,gorm,追踪 From: https://www.cnblogs.com/xingxia/p/jaeger.html