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

如何从x-cloud-trace-context头提取Trace Context并创建OpenTelemetry Span?

问题

在Google Cloud App Engine上部署的FastAPI微服务中,需通过OpenTelemetry Python SDK提取AppEngine自带的x-cloud-trace-context请求头中的追踪上下文并创建对应Span,但调用propagator.extract后得到空上下文。

当前代码:

from opentelemetry import trace
from opentelemetry import propagate
from opentelemetry.sdk.trace import TracerProvider
from opentelemetry.sdk.resources import Resource
from opentelemetry.trace import (
    SpanContext,
    get_current_span,
    set_span_in_context,
)

provider = TracerProvider(resource=Resource.create({"service.name": "api-backend"}))
trace.set_tracer_provider(provider)
tracer = trace.get_tracer(__name__)
PROPAGATOR = propagate.get_global_textmap()

def get_span_from_request_header(request_headers):
    headers = {"x-cloud-trace-context": request_headers.get("x-cloud-trace-context")}
    context = PROPAGATOR.extract(headers)
    print(context)
    span = get_current_span(context=context)
    set_span_in_context(span, context)
    print(f" Printing span: {span.get_span_context()}")
    return span

代码中打印语句均输出空内容,请求头格式如下:

X-Cloud-Trace-Context: TRACE_ID/SPAN_ID;o=TRACE_TRUE

  • Trace_ID: 十六进制字符串
  • SPAN_ID: 十六进制字符串

尝试手动用trace_id和span_id创建SpanContext时,报错提示需要整数类型的trace_id,求正确提取上下文并创建Span的方法。


解决方案

1. 问题根源

OpenTelemetry默认全局propagator不支持Google Cloud的x-cloud-trace-context格式,需使用专用GCP propagator,或手动解析请求头构建SpanContext。

2. 方法一:使用OpenTelemetry GCP Propagator

这是最简单的官方解决方案,专门适配GCP的追踪格式:
首先安装依赖:

pip install opentelemetry-propagator-gcp

替换全局propagator并调整代码:

from opentelemetry import trace
from opentelemetry import propagate
from opentelemetry.sdk.trace import TracerProvider
from opentelemetry.sdk.resources import Resource
from opentelemetry.propagators.cloud_trace_propagator import CloudTraceFormatPropagator

# 设置GCP专属propagator为全局文本映射器
propagate.set_global_textmap(CloudTraceFormatPropagator())

provider = TracerProvider(resource=Resource.create({"service.name": "api-backend"}))
trace.set_tracer_provider(provider)
tracer = trace.get_tracer(__name__)

def get_span_from_request_header(request_headers):
    # 将FastAPI的Headers对象转为字典传入
    context = propagate.get_global_textmap().extract(dict(request_headers))
    span = trace.get_current_span(context=context)
    print(f"Span context: {span.get_span_context()}")
    return span

3. 方法二:手动解析请求头构建SpanContext

若不想额外安装依赖,可手动解析x-cloud-trace-context格式并构建SpanContext:

from opentelemetry import trace
from opentelemetry.sdk.trace import TracerProvider
from opentelemetry.sdk.resources import Resource
from opentelemetry.trace import SpanContext, TraceFlags, set_span_in_context, Context

provider = TracerProvider(resource=Resource.create({"service.name": "api-backend"}))
trace.set_tracer_provider(provider)
tracer = trace.get_tracer(__name__)

def parse_cloud_trace_header(header_value):
    if not header_value:
        return None
    # 拆分格式:TRACE_ID/SPAN_ID;o=TRACE_TRUE
    trace_part, opts_part = header_value.split(';', 1)
    trace_id_hex, span_id_hex = trace_part.split('/', 1)
    # 将十六进制字符串转为整数(符合SpanContext要求)
    trace_id = int(trace_id_hex, 16)
    span_id = int(span_id_hex, 16)
    # 解析采样标记:o=1表示采样,o=0不采样
    is_sampled = opts_part.split('=', 1)[1] == '1'
    trace_flags = TraceFlags(TraceFlags.SAMPLED if is_sampled else 0)
    
    return SpanContext(
        trace_id=trace_id,
        span_id=span_id,
        trace_flags=trace_flags,
        is_remote=True  # 标记为外部传入的上下文
    )

def get_span_from_request_header(request_headers):
    header_value = request_headers.get("x-cloud-trace-context")
    span_context = parse_cloud_trace_header(header_value)
    
    if not span_context:
        # 无上下文时创建根Span
        with tracer.start_as_current_span("root-api-request") as span:
            return span
    
    # 基于已有上下文创建子Span
    trace_context = Context(span_context=span_context)
    with tracer.start_as_current_span("api-request", context=trace_context) as span:
        print(f"Span context: {span.get_span_context()}")
        return span

4. 关键注意事项

  • FastAPI的request.headers是starlette.datastructures.Headers对象,必须转为字典后才能被propagator正确处理
  • 手动构建SpanContext时,需保证trace_id是32位十六进制转成的整数(16字节)、span_id是16位十六进制转成的整数(8字节),同时设置is_remote=True标记为外部上下文

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.25 05:15:32