Cloud Run部署Python gRPC服务OpenTelemetry链路追踪传播失效问题
问题根因
你仅配置了全局传播器,但没有完成gRPC请求的链路上下文提取逻辑,传播器不会自动解析gRPC调用的metadata,因此手动创建的span始终是新链路的根span,和请求头里的trace id无关。
方案1:使用OpenTelemetry gRPC自动埋点(推荐)
该方案不需要修改业务代码,自动完成上下文提取、span创建等操作:
- 首先安装依赖包:
pip install opentelemetry-instrumentation-grpc - 在
configure_tracing()执行完成后、启动gRPC服务前,添加instrumentation初始化代码:
from opentelemetry.instrumentation.grpc import GrpcInstrumentorServer grpc_server_instrumentor = GrpcInstrumentorServer() grpc_server_instrumentor.instrument()
- 此时不需要在业务代码里手动创建
GetStripeInvoicespan,instrumentation会自动创建服务端span,且自动关联请求头里的trace id。如果需要自定义子span,直接在方法内创建即可,会自动继承父上下文。
方案2:手动提取链路上下文
如果不想使用自动埋点,你需要在创建span前手动从gRPC metadata中提取父上下文,修改gRPC方法代码如下:
import grpc from opentelemetry import trace, propagate import stripe from common import cloud_logging, datastore_utils, proto_helpers, tracing from services.payment_service import payment_service_pb2 from third_party import stripe_client def GetStripeInvoice( self, request: payment_service_pb2.GetStripeInvoiceRequest, context: grpc.ServicerContext ) -> payment_service_pb2.StripeInvoiceResponse: tracer: trace.Tracer = tracing.get_tracer() # 从gRPC metadata中提取链路上下文 metadata = dict(context.invocation_metadata()) # 传播器会自动从metadata中读取x-cloud-trace-context字段解析父上下文 parent_context = propagate.extract(metadata) # 创建span时传入提取到的父上下文 with tracer.start_as_current_span('GetStripeInvoice', context=parent_context): print(f"trace ID from header: {metadata.get('x-cloud-trace-context')}") # 可打印当前span的trace id验证是否匹配 current_span = trace.get_current_span() print(f"current span trace id: {format(current_span.get_span_context().trace_id, '032x')}") cloud_logging.info(f"Getting Stripe invoice.") order = datastore_utils.get_pb_with_pb_key(request.order) try: invoice: stripe.Invoice = stripe_client.get_invoice( invoice_id=order.stripe_invoice_id ) cloud_logging.info(f"Retrieved Stripe invoice. Amount due: {invoice['amount_due']}") except stripe.error.StripeError as e: cloud_logging.error( f"Failed to retrieve invoice: {e}" ) context.abort(code=grpc.StatusCode.INTERNAL, details=str(e)) return payment_service_pb2.StripeInvoiceResponse( invoice=proto_helpers.create_struct(invoice) )
补充配置检查
你当前的configure_tracing方法中,只有非本地环境才设置了全局传播器,如果需要在本地测试链路传播逻辑,需要把propagate.set_global_textmap的配置移到分支外,本地环境也启用CloudTrace格式传播器:
def configure_tracing() -> None: trace.set_tracer_provider(sdk_trace.TracerProvider()) # 全局都设置CloudTrace格式传播器,方便本地测试 propagate.set_global_textmap(cloud_trace_propagator.CloudTraceFormatPropagator()) if app_instance.IS_LOCAL: print("Configuring local tracing.") span_exporter: export.SpanExporter = export.ConsoleSpanExporter() else: print(f"Configuring cloud tracing in environment {app_instance.ENVIRONMENT}.") span_exporter = cloud_trace.CloudTraceSpanExporter() trace.get_tracer_provider().add_span_processor(export.SimpleSpanProcessor(span_exporter))
内容的提问来源于stack exchange,提问作者dkhaupt
相关产品推荐
相关产品推荐

