1- import { SQSEvent } from "aws-lambda" ;
1+ import { SQSEvent , SQSRecord } from "aws-lambda" ;
22import { TracerWrapper } from "../../tracer-wrapper" ;
33import { logDebug } from "../../../utils" ;
44import { EventTraceExtractor } from "../extractor" ;
@@ -10,23 +10,18 @@ export class SQSEventTraceExtractor implements EventTraceExtractor {
1010 constructor ( private tracerWrapper : TracerWrapper , private config : TraceConfig ) { }
1111
1212 extract ( event : SQSEvent ) : SpanContextWrapper | null {
13- // Set DSM consume checkpoints if enabled
13+ // Set DSM consume checkpoints if enabled and capture first record's headers
14+ let firstRecordHeaders : Record < string , string > | null = null ;
1415 if ( this . config . dataStreamsEnabled ) {
15- for ( const record of event ?. Records || [ ] ) {
16+ for ( let i = 0 ; i < ( event ?. Records || [ ] ) . length ; i ++ ) {
17+ const record = event . Records [ i ] ;
1618 try {
17- // First get the headers from the message attributes, which makes it easy to extract trace context
18- let headers = record . messageAttributes ?. _datadog ?. stringValue ;
19- if ( ! headers ) {
20- // Then try to get headers from binary value. This happens when SNS->SQS, but SNS has raw message delivery enabled.
21- // In this case, SNS maps any messageAttributes to the SQS messageAttributes.
22- // We can at least get trace context from SQS, but we won't be able to create the SNS inferred span.
23- const encodedTraceContext = record . messageAttributes ?. _datadog ?. binaryValue ;
24- if ( encodedTraceContext ) {
25- headers = Buffer . from ( encodedTraceContext , "base64" ) . toString ( "ascii" ) ;
26- }
27- }
19+ const headers = this . getParsedRecordHeaders ( record ) ;
2820
29- headers = headers ? JSON . parse ( headers ) : null ;
21+ // Store first record's headers for trace context extraction
22+ if ( i === 0 ) {
23+ firstRecordHeaders = headers ;
24+ }
3025
3126 // Set a checkpoint for the record, even if we don't have headers
3227 this . tracerWrapper . setConsumeCheckpoint ( headers , "sqs" , record . eventSourceARN ) ;
@@ -38,23 +33,13 @@ export class SQSEventTraceExtractor implements EventTraceExtractor {
3833
3934 logDebug ( "SQS Extractor Being Used" ) ;
4035 try {
41- // First try to extract trace context from message attributes
42- let headers = event ?. Records ?. [ 0 ] ?. messageAttributes ?. _datadog ?. stringValue ;
43-
44- if ( ! headers ) {
45- // Then try to get from binary value. This happens when SNS->SQS, but SNS has raw message delivery enabled.
46- // In this case, SNS maps any messageAttributes to the SQS messageAttributes.
47- // We can at least get trace context from SQS, but we won't be able to create the SNS inferred span.
48- const encodedTraceContext = event ?. Records ?. [ 0 ] ?. messageAttributes ?. _datadog ?. binaryValue ;
49- if ( encodedTraceContext ) {
50- headers = Buffer . from ( encodedTraceContext , "base64" ) . toString ( "ascii" ) ;
51- }
36+ // Use already parsed headers from DSM if available, otherwise parse now
37+ if ( ! firstRecordHeaders ) {
38+ firstRecordHeaders = this . getParsedRecordHeaders ( event ?. Records ?. [ 0 ] ) ;
5239 }
5340
54- if ( headers ) {
55- const parsedHeaders = JSON . parse ( headers ) ;
56-
57- const traceContext = extractTraceContext ( parsedHeaders , this . tracerWrapper ) ;
41+ if ( firstRecordHeaders ) {
42+ const traceContext = extractTraceContext ( firstRecordHeaders , this . tracerWrapper ) ;
5843 if ( traceContext ) {
5944 return traceContext ;
6045 }
@@ -73,4 +58,27 @@ export class SQSEventTraceExtractor implements EventTraceExtractor {
7358
7459 return null ;
7560 }
61+
62+ private getParsedRecordHeaders ( record : SQSRecord | undefined ) : Record < string , string > | null {
63+ if ( ! record ) {
64+ return null ;
65+ }
66+ try {
67+ // First get the headers from the message attributes
68+ let headers = record . messageAttributes ?. _datadog ?. stringValue ;
69+ if ( ! headers ) {
70+ // Then try to get from binary value. This happens when SNS->SQS, but SNS has raw message delivery enabled.
71+ // In this case, SNS maps any messageAttributes to the SQS messageAttributes.
72+ // We can at least get trace context from SQS, but we won't be able to create the SNS inferred span.
73+ const encodedTraceContext = record . messageAttributes ?. _datadog ?. binaryValue ;
74+ if ( encodedTraceContext ) {
75+ headers = Buffer . from ( encodedTraceContext , "base64" ) . toString ( "ascii" ) ;
76+ }
77+ }
78+
79+ return headers ? JSON . parse ( headers ) : null ;
80+ } catch ( error ) {
81+ return null ;
82+ }
83+ }
7684}
0 commit comments