一、基本介绍
二、TraceID的注入
如果使用GoFrame
框架的Client
,那么所有的请求将会自带TraceID
的注入。GoFrame
的TraceID
使用的是OpenTelemetry
规范,是由十六进制字符组成的的32
字节字符串。
强烈建议大家统一使用gclient
组件,不仅功能全面而且自带链路跟踪能力。
2、服务端
如果使用GoFrame
框架的Server
,如果请求带有TraceID
,那么将会自动承接到Context
中;否则,将会自动注入标准的TraceID
,并传递给后续逻辑。
三、TraceID的获取
1、客户端
如果使用GoFrame
框架的Client
,这里有三种方式。
通过gctx.New/WithCtx
方法创建一个带有TraceID
的Context
,该Context
参数用于传递给请求方法。随后可以通过gctx.CtxId
方法获取整个链路的TraceID
。相关方法:
这里还有个高级的用法,客户端可以自定义TraceID
,使用gtrace.WithTraceID
方法。方法定义如下:
// WithTraceID injects custom trace id into context to propagate.
func WithTraceID(ctx context.Context, traceID string) (context.Context, error)
如果是请求 GoFrame
框架的 Server
,那么在返回请求的 Header
中将会增加 Trace-Id
字段,供客户端读取。
如果使用GoFrame
框架的Server
,直接通过gctx.CtxId
方法即可获取TraceID
。相关方法:
// CtxId retrieves and returns the context id from context.
func CtxId(ctx context.Context) string
四、使用示例
1、HTTP Response Header TraceID
执行后,终端输出:
ADDRESS | METHOD | ROUTE | HANDLER | MIDDLEWARE
----------|--------|-------|-----------------------------------------------------------------|--------------------
:8199 | ALL | / | main.main.func1 |
----------|--------|-------|-----------------------------------------------------------------|--------------------
:8199 | ALL | /* | github.com/gogf/gf/v2/net/ghttp.internalMiddlewareServerTracing | GLOBAL MIDDLEWARE
----------|--------|-------|-----------------------------------------------------------------|--------------------
2022-06-06 21:14:37.245 [INFO] pid[55899]: http server started listening on [:8199]
2022-06-06 21:14:38.247 [INFO] {908d2027560af616e218e912d2ac3972} handler
+---------------------------------------------+
| REQUEST |
+---------------------------------------------+
GET / HTTP/1.1
Host: 127.0.0.1:8199
User-Agent: GClient v2.1.0-rc4 at TXQIANGGUO-MB0
Accept-Encoding: gzip
+---------------------------------------------+
| RESPONSE |
+---------------------------------------------+
HTTP/1.1 200 OK
Connection: close
Content-Length: 32
Content-Type: text/plain; charset=utf-8
Server: GoFrame HTTP Server
Trace-Id: 908d2027560af616e218e912d2ac3972
908d2027560af616e218e912d2ac3972
2、客户端注入TraceID
package main
import (
"time"
"github.com/gogf/gf/v2/frame/g"
"github.com/gogf/gf/v2/net/ghttp"
"github.com/gogf/gf/v2/os/gctx"
)
func main() {
s := g.Server()
s.BindHandler("/", func(r *ghttp.Request) {
traceID := gctx.CtxId(r.Context())
g.Log().Info(r.Context(), "handler")
r.Response.Write(traceID)
})
s.SetPort(8199)
go s.Start()
time.Sleep(time.Second)
ctx := gctx.New()
g.Log().Info(ctx, "request starts")
content := g.Client().GetContent(ctx, "http://127.0.0.1:8199/")
g.Log().Infof(ctx, "response: %s", content)
}
执行后,终端输出:
package main
import (
"context"
"time"
"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/gogf/gf/v2/text/gstr"
)
func main() {
s := g.Server()
s.BindHandler("/", func(r *ghttp.Request) {
g.Log().Info(r.Context(), "handler")
r.Response.Write(traceID)
})
s.SetPort(8199)
time.Sleep(time.Second)
ctx, _ := gtrace.WithTraceID(context.Background(), gstr.Repeat("a", 32))
g.Log().Info(ctx, "request starts")
content := g.Client().GetContent(ctx, "http://127.0.0.1:8199/")
g.Log().Infof(ctx, "response: %s", content)
}
ADDRESS | METHOD | ROUTE | HANDLER | MIDDLEWARE
----------|--------|-------|-----------------------------------------------------------------|--------------------
:8199 | ALL | / | main.main.func1 |
----------|--------|-------|-----------------------------------------------------------------|--------------------
:8199 | ALL | /* | github.com/gogf/gf/v2/net/ghttp.internalMiddlewareServerTracing | GLOBAL MIDDLEWARE
----------|--------|-------|-----------------------------------------------------------------|--------------------
2022-06-06 21:40:03.897 [INFO] pid[58435]: http server started listening on [:8199]
2022-06-06 21:40:04.900 [INFO] {aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa} request starts
2022-06-06 21:40:04.901 [INFO] {aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa} handler
2022-06-06 21:40:04.901 [INFO] {aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa} response: aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
五、常见问题
1、如果没有使用GoFrame
框架的Client/Server
,如何获取链路的TraceID
?
可以参考GoFrame
框架的Client/Server
的链路跟踪实现,并自行实现一遍,这块可能需要一定成本。
如果使用的第三方Client/Server
组件,请参考第三方组件相关介绍。
2、企业内部服务没有使用标准的OpenTelemetry
规范,但是每个请求都带RequestID
参数,形如 33612a70-990a-11ea-87fe-fd68517e7a2d
,如何和TraceID
结合起来?
根据我的分析,你这个RequestID
的格式和TraceID
规范非常切合,使用的是UUID
字符串,而UUID
可直接转换为TraceID
。建议在自己的Server
内部第一层中间件中将RequestID
转换为TraceID
,通过自定义TraceID
的方式注入到Context
中,并将该Context
传递给后续业务逻辑。
我来给你写个例子吧:
为了演示服务间的链路跟踪能力,这个示例代码中运行了两个HTTP服务,一个内部服务,提供功能逻辑;一个外部服务,供外部的接口调用,它的功能是调用内部服务来实现的。执行后,我们访问:http://127.0.0.1:8299/?RequestID=33612a70-990a-11ea-87fe-fd68517e7a2d
2022-06-07 14:51:21.957 [INFO] openapi specification is disabled
2022-06-07 14:51:21.958 [INTE] ghttp_server.go:78 78198: graceful reload feature is disabled
SERVER | DOMAIN | ADDRESS | METHOD | ROUTE | HANDLER | MIDDLEWARE
-----------------|---------|---------|--------|-------|-----------------------------------------------------------------|--------------------
internalServer | default | :8199 | ALL | / | main.main.func1 |
-----------------|---------|---------|--------|-------|-----------------------------------------------------------------|--------------------
internalServer | default | :8199 | ALL | /* | github.com/gogf/gf/v2/net/ghttp.internalMiddlewareServerTracing | GLOBAL MIDDLEWARE
-----------------|---------|---------|--------|-------|-----------------------------------------------------------------|--------------------
2022-06-07 14:51:21.959 [INFO] pid[78198]: http server started listening on [:8199]
2022-06-07 14:51:21.965 [INFO] openapi specification is disabled
SERVER | DOMAIN | ADDRESS | METHOD | ROUTE | HANDLER | MIDDLEWARE
-----------------|---------|---------|--------|-------|-----------------------------------------------------------------|--------------------
userSideServer | default | :8299 | ALL | / | main.main.func3 |
-----------------|---------|---------|--------|-------|-----------------------------------------------------------------|--------------------
userSideServer | default | :8299 | ALL | /* | github.com/gogf/gf/v2/net/ghttp.internalMiddlewareServerTracing | GLOBAL MIDDLEWARE
-----------------|---------|---------|--------|-------|-----------------------------------------------------------------|--------------------
userSideServer | default | :8299 | ALL | /* | main.main.func2 | GLOBAL MIDDLEWARE
-----------------|---------|---------|--------|-------|-----------------------------------------------------------------|--------------------
2022-06-07 14:51:21.965 [INFO] pid[78198]: http server started listening on [:8299]
2022-06-07 14:53:05.322 [INFO] {33612a70990a11ea87fefd68517e7a2d} request internalServer starts
2022-06-07 14:53:05.323 [INFO] {33612a70990a11ea87fefd68517e7a2d} internalServer response: 33612a70990a11ea87fefd68517e7a2d
我们发现,RequestID
作为TraceID
贯通了整个服务间的链路了呢!