头图

最近在go-zero中使用了一些三方包集成内部的链路追踪, 部分代码如下

package main

import (
    "fmt"
    "github.com/zeromicro/go-zero/zrpc"
)

func main() {
    
    // 1. 获取服务依赖的配置
    svcCtx := svc.NewServiceContext()
    
    // 2. 实例化服务但配置, 实际上这里的代码会调用 otel.SetTracerProvider()
    // server.NewServer() => 
    // service.SetUp => 
    // trace.StartAgent => 
    // trace.startAgent() => 
    // otel.SetTracerProvider()
    s := zrpc.MustNewServer()
    defer s.Stop()


    fmt.Printf("Starting rpc server at %s...\n", svcCtx.Config.ListenOn)
    s.Start()
}

package svc

import (
    "time"

    "github.com/redis/go-redis/extra/redisotel/v9"
    "github.com/redis/go-redis/v9"
    "gorm.io/driver/mysql"
    "gorm.io/gorm"
    "gorm.io/plugin/opentelemetry/tracing"
    "github.com/zeromicro/go-zero/zrpc"
)

func NewServiceContext() {

    conn, err := gorm.Open()
    redisClient := redis.NewClient()
    
    // 1.1 增加 链路追踪
    // 这以下两个方法都会调用 otel.GetTracerProvider()
    redisotel.InstrumentTracing(redisClient)
    conn.Use(tracing.NewPlugin(tracing.WithoutMetrics()))
    
    // return xxx
}

代码追踪

  • otel包的代码也很简单, 就是为了包装一层标准, 实际上是调用了global
package otel // import "go.opentelemetry.io/otel"

import (
    "go.opentelemetry.io/otel/internal/global"
    "go.opentelemetry.io/otel/trace"
)


func Tracer(name string, opts ...trace.TracerOption) trace.Tracer {
    return GetTracerProvider().Tracer(name, opts...)
}

func GetTracerProvider() trace.TracerProvider {
    return global.TracerProvider()
}

func SetTracerProvider(tp trace.TracerProvider) {
    global.SetTracerProvider(tp)
}
  • global包的代码也很简单, 就是为了包装一层标准, 实际上是调用了global
  • 代码也没什么特别的, 只是使用了原子返回了一个默认的实例
  • 最主要的就是SetTracerProvider方法, 它会通过TracerProvider拿到当前的实例(gorm,redis已经用的那个)
  • 然后把当前要设置的tp传递给原来的的那个(且只会执行一次)
package global // import "go.opentelemetry.io/otel/internal/global"

import (
    "sync"
    "sync/atomic"

    "go.opentelemetry.io/otel/metric"
    "go.opentelemetry.io/otel/propagation"
    "go.opentelemetry.io/otel/trace"
)

var (
    globalTracer        = defaultTracerValue()
    delegateTraceOnce             sync.Once
    delegateTextMapPropagatorOnce sync.Once
    delegateMeterOnce             sync.Once
)

type (
    tracerProviderHolder struct {
        tp trace.TracerProvider
    }

    propagatorsHolder struct {
        tm propagation.TextMapPropagator
    }

    meterProviderHolder struct {
        mp metric.MeterProvider
    }
)

func TracerProvider() trace.TracerProvider {
    return globalTracer.Load().(tracerProviderHolder).tp
}

func SetTracerProvider(tp trace.TracerProvider) {
    current := TracerProvider()

    if _, cOk := current.(*tracerProvider); cOk {
        if _, tpOk := tp.(*tracerProvider); tpOk && current == tp {
            // Do not assign the default delegating TracerProvider to delegate
            // to itself.
            Error(
                errors.New("no delegate configured in tracer provider"),
                "Setting tracer provider to its current value. No delegate will be configured",
            )
            return
        }
    }

    delegateTraceOnce.Do(func() {
        if def, ok := current.(*tracerProvider); ok {
            def.setDelegate(tp)
        }
    })
    globalTracer.Store(tracerProviderHolder{tp: tp})
}

func defaultTracerValue() *atomic.Value {
    v := &atomic.Value{}
    v.Store(tracerProviderHolder{tp: &tracerProvider{}})
    return v
}

图解

  ┌───────────────────┐
  │                   │
  │                   │
  │  tracer.Start()   ├──────────────────────────────┐
  │  tracer.Tracer()  │                              │
  │                   │                              │
  │                   │               6. 实 际 是 使 用 delegate 去 调 用 对 应 的 方 法
  ├───────────────────┘                              │
  │                                                  │          zrpc.MustNewServer()
  │  go-redis/gorm/x                                 │                 │
  │   tracer = otel.GetTracerProvider()──┐           │                 │
  │                                      │           │                 │
  │                                      │           │        4. 设 置 链 路 追 踪 服 务 提 供 者
                           2. get global default     │                 │
                                         │           │                 │
┌───────────package global─────────────  │ ───────┐  │                 ▼
│                                        ▼        │  │        otel.SetTracerProvider()
│           ┌───────────────TracerProvider()      │  │                 │ tp = 0x03
│           │                                     │  │                 │
│           │                                     │  │                 │
│           │                                     │  │                 ▼
│   3. return global default                      │  │      ┌─ global.SetTracerProvider()
│           │                                     │  │      │          │
│           ▼                                     │  │      │          │
│  ┌─►globalTracer tracerProviderHolder = 0x01    │  │      │  5. 修改当前全局默认
│  │    tp tracerProvider = 0x02         ┌────┐   │  │      │          │
│  │      delegate trace.TracerProvider =│nil │   │  │      │          ▼
│  │                                     │    │   │  │      │ globalTracer tracerProviderHolder = 0x04
│  │                                     │    │      │      │   tp tracerProvider = 0x03
│ 1. init global default                 │0x03│◄─────┘      │
│  │                                     └────┘             │
│  └──defaultTracerValue()                 ▲      │         │
│                                          │      │         │
└────────────────────────────────────────  │ ─────┘         │
                                           │                │
                                           │                │
                                           │                │
                                           │                │
                                           │                │
                                           │       5-1. 把 delegate 从 nil => 0x03
                                           │                │
                                           │                │
                                           └────────────────┘
  • 调试断点的值也能说明这一点

seth-shi
1.8k 声望231 粉丝

当神不再是我们的信仰,那么信仰自己吧,努力让自己变好,不辜负自己的信仰!