分布式链路追踪(三) - Baggage和GoFrame的结合使用

Baggage 概念

Baggage 是 OpenTelemetry 中的一个重要概念,它允许我们在分布式追踪中传递自定义的上下文信息。Baggage 以键值对的形式存在,可以在服务间传递,使得我们能够在不同的服务中访问这些共享的上下文数据。这在跨服务调用时非常有用,例如,我们可以在客户端设置一些调试信息或用户标识,并在服务端获取这些信息,从而实现更灵活的追踪和监控。

客户端代码示例

在客户端,我们初始化链路追踪器(tracer),并创建一个根 Span 来表示整个请求的开始。然后,我们使用 gtrace.SetBaggageValue 方法在上下文中设置 Baggage 信息,这些信息将随着 HTTP 请求一起发送到服务端。

package main

import (
	"github.com/gogf/gf/contrib/trace/otlphttp/v2"
	"github.com/gogf/gf/v2/frame/g"
	"github.com/gogf/gf/v2/net/gtrace"
	"github.com/gogf/gf/v2/os/gctx"
)

const (
	ServiceName       = "tracing-http-client"
	JaegerUdpEndpoint = "127.0.0.1:6831"
)

func main() {
	var ctx = gctx.New()
	shutdown, err := otlphttp.Init(ServiceName, JaegerUdpEndpoint, "/api/traces")
	if err != nil {
		g.Log().Fatal(ctx, err)
	}
	defer shutdown(ctx)
	StartRequests()
}

func StartRequests() {
	ctx, span := gtrace.NewSpan(gctx.New(), "StartRequests")
	defer span.End()
	ctx = gtrace.SetBaggageValue(ctx, "name", "hello")
	content := g.Client().GetContent(ctx, "http://127.0.0.1:8199/hello")
	g.Log().Print(ctx, content)
}

客户端代码解释

初始化链路追踪器:

  • otlphttp.Init(serviceName, endpoint, path):初始化链路追踪器,连接到指定的 tracing 服务。
  • gctx.New():创建一个新的上下文对象。

创建根 Span:

  • gtrace.NewSpan(gctx.New(), "StartRequests"):创建一个根 Span,表示整个请求的开始。

设置 Baggage 信息:

  • gtrace.SetBaggageValue(ctx, "name", "hello"):在上下文中设置 Baggage 信息,键为 name,值为 hello

发送 HTTP 请求:

  • g.Client().GetContent(ctx, "http://127.0.0.1:8199/hello"):发送 HTTP GET 请求,并将上下文传递给请求。
package main

import (
	"fmt"
	"github.com/gogf/gf/contrib/trace/otlphttp/v2"
	"github.com/gogf/gf/v2/frame/g"
	"github.com/gogf/gf/v2/net/ghttp"
	"github.com/gogf/gf/v2/net/gtrace"
	"github.com/gogf/gf/v2/os/gctx"
	"github.com/opentracing/opentracing-go"
	"github.com/uber/jaeger-client-go"
	jaegerCfg "github.com/uber/jaeger-client-go/config"
	"io"
)

const (
	ServiceName       = "tracing-http-server"
	JaegerUdpEndpoint = "localhost:6831"
)

func main() {
	var ctx = gctx.New()
		shutdown, err := otlphttp.Init(ServiceName, JaegerUdpEndpoint, "/api/otlp/traces")
		if err != nil {
			g.Log().Fatal(ctx, err)
		}
		defer shutdown(ctx)
	tracer := opentracing.GlobalTracer()
	span := tracer.StartSpan("in-process-service")
	defer span.Finish()
	s := g.Server()
	s.Group("/", func(group *ghttp.RouterGroup) {
		group.GET("/hello", HelloHandler)
	})
	s.SetPort(8199)
	s.Run()
}

func HelloHandler(r *ghttp.Request) {
	ctx, span := gtrace.NewSpan(r.Context(), "StartRequests")
	defer span.End()
	value := gtrace.GetBaggageVar(ctx, "name").String()
	r.Response.Write("hello:", value)
}

服务端代码解释

初始化链路追踪器:

  • otlphttp.Init(serviceName, endpoint, path):初始化链路追踪器,连接到指定的 tracing 服务。
  • gctx.New():创建一个新的上下文对象。

创建 HTTP 服务器:

  • g.Server():创建一个新的 HTTP 服务器。
  • s.Group("/", func(group *ghttp.RouterGroup) { ... }):定义路由组,处理 /hello 路由。

处理请求:

  • gtrace.NewSpan(r.Context(), "HelloHandler"):创建一个新的 Span,表示请求处理的开始。
  • gtrace.GetBaggageVar(ctx, "name").String():从上下文中获取 Baggage 信息,键为 name
  • r.Response.Write("hello:", value):将获取的 Baggage 信息写入响应中。

效果查看

客户端提交的 baggage 已经被服务端成功接收到并打印返回。并且客户端在输出日志内容的时候也同时输出了 TraceId 信息。TraceId 是一条链路的唯一ID,可以通过该ID检索该链路的所有日志信息,并且也可以通过该 TraceIdJaeger 系统上查询该调用链路详情。

Jaeger UI 中,我们可以看到这次请求涉及到两个服务:otlp-http-clientotlp-http-server,分别表示HTTP请求的客户端和服务端,并且每个服务中分别涉及到 2span 链路节点。

点击这个 trace 的详情,可以看得到调用链的层级关系。并且可以看得到客户端请求的地址、服务端接收的路由以及服务端路由函数名称。我们这里来介绍一下客户端的 Attributes 信息和 Events 信息,也就是 Jaeger 中展示的 Tags 信息和 Process 信息。

打 赏