jaeger客户端初始化报nil pointer dereference的根本原因是未调用cfg.newtracer()或调用前未设置cfg.servicename和cfg.sampler;servicename必设,sampler需指定type与param;须defer tracer.close()防goroutine泄漏;http/grpc需手动注入提取trace上下文;reporter端口协议要匹配;跨goroutine finish span会导致链路截断。

Jaeger客户端初始化为什么总报nil pointer dereference
根本原因是没调用cfg.NewTracer(),或者调用前没正确设置cfg.ServiceName和cfg.Sampler。Jaeger的config.Configuration是值类型,修改字段后必须显式调用NewTracer()生成实例,否则tracer为nil。
- 必须设置
cfg.ServiceName,否则NewTracer()返回nil且不报错 - 采样器不能留空:本地开发用
cfg.Sampler.Type = "const"+cfg.Sampler.Param = 1;生产环境建议"probabilistic" - 忘记
defer tracer.Close()会导致goroutine泄漏,尤其在短生命周期命令行工具里特别明显
HTTP服务注入/提取traceID时opentracing.HTTPHeaders不起作用
Go标准库http.Client和http.ServeMux都不自动处理trace上下文,必须手动在RoundTrip和Handler里注入/提取。直接传opentracing.HTTPHeaders只是个键名,不是自动行为。
- 客户端侧:用
othttp.Transport包装http.DefaultTransport,或自己实现RoundTripper调用tracer.Inject() - 服务端侧:用
othttp.Middleware包装handler,它会从uber-trace-id头读取并创建span - 别依赖
req.Header.Set("uber-trace-id", ...)手写——格式要符合Jaeger的TraceID:SpanID:ParentID:Flags十六进制字符串,错一位就丢链路
Go微服务间gRPC调用怎么透传trace上下文
gRPC默认不传递OpenTracing上下文,必须用grpc_opentracing插件,且要注意拦截器注册顺序和context传递时机。
- 服务端注册
grpc.StreamInterceptor(otgrpc.OpenTracingStreamServerInterceptor(tracer))和grpc.UnaryInterceptor(...) - 客户端调用时,必须把span context塞进
context.Context:用opentracing.ContextWithSpan(ctx, span)再传给client.Method(ctx, req) - 如果用了
grpc.WithBlock()或自定义DialOptions,确保拦截器在WithUnaryInterceptor之后注册,否则context丢失 - 注意
grpc-gov1.38+对context.WithValue更严格,避免在中间件里覆盖原context的span键
本地调试时Jaeger UI看不到span,但日志显示reporter: submitting X spans
大概率是Reporter配置没对齐:本地Jaeger Agent默认监听localhost:6831(compact thrift),而Go客户端默认走localhost:6832(binary thrift)或直连Collector HTTP端口,协议不匹配导致静默丢数据。
- 启动Agent时加
--collector.host-port=jaeger-collector:14268,客户端配cfg.Reporter.LocalAgentHostPort = "localhost:6831" - 或者跳过Agent,客户端直连Collector:
cfg.Reporter.CollectorEndpoint = "http://localhost:14268/api/traces",此时必须关掉LocalAgentHostPort - 检查
tracer.StartSpan()是否漏了opentracing.ChildOf(span.Context()),父span为空时新span变成root,但UI可能因时间戳异常被过滤
真正麻烦的是跨进程context传递时span的finish时机——一个span在goroutine里finish,但它的child span还在另一个goroutine跑,Jaeger会截断链路。这种问题不会报错,只会在UI里看到“断掉的线”,得靠span.Finish()前加span.SetTag("debug", true)人工标记排查。
golang免费学习笔记(深入):立即使用
在学习笔记中,你将探索golang的核心概念和高级技巧!











