当前位置: 首页 > news >正文

go2sky的封装及使用

初始化go2sky

package skyimport ("encoding/json""github.com/SkyAPM/go2sky""github.com/SkyAPM/go2sky/reporter""log""sync"
)var once sync.Oncevar globalTracer *go2sky.Tracerfunc NewGlobalTracer(addr, srvName string, ops ...ReporterOption) {once.Do(func() {globalTracer = NewTracer(addr, srvName, ops...)})
}func NewTracer(addr, srvName string, ops ...ReporterOption) *go2sky.Tracer {r, err := reporter.NewGRPCReporter(addr)if err != nil {log.Printf("new reporter error %v \n", err)return nil}// new warped reportnr := &Report{Reporter: r}for _, op := range ops {op(nr)}tracer, err := go2sky.NewTracer(srvName, go2sky.WithReporter(nr))if err != nil {log.Printf("create tracer error %v \n", err)}return tracer
}// Report warp go2sky.GRPCReporter
type Report struct {go2sky.Reporterdebug bool
}type ReporterOption func(r *Report)func WithDebug(debug bool) ReporterOption {return func(r *Report) {r.debug = debug}
}func (t *Report) Send(spans []go2sky.ReportedSpan) {t.Reporter.Send(spans)if t.debug {bs, _ := json.Marshal(spans)log.Printf("trace span:%s", string(bs))}
}

操作封装

package skyimport ("context""github.com/SkyAPM/go2sky""github.com/SkyAPM/go2sky/propagation"v3 "skywalking.apache.org/repo/goapi/collect/language/agent/v3""time"
)// Trace 封装 go2sky 的 Span,提供了创建入口、出口和本地 Trace 的方法
// 简化使用 go2sky 的 Span 的流程,屏蔽组件未初始化、创建span报错、span判空,提供了更友好的接口
// DefaultTrace 是一个实现了 Trace 接口的结构体,代表一个有效的 Trace
// NonTrace 是一个实现了 Trace 接口的空结构体,代表一个无效的 Trace
// 当go2sky没有初始化时,返回 NonTrace,避免代码中出现空指针异常
type Trace interface {Context() context.Context                                    // 返回携带链路信息的 context.Context,由 go2sky 生成End()                                                        // 结束当前的 TraceTag(key, value string)                                       // 设置tag,在ui上可以进行过滤SetComponent(int32)                                          // 设置组件ID,skywalking oap-server的component-libraries.yml文件规范了中间件组件的ID,如dubbo=3SetSpanLayer(v3.SpanLayer)                                   // 设置span的类型,例如 v3.SpanLayer_RPCFrameworkChildLocalTrace(optName string) Trace                        // 创建local类型的子TraceChildExitTrace(optName, peer string) (Trace, string, string) // 创建exit类型的子Trace,peer是GetTraceId() string                                          // 获取当前Trace的TraceIdError(time.Time, ...string)                                  // 记录错误信息,time.Time是错误发生的时间,...string是错误信息Log(time.Time, ...string)                                    // 记录错误信息,time.Time是错误发生的时间,...string是错误信息IsExit() bool                                                // 判断是否ExitIsEntry() bool                                               // 判断是否EntryIsNon() bool                                                 // Trace 是 NonTrace 实例 返回 true
}// nonTrace 判读组件是否可用
func noTracer() bool {return globalTracer == nil
}// CreateInnerEntry 自动创建sw8的入口span
func CreateInnerEntry(ctx context.Context, optName string) Trace {if noTracer() {return nonTrace}// CreateEntrySpan 的回调函数返回""时,底层会自动生成相关的内容s, c, err := globalTracer.CreateEntrySpan(ctx, optName, func(headerKey string) (string, error) {return "", nil})return evalTrace(s, c, err)
}// CreateEntry 创建指定sw8 header入口的trace
func CreateEntry(ctx context.Context, optName string, sw8, sw8correlation string) Trace {if noTracer() {return nonTrace}// sw8 header必须符合规范,否则底层会报错s, c, err := globalTracer.CreateEntrySpan(ctx, optName, func(headerKey string) (string, error) {if headerKey == propagation.Header {return sw8, nil}if headerKey == propagation.HeaderCorrelation {return sw8correlation, nil}return "", nil})return evalTrace(s, c, err)
}// CreateExit 创建出口类型的trace,同时返回sw8、sw8correlation,便于开发者透传给下游服务
func CreateExit(ctx context.Context, optName, peer string) (t Trace, sw8, sw8correlation string) {if noTracer() {return nonTrace, "", ""}s, err := globalTracer.CreateExitSpan(ctx, optName, peer, func(headerKey, headerValue string) error {if headerKey == propagation.Header {sw8 = headerValue}if headerKey == propagation.HeaderCorrelation {sw8correlation = headerValue}return nil})return evalTrace(s, ctx, err), sw8, sw8correlation
}// CreateLocal 创建本地类型的trace
func CreateLocal(ctx context.Context, optName string) Trace {if noTracer() {return nonTrace}s, c, err := globalTracer.CreateLocalSpan(ctx, go2sky.WithOperationName(optName))return evalTrace(s, c, err)
}// evalTrace 评估并返回一个 Trace 对象
func evalTrace(s go2sky.Span, c context.Context, err error) Trace {if noTracer() {return nonTrace}if err != nil {return nonTrace}if s == nil {return nonTrace}id := go2sky.TraceID(c)t := &DefaultTrace{ctx:     c,span:    s,traceId: id,}return t
}

Trace实现

NonTrace兜底实现

package skyimport ("context""github.com/SkyAPM/go2sky"v3 "skywalking.apache.org/repo/goapi/collect/language/agent/v3""time"
)var nonTrace = &NonTrace{}type NonTrace struct {
}func NewNonTrace() *NonTrace {return &NonTrace{}
}func (n NonTrace) End() {
}func (n NonTrace) Tag(key, value string) {
}func (n NonTrace) SetComponent(i int32) {
}func (n NonTrace) SetSpanLayer(layer v3.SpanLayer) {
}func (n NonTrace) Context() context.Context {return context.Background()
}func (n NonTrace) ChildLocalTrace(optName string) Trace {return n
}func (n NonTrace) ChildExitTrace(optName, peer string) (Trace, string, string) {return n, "", ""
}func (n NonTrace) GetTraceId() string {return go2sky.EmptyTraceID
}func (n NonTrace) IsExit() bool {return false
}func (n NonTrace) IsEntry() bool {return false
}func (n NonTrace) IsNon() bool {return true
}func (n NonTrace) Error(time time.Time, s ...string) {
}func (n NonTrace) Log(t time.Time, s ...string) {
}

DefaultTrace

package skyimport ("context""github.com/SkyAPM/go2sky"v3 "skywalking.apache.org/repo/goapi/collect/language/agent/v3""sync""time"
)type DefaultTrace struct {ctx     context.Contextspan    go2sky.Spanonce    sync.OncetraceId string
}// End 结束当前的 DefaultTrace
func (t *DefaultTrace) End() {if t == nil {return}if t.span != nil {t.once.Do(func() {t.span.End()})}
}func (t *DefaultTrace) Tag(key, value string) {if t.span != nil {t.span.Tag(go2sky.Tag(key), value)}
}func (t *DefaultTrace) SetComponent(i int32) {if t.span != nil {t.span.SetComponent(i)}
}func (t *DefaultTrace) SetSpanLayer(layer v3.SpanLayer) {if t.span != nil {t.span.SetSpanLayer(layer)}
}func (t *DefaultTrace) Context() context.Context {return t.ctx
}func (t *DefaultTrace) ChildLocalTrace(optName string) Trace {return CreateLocal(t.ctx, optName)
}func (t *DefaultTrace) ChildExitTrace(optName, peer string) (Trace, string, string) {return CreateExit(t.ctx, optName, peer)
}func (t *DefaultTrace) GetTraceId() string {return t.traceId
}func (t *DefaultTrace) IsExit() bool {return t.span != nil && t.span.IsExit()
}func (t *DefaultTrace) IsEntry() bool {return t.span != nil && t.span.IsEntry()
}func (t *DefaultTrace) IsNon() bool {return false
}func (t *DefaultTrace) Error(time time.Time, s ...string) {if t.span != nil {t.span.Error(time, s...)}
}func (t *DefaultTrace) Log(time time.Time, s ...string) {if t.span != nil {t.span.Log(time, s...)}
}

测试代码

package mainimport ("context""demo/farmer/trace/sky""fmt""time"
)func main() {sky.NewGlobalTracer("10.202.244.31:11800", "a-chat-server")entryA := sky.CreateInnerEntry(context.Background(), "test")tid := entryA.GetTraceId()fmt.Println("entryA-traceId:", tid)exit, sw8, _ := sky.CreateExit(entryA.Context(), "call goroutine", "nope")go func(sw8 string) {entryB := sky.CreateEntry(context.Background(), "goroutine", sw8, "")tid := entryB.GetTraceId()fmt.Println("entryB-traceId:", tid)entryB.End()}(sw8)exit.End()entryA.End()time.Sleep(5 * time.Second)
}

jaeger ui展示
在这里插入图片描述
提示:

  1. 父子span的end顺序要有保证,如果父span先end,那么父子span会变成同级的关系,因为它们的segment_id不再相同。
  2. 跨协程要像跨进程一样处理链路追踪
http://www.dtcms.com/a/308460.html

相关文章:

  • LeetCode 刷题【23. 合并 K 个升序链表】
  • Android屏幕适配:从dp到px的转换与今日头条适配方案详解
  • 嵌入式第十六课!!!结构体与共用体
  • 安卓 Activity 四种启动模式(Launch Mode)的核心知识点整理
  • Linux 进程调度管理
  • 如何解决pip安装报错ModuleNotFoundError: No module named ‘plotly’问题
  • SAM附录详解
  • 乱删文件,电脑不能开机,怎么办
  • 电子电路原理学习笔记---第5章特殊用途二极管---第1天
  • XSS跨站脚本攻击详解
  • 从0到1学PHP(九):PHP 会话管理:跟踪用户状态
  • opencv解迷宫
  • Nuitka:将源码编译为 `.pyd`
  • vue+elementui实现问卷调查配置可单选、多选、解答
  • vector的增删改查模拟实现(简单版)【C++】
  • 【ProtoBuf】ProtoBuf安装
  • 力扣面试150(45/150)
  • 【C语言】深度剖析指针(三):回调机制、通用排序与数组指针逻辑
  • esp32s3 + ov2640,给摄像头加上拍照功能,存储到sd卡
  • 109㎡中古风家装:北京业之峰在朝阳区绘就温馨画卷
  • 【实际项目1.2-西门子PLC的报警监控思路】
  • Java多线程详解(1)
  • C#反射的概念与实战
  • [2025CVPR-小样本方向]ImagineFSL:基于VLM的少样本学习的想象基集上的自监督预训练很重要
  • 三方支付详解
  • SQL 中 WHERE 与 HAVING 的用法详解:分组聚合场景下的混用指南
  • 大数据平台数仓数湖hive之拉链表高效实现
  • 深度学习入门:用pytorch跑通GitHub的UNET-ZOO项目
  • 云服务器数据库
  • Camx-查看sensor mode 和效果参数