Categories: GoFrame 教程

GoFrame 链路跟踪-基本示例

单进程示例

单进程的链路跟踪即进程内方法之间的调用链关系。这种场景的跟踪没有涉及到分布式跟踪,比较简单,以该示例作为我们入门的一个例子吧。示例代码地址:https://github.com/gogf/gf/tree/master/example/trace/inprocess

Root Span

root span​即链路中第一个​span​对象。在这里的单进程场景中,往往需要手动创建一个。随后在方法内部创建的​span​都会作为它的子级​span​。

在分布式架构的服务间通信场景中,往往不需要开发者手动创建​root span​,而是由客户端/服务端请求的拦截器来自动创建。

创建​tracer​,生成​root span​:

func main() {
 var ctx = gctx.New()
 tp, err := jaeger.Init(ServiceName, JaegerUdpEndpoint)
 if err != nil {
  g.Log().Fatal(ctx, err)
 }
 defer tp.Shutdown(ctx)

 ctx, span := gtrace.NewSpan(ctx, "main")
 defer span.End()

 // Trace 1.
 user1 := GetUser(ctx, 1)
 g.Dump(user1)

 // Trace 2.
 user100 := GetUser(ctx, 100)
 g.Dump(user100)
}

上述代码创建了一个​root span​,并将该​span​通过​context​传递给​GetUser​方法,以便在​GetUser​方法中将追踪链继续延续下去。

方法间Span创建

// GetUser retrieves and returns hard coded user data for demonstration.
func GetUser(ctx context.Context, id int) g.Map {
 ctx, span := gtrace.NewSpan(ctx, "GetUser")
 defer span.End()
 m := g.Map{}
 gutil.MapMerge(
  m,
  GetInfo(ctx, id),
  GetDetail(ctx, id),
  GetScores(ctx, id),
 )
 return m
}

// GetInfo retrieves and returns hard coded user info for demonstration.
func GetInfo(ctx context.Context, id int) g.Map {
 ctx, span := gtrace.NewSpan(ctx, "GetInfo")
 defer span.End()
 if id == 100 {
  return g.Map{
   "id":     100,
   "name":   "john",
   "gender": 1,
  }
 }
 return nil
}

// GetDetail retrieves and returns hard coded user detail for demonstration.
func GetDetail(ctx context.Context, id int) g.Map {
 ctx, span := gtrace.NewSpan(ctx, "GetDetail")
 defer span.End()
 if id == 100 {
  return g.Map{
   "site":  "https://goframe.org",
   "email": "john@goframe.org",
  }
 }
 return nil
}

// GetScores retrieves and returns hard coded user scores for demonstration.
func GetScores(ctx context.Context, id int) g.Map {
 ctx, span := gtrace.NewSpan(ctx, "GetScores")
 defer span.End()
 if id == 100 {
  return g.Map{
   "math":    100,
   "english": 60,
   "chinese": 50,
  }
 }
 return nil
}

该示例代码展示了多层级方法间的链路信息传递,即是把​ctx​上下文变量作为第一个方法参数传递即可。在方法内部,我们通过的固定语法来创建/开始一个​Span​:

ctx, span := gtrace.NewSpan(ctx, "xxx")
defer span.End()

并通过​defer​的方式调用​span.End​来结束一个​Span​,这样可以很好地记录​Span​生命周期(开始和结束)信息,这些信息都将会展示到链路跟踪系统中。其中​gtrace.NewSpan​方法的第二个参数​spanName​我们直接给定方法的名称即可,这样在链路展示中比较有识别性。

效果查看

执行完上面的程序后,终端输出:

打开​Jaeger UI​: http://localhost:16686/search,可以看到链路追踪的结果:

点击详情可以查看具体信息,包括​span​的调用顺序、调用关系,执行时间轴,以及记录一些​Attributes​和​Events​信息,极大的方便我们定位系统中的异常和发现性能瓶颈:

其中的​tracing-inprocess​是我们​tracer​的名称,该名称往往是服务名称,由于我们这里只有一个进程和一个​tracer​,因此这里只看得到一个服务名称。其中的​main​为我们创建的​root span​名称,其他的​span​为基于该​root span​创建的子级​span​。由于我们在程序中调用了两次​GetUser​方法,因此这里也展示了两次​GetUser​方法的调用。每一次​GetUser​调用的内部又分别去调用了​GetIndo​、​GetDetail​、​GetScores​三个方法,方法间的调用层级关系展示得非常清晰明了,并且每个方法的调用时长都可以看得到。

关于其中每个​span​记录的​Tags​和​Process​信息其实对应了​OpenTelemetry​中的​Attributes​和​Events​信息,这些信息我们放到后续章节去详细介绍。

冒牌SEO

前端开发者,欢迎大家一起沟通和交流。

Share
Published by
冒牌SEO

Recent Posts

聊聊vue3中的defineProps

在Vue 3中,defineP…

1 周 ago

在 Chrome 中删除、允许和管理 Cookie

您可以选择删除现有 Cooki…

2 周 ago

自定义指令:聊聊vue中的自定义指令应用法则

今天我们来聊聊vue中的自定义…

3 周 ago

聊聊Vue中@click.stop和@click.prevent

一起来学下聊聊Vue中@cli…

4 周 ago

Nginx 基本操作:启动、停止、重启命令。

我们来学习Nginx基础操作:…

1 月 ago

Vue3:手动清理keep-alive组件缓存的方法

Vue3中手动清理keep-a…

1 月 ago