Skip to content

Commit 9a14428

Browse files
authored
Extract trace context from SNS->SQS event when SNS has raw message delivery (#621)
1 parent 7d8e605 commit 9a14428

File tree

2 files changed

+69
-1
lines changed

2 files changed

+69
-1
lines changed

src/trace/context/extractors/sqs.spec.ts

+57
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,63 @@ describe("SQSEventTraceExtractor", () => {
8585
expect(traceContext?.source).toBe("event");
8686
});
8787

88+
it("extracts trace context from _datadog binaryValue when raw message delivery is used", () => {
89+
mockSpanContext = {
90+
toTraceId: () => "1234567890",
91+
toSpanId: () => "0987654321",
92+
_sampling: {
93+
priority: "1",
94+
},
95+
};
96+
const tracerWrapper = new TracerWrapper();
97+
98+
const ddHeaders = {
99+
"x-datadog-trace-id": "1234567890",
100+
"x-datadog-parent-id": "0987654321",
101+
"x-datadog-sampled": "1",
102+
"x-datadog-sampling-priority": "1",
103+
};
104+
const ddHeadersString = JSON.stringify(ddHeaders);
105+
const ddHeadersBase64 = Buffer.from(ddHeadersString, "ascii").toString("base64");
106+
107+
const payload: SQSEvent = {
108+
Records: [
109+
{
110+
messageId: "abc-123",
111+
receiptHandle: "MessageReceiptHandle",
112+
body: "Hello from SQS!",
113+
attributes: {
114+
ApproximateReceiveCount: "1",
115+
SentTimestamp: "1523232000000",
116+
SenderId: "123456789012",
117+
ApproximateFirstReceiveTimestamp: "1523232000001",
118+
},
119+
messageAttributes: {
120+
_datadog: {
121+
binaryValue: ddHeadersBase64,
122+
dataType: "Binary",
123+
},
124+
},
125+
md5OfBody: "x",
126+
eventSource: "aws:sqs",
127+
eventSourceARN: "arn:aws:sqs:us-east-1:123456789012:MyQueue",
128+
awsRegion: "us-east-1",
129+
},
130+
],
131+
};
132+
133+
const extractor = new SQSEventTraceExtractor(tracerWrapper);
134+
const traceContext = extractor.extract(payload);
135+
expect(traceContext).not.toBeNull();
136+
137+
expect(spyTracerWrapper).toHaveBeenCalledWith(ddHeaders);
138+
139+
expect(traceContext?.toTraceId()).toBe("1234567890");
140+
expect(traceContext?.toSpanId()).toBe("0987654321");
141+
expect(traceContext?.sampleMode()).toBe("1");
142+
expect(traceContext?.source).toBe("event");
143+
});
144+
88145
it.each([
89146
["Records", {}],
90147
["Records first entry", { Records: [] }],

src/trace/context/extractors/sqs.ts

+12-1
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,18 @@ export class SQSEventTraceExtractor implements EventTraceExtractor {
1111
extract(event: SQSEvent): SpanContextWrapper | null {
1212
try {
1313
// First try to extract trace context from message attributes
14-
const headers = event?.Records?.[0]?.messageAttributes?._datadog?.stringValue;
14+
let headers = event?.Records?.[0]?.messageAttributes?._datadog?.stringValue;
15+
16+
if (!headers) {
17+
// Then try to get from binary value. This happens when SNS->SQS, but SNS has raw message delivery enabled.
18+
// In this case, SNS maps any messageAttributes to the SQS messageAttributes.
19+
// We can at least get trace context from SQS, but we won't be able to create the SNS inferred span.
20+
const encodedTraceContext = event?.Records?.[0]?.messageAttributes?._datadog?.binaryValue;
21+
if (encodedTraceContext) {
22+
headers = Buffer.from(encodedTraceContext, "base64").toString("ascii");
23+
}
24+
}
25+
1526
if (headers !== undefined) {
1627
const traceContext = this.tracerWrapper.extract(JSON.parse(headers));
1728
if (traceContext) {

0 commit comments

Comments
 (0)