@@ -290,9 +290,7 @@ def extract_context_from_sqs_or_sns_event_or_context(
290290
291291 # EventBridge => SQS
292292 try :
293- context , is_eventbridge_sqs = _extract_context_from_eventbridge_sqs_event (
294- event
295- )
293+ context , is_eventbridge_sqs = _extract_context_from_eventbridge_sqs_event (event )
296294 if is_eventbridge_sqs :
297295 if _is_context_complete (context ):
298296 return context
@@ -400,37 +398,25 @@ def _extract_context_from_eventbridge_sqs_event(event):
400398 return None , False
401399
402400 first_record = records [0 ]
403- body_str = first_record .get ("body" )
404- body = json .loads (body_str )
405- if not isinstance (body , dict ):
406- return None , False
407-
408- detail = body .get ("detail" )
409- if not (
410- isinstance (detail , dict )
411- and body .get ("detail-type" )
412- and body .get ("source" )
413- ):
401+ dd_context , is_eventbridge_sqs = _extract_eventbridge_sqs_record_context (
402+ first_record
403+ )
404+ if not is_eventbridge_sqs :
414405 return None , False
415406
416- dd_context = detail .get ("_datadog" )
417-
418407 # The event has been confirmed as EventBridge -> SQS. Set a consume
419408 # checkpoint for every record in the batch. The message is consumed from
420409 # the SQS queue, so it follows SQS conventions (type:sqs, topic:queue ARN).
421410 if config .data_streams_enabled :
422- _dsm_set_checkpoint (dd_context , "sqs" , first_record .get ("eventSourceARN" , "" ))
423411 for record in records :
424- if record is first_record :
425- continue
426412 try :
427- record_body = json .loads (record .get ("body" ))
428- record_detail = record_body .get ("detail" )
429- record_context = (
430- record_detail .get ("_datadog" )
431- if isinstance (record_detail , dict )
432- else None
413+ record_context , is_eventbridge_record = (
414+ _extract_eventbridge_sqs_record_context (record )
433415 )
416+ if not is_eventbridge_record :
417+ record_context = _extract_sqs_record_message_attribute_context (
418+ record
419+ )
434420 _dsm_set_checkpoint (
435421 record_context , "sqs" , record .get ("eventSourceARN" , "" )
436422 )
@@ -450,6 +436,46 @@ def _extract_context_from_eventbridge_sqs_event(event):
450436 return propagator .extract (dd_context ), True
451437
452438
439+ def _extract_eventbridge_sqs_record_context (record ):
440+ body_str = record .get ("body" )
441+ body = json .loads (body_str )
442+ if not isinstance (body , dict ):
443+ return None , False
444+
445+ detail = body .get ("detail" )
446+ if not (
447+ isinstance (detail , dict ) and body .get ("detail-type" ) and body .get ("source" )
448+ ):
449+ return None , False
450+
451+ return detail .get ("_datadog" ), True
452+
453+
454+ def _extract_sqs_record_message_attribute_context (record ):
455+ msg_attributes = record .get ("messageAttributes" ) or {}
456+ dd_payload = msg_attributes .get ("_datadog" )
457+ if not dd_payload :
458+ return None
459+
460+ dd_json_data = None
461+ dd_json_data_type = dd_payload .get ("Type" ) or dd_payload .get ("dataType" )
462+ if dd_json_data_type == "Binary" :
463+ import base64
464+
465+ dd_json_data = dd_payload .get ("binaryValue" ) or dd_payload .get ("Value" )
466+ if dd_json_data :
467+ dd_json_data = base64 .b64decode (dd_json_data )
468+ elif dd_json_data_type == "String" :
469+ dd_json_data = dd_payload .get ("stringValue" ) or dd_payload .get ("Value" )
470+ else :
471+ logger .debug (
472+ "Datadog Lambda Python only supports extracting trace"
473+ "context from String or Binary SQS/SNS message attributes"
474+ )
475+
476+ return json .loads (dd_json_data ) if dd_json_data else None
477+
478+
453479def extract_context_from_eventbridge_event (event , lambda_context ):
454480 """
455481 Extract datadog trace context from an EventBridge message's Details.
0 commit comments