FastAPI集成OpenTelemetry如何获取Jaeger可识别Trace ID写入响应头
问题根因
你现有代码拿不到Jaeger可检索的Trace ID,是两个错误导致的:
- 格式不匹配:
span.get_span_context().trace_id返回的是128位整数类型的ID,直接转字符串得到的是十进制数字串,而Jaeger UI检索使用的是32位小写十六进制格式的Trace ID,也就是你看到的类似8eddc793de380fa76c54557af09538e3的格式。 - 取错了上下文对象:你手动创建了一个名为
dummy-span的临时Span,这个Span在实际请求处理(call_next)执行前就已经退出上下文结束了,拿到的是这个孤立临时Span的Trace ID,和当前请求实际生成、上报到Jaeger的链路Trace ID完全无关,自然搜不到结果。
正确实现方法
不要手动创建无意义的临时Span,直接从OpenTelemetry的当前活跃上下文中获取请求绑定的根Span,再将Trace ID转换为Jaeger兼容的十六进制格式即可。
首先确保你已经正确完成OpenTelemetry FastAPI的埋点初始化,然后使用如下中间件实现:
from starlette.middleware.base import BaseHTTPMiddleware from fastapi import Request from opentelemetry import trace class EnrichOpenTelemetryId(BaseHTTPMiddleware): async def dispatch(self, request: Request, call_next): # 先执行后续请求处理逻辑 response = await call_next(request) # 获取当前请求链路绑定的活跃Span current_span = trace.get_current_span() # 将整数格式的Trace ID转换为32位小写十六进制格式,自动补前导零 trace_id = format(current_span.get_span_context().trace_id, "032x") # 写入响应头 response.headers["X-Trace-Id"] = trace_id return response
配置注意事项
- 中间件注册顺序必须正确:先注册OpenTelemetry提供的FastAPI instrumentation中间件,再注册上述自定义Trace ID注入中间件。如果顺序颠倒,请求进入自定义中间件时OTel还未创建链路根Span,会拿到全0的无效Trace ID。
- 上述转换得到的32位十六进制Trace ID完全兼容W3C Trace Context标准,除Jaeger外可直接在Zipkin、Grafana Tempo等所有主流链路追踪后端检索使用。
- 不要在中间件里手动创建额外Span取ID,既会产生多余的无意义链路节点,也无法保证拿到请求实际使用的Trace ID。
内容的提问来源于stack exchange,提问作者omer bar lev
相关产品推荐
相关产品推荐

