必须先启动Zipkin Server,否则zipkin-go静默丢弃所有span;需用完整上报地址如https://www.php.cn/link/cf23ef9e7106ffddf2b5801e41bbfb18,HTTP自动埋点须正确注册zipkin.HTTPServerMiddleware且透传X-B3-*头,跨goroutine必须显式传递context,服务名非空、span需显式Finish。

zipkin-go 是当前 Go 生态中最直接、最轻量的 Zipkin 客户端,不依赖 OpenTracing/OpenTelemetry 抽象层,适合快速落地。但“快速”不等于“随便配”,踩错一步,所有 trace 都静默消失,且无任何错误提示。
必须先启动 Zipkin Server,否则所有 span 都丢弃
zipkin-go 只负责采集和上报,不托管服务端。没服务端,它连 404 都不报,只是默默 drop 所有 span。
- 启动命令(推荐):
docker run -d -p 9411:9411 openzipkin/zipkin - 验证是否就绪:
curl -s <a href="https://www.php.cn/link/724313cde1a7f2c508b6fb312715a83c">https://www.php.cn/link/724313cde1a7f2c508b6fb312715a83c</a>应返回{"status":"UP"} - 容器内调用时,
localhost指向本容器,得换成真实服务名(如zipkin.default.svc.cluster.local) - 上报地址必须写全:
<a href="https://www.php.cn/link/cf23ef9e7106ffddf2b5801e41bbfb18">https://www.php.cn/link/cf23ef9e7106ffddf2b5801e41bbfb18</a>,漏掉/api/v2/spans会 404,且 client 默认不打日志
HTTP 服务自动埋点:别手写 StartSpan,但中间件要插对位置
zipkin.HTTPServerMiddleware 能自动从 X-B3-* 头提取上下文、创建 server span 并 finish,但只适配标准库 net/http。
- Gin 用户必须换用
gin-contrib/zipkin,不是zipkin-go自带的中间件 - 中间件注册顺序关键:必须在
router.ServeHTTP或engine.Use()里最早注册,晚于路由定义就捕获不到完整 path - 前端或上游必须透传
X-B3-TraceId、X-B3-SpanId、X-B3-ParentSpanId,否则每个请求都是孤立 trace - handler panic 时 span 不会自动标 error,需 recover 后手动
span.Tag("error", "true")+span.Finish()
跨 goroutine 必须显式传 context,否则链路断开
zipkin-go 的 Span 不绑定 goroutine,也不继承父 goroutine 的 context。
立即学习“go语言免费学习笔记(深入)”;
- 正确做法:主线程中调
span.Context()得到带 trace 信息的context.Context,再作为参数传给子函数 - 错误写法:
go doWork()—— 这里的doWork拿不到任何 trace 上下文 -
go doWork(ctx)才对;子函数内部再调tracer.StartSpanFromContext(ctx, "sub-op") - Gin 的
c.Request.Context()是干净的,不含 span,必须自己把 span.Context() 塞进去
Reporter 初始化失败:URL 格式错、没 Finish、服务名为空
三个高频静默失败点:
zipkin.NewReporter传了空字符串或缺http://,导致 reporter 构建失败,后续所有 span 上报直接 returntracer.StartSpan()后忘记defer span.Finish(),UI 显示 “incomplete”,耗时为 0服务名为空:
zipkin.WithName("")→ Zipkin UI 全部归到unknown,无法过滤调试期建议加
zipkin.HTTPBatchSize(1),避免 batch 导致延迟掩盖问题别用
zipkin.NewUDPTransport:Go 的WriteTo在高并发下易丢包,Zipkin Server 默认也不监听 UDP
真正卡住人的,从来不是代码写几行,而是服务端没起来、context 没传下去、URL 少写了协议头——这些地方一错,整个链路就断成碎片,还找不到报错。


















