能否将AWS Lambda+SQS的OpenTelemetry Span Link配置为traceparent?
问题
当前AWS Lambda与SQS集成OpenTelemetry时,默认是将_X_AMZN_TRACE_ID作为Span Link,但我需要从traceparent中获取生产者的TraceID并填充到Span Link字段,以此实现生产者与消费者链路的关联。请问是否可通过配置实现,还是需要编写自定义代码?
已执行操作
- 手动编译并创建包含PR#1657变更的Layer;
- 通过本地Python进程向SQS发送消息,生产者代码如下:
import boto3 # Create SQS client sqs = boto3.client('sqs') queue_url = 'https://sqs.us-west-2.amazonaws.com/account_number/shuwpan-sqs-between-f1-f2' # Send message to SQS queue response = sqs.send_message( QueueUrl=queue_url, DelaySeconds=10, MessageAttributes={ 'Title': { 'DataType': 'String', 'StringValue': 'The Whistler' }, 'Author': { 'DataType': 'String', 'StringValue': 'John Grisham' }, 'WeeksOn': { 'DataType': 'Number', 'StringValue': '6' } }, MessageBody=( 'Information about current NY Times fiction bestseller for ' 'week of 12/11/2016.' ) )
- 使用Lambda函数消费消息并打印日志,消费者代码如下:
import json import os def lambda_handler(event, context): for record in event['Records']: payload = record["body"] print('------------ Trace parent------------', record['messageAttributes']['traceparent']) xray_env = os.getenv('_X_AMZN_TRACE_ID') print('------------ X_RAY ------------', xray_env) return { 'statusCode': 200, 'body': json.dumps(str(payload)) }
当前现象与预期
- 当前Lambda的Span Link中为X-Ray的TraceID(
644af9cb30e86117070956834d350c2a),而生产者的TraceID为755953bd01c1f767dc857d1f45c511a2; - 预期:Span Link字段中能获取生产者的TraceID,以便后端关联两条链路。
解决方案
目前官方未提供直接配置项切换到traceparent作为Span Link来源,因此无法仅通过配置实现需求,需要通过自定义代码完成链路关联。
1. 完善生产者链路注入
你的当前生产者代码未自动注入traceparent到消息属性,需要在发送SQS消息时,通过OpenTelemetry API获取当前Span的traceparent并添加到消息属性中:
import boto3 from opentelemetry import trace tracer = trace.get_tracer(__name__) # Create SQS client sqs = boto3.client('sqs') queue_url = 'https://sqs.us-west-2.amazonaws.com/account_number/shuwpan-sqs-between-f1-f2' with tracer.start_as_current_span("send-sqs-message"): # 获取当前Span的traceparent current_span = trace.get_current_span() traceparent = trace.format_traceparent(current_span.get_span_context()) # Send message to SQS queue response = sqs.send_message( QueueUrl=queue_url, DelaySeconds=10, MessageAttributes={ 'Title': { 'DataType': 'String', 'StringValue': 'The Whistler' }, 'Author': { 'DataType': 'String', 'StringValue': 'John Grisham' }, 'WeeksOn': { 'DataType': 'Number', 'StringValue': '6' }, 'traceparent': { 'DataType': 'String', 'StringValue': traceparent } }, MessageBody=( 'Information about current NY Times fiction bestseller for ' 'week of 12/11/2016.' ) )
2. 在消费者中添加自定义Span Link
修改Lambda消费者代码,解析traceparent字段并通过OpenTelemetry API将生产者链路添加为当前Span的Link:
import json import os from opentelemetry import trace from opentelemetry.trace import Link, TraceState tracer = trace.get_tracer(__name__) def lambda_handler(event, context): for record in event['Records']: payload = record["body"] # 从消息属性中获取traceparent traceparent = record['messageAttributes']['traceparent']['StringValue'] # 解析W3C Trace Context格式的traceparent version, trace_id, span_id, flags = traceparent.split('-') # 创建Span Link link = Link( trace_id=int(trace_id, 16), span_id=int(span_id, 16), trace_state=TraceState() ) # 启动当前处理Span并关联生产者链路 with tracer.start_as_current_span("process-sqs-message", links=[link]): print('------------ Processed Message ------------', payload) xray_env = os.getenv('_X_AMZN_TRACE_ID') print('------------ X_RAY ------------', xray_env) return { 'statusCode': 200, 'body': json.dumps(str(payload)) }
3. 进阶优化(可选)
如果不想在业务代码中硬编码链路逻辑,可以自定义OpenTelemetry Lambda Instrumentation,在Lambda入口处自动解析SQS消息中的traceparent并添加Span Link。这需要继承现有Lambda Instrumentation类重写处理方法,适合需要批量适配多个Lambda函数的场景。
内容的提问来源于stack exchange,提问作者shuwpan
相关产品推荐
相关产品推荐

