必须开启Trace: true配置,HTTP入口自动注入trace_id;日志需用logx.WithContext(ctx)输出;RPC调用须显式透传traceparent header;异步goroutine必须传递并使用带trace的context。

要在Go-Zero服务中实现请求链路ID注入并让日志自动串联该ID,必须确保trace_id从HTTP入口开始注入context,并在所有下游日志、RPC调用、goroutine中持续透传——任一环节丢失context或未使用WithContext日志器,链路就会断裂。
HTTP入口自动注入trace_id
go-zero默认已在HTTP Server启动时注册middlewareTracingHandler,只要配置项Trace: true开启,它就会自动从X-Trace-ID或X-Request-ID请求头读取ID;若头不存在,则生成UUIDv4作为新trace_id塞入context。
确认你的etc/xxx.yaml中已启用追踪:
【Trace: true】
这一步不可省略,否则middlewareTracingHandler不会被挂载,后续所有日志和RPC调用都拿不到trace上下文。
日志输出自动携带trace_id
go-zero内置logx日志模块原生支持context感知。只要调用logx.WithContext(ctx),日志行开头就会自动附加[trace=xxx]前缀。
在handler或logic中直接写:
logx.WithContext(r.Context()).Info("用户登录成功")
这条日志会输出为:[trace=8a3f9b1e-2c4d-4e7f-9a0b-5d6e7f8a9b1c] 用户登录成功。
⚠️注意:不能用logx.Info裸调用——它完全无视context,trace_id将彻底丢失。
RPC客户端透传trace_id到下游服务
go-zero的RPC client默认不透传trace信息,必须显式构造metadata并注入context。
方法一:使用go-zero封装的rpcx.Client(推荐)
1. 在internal/svc/servicecontext.go中初始化client时传入rpcx.WithTracing()选项;
2. 调用RPC方法时,直接传入带trace的r.Context(),框架自动提取并注入traceparent header;
方法二:手动注入metadata(兼容自定义gRPC client)
① 从当前context提取trace_id:traceID := trace.ExtractTraceID(r.Context());
② 构造metadata:md := metadata.Pairs("traceparent", fmt.Sprintf("00-%s-0000000000000001-01", traceID));
③ 注入outgoing context:ctx = metadata.NewOutgoingContext(r.Context(), md);
④ 使用该ctx发起RPC调用:resp, err := client.SomeMethod(ctx, req)。
这四步缺一不可,漏掉第③步则下游服务收不到trace信息,链路在RPC边界处中断。
异步goroutine中保持trace上下文
Go语言中goroutine默认不继承父context,必须显式传递。
错误写法:go func() { logx.Info("异步任务") }() → 日志无trace前缀,且无法关联原始请求。
正确写法:go func(ctx context.Context) { logx.WithContext(ctx).Info("异步任务") }(r.Context())。
如果异步逻辑较长,建议用context.WithTimeout或context.WithCancel派生子context,避免原始请求结束而goroutine仍在运行导致trace_id语义失效。











