用OpenTelemetry搭建轻量级链路追踪需先注册TracerProvider并使用ConsoleSpanExporter验证;HTTP跨服务需手动inject/extract traceparent头;异步与多线程下context易丢失,须确保span上下文正确传递。

Python 里用 opentelemetry 搭一个轻量级分布式链路追踪系统,不依赖 Jaeger 或 Zipkin 后端也能跑通核心链路——关键在于用 ConsoleSpanExporter 或内存式 SimpleSpanProcessor 快速验证逻辑,而不是一上来就对接远程 collector。
用 opentelemetry-sdk 初始化 tracer,别碰 opentracing
opentracing 已归档,新项目必须用 OpenTelemetry(OTel)。初始化时容易漏掉 TracerProvider 的全局注册,导致 trace.get_tracer(__name__) 返回空 tracer。
- 必须调用
trace.set_tracer_provider(TracerProvider()),否则所有start_span()都静默失败 - 如果用 Flask/FastAPI,要在应用启动前完成 provider 注册,不能放在路由函数里
- 避免手动传
span_context:优先用with tracer.start_as_current_span("xxx"):自动处理上下文绑定
跨进程传递 trace context,靠 traceparent HTTP header
服务间调用时,不透传 traceparent,链路就断成单点。Python 的 requests 不自动注入,httpx 也一样。
- 发送请求前,用
propagator.inject(carrier=headers)把当前 span context 写进headers字典 - 接收方用
propagator.extract(carrier=headers)从request.headers恢复 context - 默认 propagator 是
TraceContextTextMapPropagator(),它只认traceparent(不是X-B3-TraceId) - FastAPI 中可在依赖项里统一 extract,Flask 建议用
@app.before_request处理
本地调试用 ConsoleSpanExporter,别急着连 Zipkin
开发阶段硬连 Zipkin 容易因网络、格式、endpoint 路径(/api/v2/spans?/v1/spans?)卡住,先确认 span 数据能生成再说。
立即学习“Python免费学习笔记(深入)”;
- 配置
SimpleSpanProcessor(ConsoleSpanExporter()),控制台直接打印 JSON 格式 span,含trace_id、span_id、parent_id和时间戳 - 注意
SimpleSpanProcessor是同步阻塞的,压测时换BatchSpanProcessor,但开发期它最直观 - 如果看到
trace_id全是00000000000000000000000000000000,说明 context 丢失,回头检查 inject/extract 是否漏了
真正难的不是发 span,而是确保每个异步任务、线程、Celery job、甚至日志语句都运行在正确的 contextvars.Context 里——OpenTelemetry 的 context 隔离比想象中脆弱,尤其混用 asyncio 和多线程时,get_current_span() 很容易返回 None。


















