You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

FastAPI服务OpenTelemetry自动埋点失效,无x-b3响应头求助

FastAPI配置OpenTelemetry自动埋点后响应头缺失x-b3-spanid和x-b3-traceid字段

我正在尝试为FastAPI服务配置OpenTelemetry自动埋点,但始终无法成功,核心问题是服务响应头中缺少x-b3-spanid和x-b3-traceid字段。即使请求时携带已有的Brave链路追踪信息,响应里还是看不到这两个目标头。

我的当前配置

main.py代码

import pkg_resources

from fastapi import FastAPI
from fastapi import APIRouter
from typing import Dict,Any
from opentelemetry import trace
from contextlib import asynccontextmanager
from opentelemetry.instrumentation.fastapi import FastAPIInstrumentor
from uvicorn.middleware.proxy_headers import ProxyHeadersMiddleware

import logging
LOG = logging.getLogger(__name__)
'''
root_logger = logging.getLogger()
root_logger.setLevel(logging.DEBUG)
for handler in root_logger.handlers:
  handler.setLevel(logging.DEBUG)
  
logconfig_dict.update({"root": {"level":"DEBUG", "handlers": ["error"]}})
'''

'''
from opentelemetry import trace, propagators, baggage
from opentelemetry.sdk.trace import TracerProvider
from opentelemetry.sdk.trace.export import (
    BatchSpanProcessor,
    ConsoleSpanExporter,
)

provider = TracerProvider()
processor = BatchSpanProcessor(ConsoleSpanExporter())
provider.add_span_processor(processor)
trace.set_tracer_provider(provider)
'''

tags_metadata = [
    {
        "name": "root",
        "description": "root route",
    }
]

app = FastAPI(
    title="fastapi-otel-test",
    description="This is a REST api that test otel with fastapi.",
    version="0.1.2",
    openapi_tags=tags_metadata,
)
# Freeze OpenAPI verstion. OpenAPI 3.1.0 is not fully backward compatible
app.openapi_version = "3.0.3"
app.add_middleware(ProxyHeadersMiddleware)

'''
def server_request_hook(span, scope: Dict[str, Any]):
     if span and span.is_recording():
         span.set_attribute("service.name", "fastapi-otel")

FastAPIInstrumentor.instrument_app(app,
                                   tracer_provider=provider,
                                   server_request_hook=server_request_hook)
'''
FastAPIInstrumentor.instrument_app(app)

@asynccontextmanager
async def lifespan(app: FastAPI):
    # initialize
    LOG.error("lifespan() start")
    yield
    LOG.info("lifespan() end")

router = APIRouter()

import httpx
@router.get("/", tags=["root"])
async def root():
    async with httpx.AsyncClient() as client:
      response = await client.get("http://localhost:8000/foo")
    LOG.info(response.headers)
    return "Hello world"

@router.get("/foo", tags=["root"])
async def foo():
    return "Hello foo"

app.include_router(router)

启动命令

./.venv/bin/fastapi dev main.py

测试请求及结果

$ curl -s http://localhost:8000/ -i -H "x-b3-span-id: deadbeef" -H "x-b3-trace-id: baadf00ddeadbeef"
HTTP/1.1 200 OK
date: Thu, 10 Oct 2024 22:20:13 GMT
server: uvicorn
content-length: 13
content-type: application/json

"Hello world"

requirements.txt

fastapi[standard]==0.115.0
httpx
opentelemetry-sdk
opentelemetry-instrumentation-fastapi

Python版本:3.12

遗漏的配置及解决方案

问题出在以下几个关键配置缺失:

  1. 未配置B3 Propagator
    OpenTelemetry默认使用W3C Trace Context格式的propagator,而B3格式(x-b3-*头)需要显式启用。需要安装opentelemetry-propagator-b3包,并配置全局propagator。

  2. 未初始化TracerProvider
    当前代码中TracerProvider的配置被注释,没有正确初始化追踪核心组件,导致链路追踪无法正常生成和传播。

  3. 未配置Span导出及处理器
    没有添加Span处理器和导出器,追踪数据无法被处理和输出,同时也会影响头信息的生成。

  4. Instrumentation时机问题
    FastAPIInstrumentor.instrument_app应该在TracerProvider和Propagator配置完成后执行,确保instrumentation使用正确的全局配置。

修改后的完整配置

首先更新requirements.txt,添加B3 propagator依赖:

fastapi[standard]==0.115.0
httpx
opentelemetry-sdk
opentelemetry-instrumentation-fastapi
opentelemetry-propagator-b3

然后修改main.py:

import pkg_resources

from fastapi import FastAPI
from fastapi import APIRouter
from typing import Dict,Any
from opentelemetry import trace
from opentelemetry.propagate import set_global_textmap
from opentelemetry.sdk.trace import TracerProvider
from opentelemetry.sdk.trace.export import (
    BatchSpanProcessor,
    ConsoleSpanExporter,
)
from opentelemetry.instrumentation.fastapi import FastAPIInstrumentor
from opentelemetry.propagators.b3 import B3MultiFormat
from uvicorn.middleware.proxy_headers import ProxyHeadersMiddleware

import logging
LOG = logging.getLogger(__name__)

# 初始化TracerProvider并配置Span处理器
provider = TracerProvider()
processor = BatchSpanProcessor(ConsoleSpanExporter())
provider.add_span_processor(processor)
trace.set_tracer_provider(provider)

# 配置B3格式的Propagator
set_global_textmap(B3MultiFormat())

tags_metadata = [
    {
        "name": "root",
        "description": "root route",
    }
]

app = FastAPI(
    title="fastapi-otel-test",
    description="This is a REST api that test otel with fastapi.",
    version="0.1.2",
    openapi_tags=tags_metadata,
)
# Freeze OpenAPI verstion. OpenAPI 3.1.0 is not fully backward compatible
app.openapi_version = "3.0.3"
app.add_middleware(ProxyHeadersMiddleware)

# 自定义请求钩子(可选,用于添加服务名等属性)
def server_request_hook(span, scope: Dict[str, Any]):
     if span and span.is_recording():
         span.set_attribute("service.name", "fastapi-otel")

# 配置FastAPI Instrumentation
FastAPIInstrumentor.instrument_app(
    app,
    tracer_provider=provider,
    server_request_hook=server_request_hook
)

@asynccontextmanager
async def lifespan(app: FastAPI):
    # initialize
    LOG.error("lifespan() start")
    yield
    LOG.info("lifespan() end")

router = APIRouter()

import httpx
@router.get("/", tags=["root"])
async def root():
    async with httpx.AsyncClient() as client:
      response = await client.get("http://localhost:8000/foo")
    LOG.info(response.headers)
    return "Hello world"

@router.get("/foo", tags=["root"])
async def foo():
    return "Hello foo"

app.include_router(router)

验证修改

  1. 重新安装依赖:pip install -r requirements.txt
  2. 启动服务:./.venv/bin/fastapi dev main.py
  3. 再次发送测试请求:
curl -s http://localhost:8000/ -i -H "x-b3-span-id: deadbeef" -H "x-b3-trace-id: baadf00ddeadbeef"

此时响应头中应该会包含x-b3-spanid和x-b3-traceid字段,同时控制台会输出Span的详细追踪信息。

内容的提问来源于stack exchange,提问作者feroze

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.17 14:40:08