Files
sundynix-agentix/sundynix-shared/bus/trace.go
T
Blizzard a2d184b7ec feat(observability): OpenTelemetry 全链路追踪(Jaeger + NATS 跨总线传播)
新增 sundynix-shared/otelx:otelx.Init(ctx,服务名) 注册 W3C 传播器 + OTLP/HTTP
批量导出(默认 localhost:4318,docker 里的 Jaeger);OTEL_SDK_DISABLED=true 关导出。
Jaeger 不在线 / 导出器构建失败都不阻断启动(可观测性是增益而非依赖)。

- NATS 跨进程传播(无现成中间件):bus/trace.go 的 natsHeaderCarrier + inject/extract,
  PublishTask/CallTool 注入 traceparent,ConsumeTasks/ServeTool 抽出续上 → 链路跨总线连成一棵树。
- 埋点:gateway 挂 otelgin(HTTP server span,链路根);dispatcher task.execute →
  node.<kind>(每节点,nctx 下传使工具/LLM 挂到节点下)→ llm.stream/llm.generate;
  bus 自动出 tool.call(client)↔tool.serve(server) 成对跨服务 span。
- docker-compose 加 jaeger all-in-one(UI :16686,OTLP :4318)。
- 依赖修复:otlptracehttp 触发 genproto 单体(旧)vs 拆分模块 ambiguous import(milvus 拉旧版),
  pin genproto 至后拆分版(go.work 工作区全局生效)。
- production_readiness.md 1.1 更新为「已实现」。

验证:真实 input→retriever→agent 任务在 Jaeger 出 14 span / 3 服务的完整树,
跨 NATS(publish→consume)、跨服务(tool.call→tool.serve)均连通,
瓶颈 kb_search 692ms、llm 1597ms 一眼可见;四模块 build+vet+test 全绿。

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-24 11:35:08 +08:00

42 lines
1.3 KiB
Go

package bus
import (
"context"
"github.com/nats-io/nats.go"
"go.opentelemetry.io/otel"
"go.opentelemetry.io/otel/trace"
)
// natsHeaderCarrier 让 OTel 传播器能读写 NATS 消息头(W3C traceparent 等),
// 从而把链路上下文跨 NATS 总线带到下游服务——这是分布式追踪能连成一棵树的关键。
type natsHeaderCarrier nats.Header
func (c natsHeaderCarrier) Get(key string) string { return nats.Header(c).Get(key) }
func (c natsHeaderCarrier) Set(key, value string) { nats.Header(c).Set(key, value) }
func (c natsHeaderCarrier) Keys() []string {
out := make([]string, 0, len(c))
for k := range c {
out = append(out, k)
}
return out
}
// injectTrace 把 ctx 里的链路上下文写进 NATS 消息头(发布前调用)。
func injectTrace(ctx context.Context, h nats.Header) {
otel.GetTextMapPropagator().Inject(ctx, natsHeaderCarrier(h))
}
// extractTrace 从 NATS 消息头还原上游链路上下文,挂到 ctx 上(消费时调用)。
func extractTrace(ctx context.Context, h nats.Header) context.Context {
if h == nil {
return ctx
}
return otel.GetTextMapPropagator().Extract(ctx, natsHeaderCarrier(h))
}
// tracer 是 bus 自身的 span 发射器(与业务同 scope,方便 Jaeger 归组)。
func tracer() trace.Tracer {
return otel.Tracer("github.com/sundynix/sundynix-agentix")
}