go 先调用 gettracerprovider() 再调用 settracerprovider() 也能上报成功? | go 技术论坛-金年会app官方网

最近在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
}
  • 按理说肯定要先set才能get,而实际上otel采用了委托的方式让我们可以先get然后再set

代码追踪

  • 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 = 0x031. init global default0x03│◄─────┘      │
│  │                                     └────┘             │
│  └──defaulttracervalue()                 ▲      │         │
│                                          │      │         │
└────────────────────────────────────────  │ ─────┘         │
                                           │                │
                                           │                │
                                           │                │
                                           │                │
                                           │                │
                                           │       5-1. 把 delegate 从 nil => 0x03
                                           │                │
                                           │                │
                                           └────────────────┘
  • 调试断点的值也能说明这一点

https://www.shiguopeng.cn/posts/2024092311/1_hu546ff4637d45be818cf3cf25e800a3a8_38592_1024x0_resize_box_3.png

本作品采用《cc 协议》,转载必须注明作者和本文链接
当神不再是我们的信仰,那么信仰自己吧,努力让自己变好,不辜负自己的信仰!
讨论数量: 0
(= ̄ω ̄=)··· 暂无内容!

讨论应以学习和精进为目的。请勿发布不友善或者负能量的内容,与人为善,比聪明更重要!
未填写
文章
42
粉丝
158
喜欢
712
收藏
347
排名:30
访问:22.2 万
博客标签
社区赞助商
网站地图