Skip to content

Commit 0e6e9dc

Browse files
authored
Cover string/b64 msg attribute trace extraction (#211)
* Cover string/b64 msg attribute trace extraction * fix lint * double quote to single and try to fix install crossbuild deps ci error * try apt get update before * revert to old install crossbuild deps step * apt-get * bring back whitespace in build.yml * remove space but keep empty line * b64decode right after pulling binaryValue/Value, add comment, and exception if message attributes are not string or binary * remove unessessary tests, fix failing test by adding dataType to msgAttribute, and try to get BinaryValue vs binaryValue depending on how casing off comes in * remove TitleCase checks and new snapshots * edit snapshots * bump ddtrace and update poetry.lock * remove newline from logs * update snapshots * force gh actions * revert change * edit snapshots * snapshots * gh action * revert force github action * make exception a logger.warn * force gh action * revert change * warning->debug to stop integration test failure * format and lint
1 parent fc1c286 commit 0e6e9dc

16 files changed

+387
-215
lines changed

datadog_lambda/tracing.py

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -223,7 +223,25 @@ def extract_context_from_sqs_or_sns_event_or_context(event, lambda_context):
223223
first_record.get("Sns", {}).get("MessageAttributes", {}),
224224
)
225225
dd_payload = msg_attributes.get("_datadog", {})
226-
dd_json_data = dd_payload.get("stringValue", dd_payload.get("Value", r"{}"))
226+
# SQS uses dataType and binaryValue/stringValue
227+
# SNS uses Type and Value
228+
dd_json_data_type = dd_payload.get("Type", dd_payload.get("dataType", ""))
229+
if dd_json_data_type == "Binary":
230+
dd_json_data = dd_payload.get(
231+
"binaryValue",
232+
dd_payload.get("Value", r"{}"),
233+
)
234+
dd_json_data = base64.b64decode(dd_json_data)
235+
elif dd_json_data_type == "String":
236+
dd_json_data = dd_payload.get(
237+
"stringValue",
238+
dd_payload.get("Value", r"{}"),
239+
)
240+
else:
241+
logger.debug(
242+
"Datadog Lambda Python only supports extracting trace"
243+
"context from String or Binary SQS/SNS message attributes"
244+
)
227245
dd_data = json.loads(dd_json_data)
228246
trace_id = dd_data.get(TraceHeader.TRACE_ID)
229247
parent_id = dd_data.get(TraceHeader.PARENT_ID)

poetry.lock

Lines changed: 263 additions & 196 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ classifiers = [
2626
python = ">=3.6.0,<4"
2727
datadog = "^0.41.0"
2828
wrapt = "^1.11.2"
29-
ddtrace = "^0.58.1"
29+
ddtrace = "^0.59.2"
3030
importlib_metadata = {version = "^1.0", python = "<3.8"}
3131
boto3 = { version = "^1.10.33", optional = true }
3232
typing_extensions = {version = "^4.0", python = "<3.8"}
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
{
2+
"Records": [
3+
{
4+
"EventSource": "aws:sns",
5+
"EventVersion": "1.0",
6+
"EventSubscriptionArn": "arn:aws:sns:sa-east-1:601427279990:serverlessTracingTopicPy:224b60ba-befc-4830-ad96-f1f0ac94eb04",
7+
"Sns": {
8+
"Type": "Notification",
9+
"MessageId": "87056a47-f506-5d77-908b-303605d3b197",
10+
"TopicArn": "arn:aws:sns:sa-east-1:601427279990:serverlessTracingTopicPy",
11+
"Subject": null,
12+
"Message": "Asynchronously invoking a Lambda function with SNS.",
13+
"Timestamp": "2022-01-31T14:13:41.637Z",
14+
"SignatureVersion": "1",
15+
"Signature": "BmwnJb0Ku2KgQef9QOgaSSTwLyUsbkRq90lzD5Vn4mAcRUOq2ForfMOYbxMB6idljWIWy9t/jK4AIMxPGk/eOGiRcENx3BvAcGcoDayBRFY13+xUGaPn5Lfoht/ZJ7/hmCgFWKRa8ooATZL+AwGAw6Id8qzf0R3M3k2asy5Vxa4ODKiFW9OzWY/zFgsYJhddR3JrQl9YOMRyIobNNHT96o1TwjGsSUTEemrxA6jQtb3QbardEKO+2SuataLEZki7gE2D2sA300WqZecumI339q7la+OIj6VDGDwFoppE2sh8hzJYXAH7oo11giwltE0V3/eLFCVhsE8Y1KD/yDPPsA==",
16+
"SigningCertUrl": "https://sns.sa-east-1.amazonaws.com/SimpleNotificationService-7ff5318490ec183fbaddaa2a969abfda.pem",
17+
"UnsubscribeUrl": "https://sns.sa-east-1.amazonaws.com/?Action=Unsubscribe&SubscriptionArn=arn:aws:sns:sa-east-1:601427279990:serverlessTracingTopicPy:224b60ba-befc-4830-ad96-f1f0ac94eb04",
18+
"MessageAttributes": {
19+
"_datadog": {
20+
"Type": "Binary",
21+
"Value": "eyJ4LWRhdGFkb2ctdHJhY2UtaWQiOiI0OTQ4Mzc3MzE2MzU3MjkxNDIxIiwieC1kYXRhZG9nLXBhcmVudC1pZCI6IjY3NDY5OTgwMTUwMzc0Mjk1MTIiLCJ4LWRhdGFkb2ctc2FtcGxpbmctcHJpb3JpdHkiOiIxIn0="
22+
}
23+
}
24+
}
25+
}
26+
]
27+
}

tests/integration/snapshots/logs/async-metrics_python36.log

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1114,6 +1114,7 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", "
11141114
"_inferred_span.tag_source": "self"
11151115
},
11161116
"metrics": {
1117+
"_dd.agent_psr": 1,
11171118
"system.pid": "XXXX",
11181119
"_sampling_priority_v1": 1,
11191120
"_dd.top_level": 1

tests/integration/snapshots/logs/async-metrics_python37.log

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1114,6 +1114,7 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", "
11141114
"_inferred_span.tag_source": "self"
11151115
},
11161116
"metrics": {
1117+
"_dd.agent_psr": 1,
11171118
"system.pid": "XXXX",
11181119
"_sampling_priority_v1": 1,
11191120
"_dd.top_level": 1

tests/integration/snapshots/logs/async-metrics_python38.log

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1114,6 +1114,7 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", "
11141114
"_inferred_span.tag_source": "self"
11151115
},
11161116
"metrics": {
1117+
"_dd.agent_psr": 1,
11171118
"system.pid": "XXXX",
11181119
"_sampling_priority_v1": 1,
11191120
"_dd.top_level": 1

tests/integration/snapshots/logs/async-metrics_python39.log

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1114,6 +1114,7 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", "
11141114
"_inferred_span.tag_source": "self"
11151115
},
11161116
"metrics": {
1117+
"_dd.agent_psr": 1,
11171118
"system.pid": "XXXX",
11181119
"_sampling_priority_v1": 1,
11191120
"_dd.top_level": 1

tests/integration/snapshots/logs/sync-metrics_python36.log

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1185,6 +1185,7 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", "
11851185
"_inferred_span.tag_source": "self"
11861186
},
11871187
"metrics": {
1188+
"_dd.agent_psr": 1,
11881189
"system.pid": "XXXX",
11891190
"_sampling_priority_v1": 1,
11901191
"_dd.top_level": 1

tests/integration/snapshots/logs/sync-metrics_python37.log

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1185,6 +1185,7 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", "
11851185
"_inferred_span.tag_source": "self"
11861186
},
11871187
"metrics": {
1188+
"_dd.agent_psr": 1,
11881189
"system.pid": "XXXX",
11891190
"_sampling_priority_v1": 1,
11901191
"_dd.top_level": 1

tests/integration/snapshots/logs/sync-metrics_python38.log

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1185,6 +1185,7 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", "
11851185
"_inferred_span.tag_source": "self"
11861186
},
11871187
"metrics": {
1188+
"_dd.agent_psr": 1,
11881189
"system.pid": "XXXX",
11891190
"_sampling_priority_v1": 1,
11901191
"_dd.top_level": 1

tests/integration/snapshots/logs/sync-metrics_python39.log

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1185,6 +1185,7 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", "
11851185
"_inferred_span.tag_source": "self"
11861186
},
11871187
"metrics": {
1188+
"_dd.agent_psr": 1,
11881189
"system.pid": "XXXX",
11891190
"_sampling_priority_v1": 1,
11901191
"_dd.top_level": 1

tests/test_tracing.py

Lines changed: 61 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -253,7 +253,8 @@ def test_with_sqs_distributed_datadog_trace_data(self):
253253
TraceHeader.PARENT_ID: "321",
254254
TraceHeader.SAMPLING_PRIORITY: "1",
255255
}
256-
)
256+
),
257+
"dataType": "String",
257258
}
258259
},
259260
"md5OfBody": "e4e68fb7bd0e697a0ae8f1bb342846b3",
@@ -796,9 +797,9 @@ def test_create_inferred_span_from_api_gateway_websocket_disconnect_event(self):
796797
self.assertEqual(span.get_tag(InferredSpanInfo.TAG_SOURCE), "self")
797798
self.assertEqual(span.get_tag(InferredSpanInfo.SYNCHRONICITY), "sync")
798799

799-
def test_create_inferred_span_from_sqs_event(self):
800-
event_sample_source = "sqs"
801-
test_file = event_samples + event_sample_source + ".json"
800+
def test_create_inferred_span_from_sqs_event_string_msg_attr(self):
801+
event_sample_name = "sqs-string-msg-attribute"
802+
test_file = event_samples + event_sample_name + ".json"
802803
with open(test_file, "r") as event:
803804
event = json.load(event)
804805
ctx = get_mock_context()
@@ -834,9 +835,47 @@ def test_create_inferred_span_from_sqs_event(self):
834835
self.assertEqual(span.get_tag(InferredSpanInfo.TAG_SOURCE), "self")
835836
self.assertEqual(span.get_tag(InferredSpanInfo.SYNCHRONICITY), "async")
836837

837-
def test_create_inferred_span_from_sns_event(self):
838-
event_sample_source = "sns"
839-
test_file = event_samples + event_sample_source + ".json"
838+
def test_create_inferred_span_from_sns_event_string_msg_attr(self):
839+
event_sample_name = "sns-string-msg-attribute"
840+
test_file = event_samples + event_sample_name + ".json"
841+
with open(test_file, "r") as event:
842+
event = json.load(event)
843+
ctx = get_mock_context()
844+
ctx.aws_request_id = "123"
845+
span = create_inferred_span(event, ctx)
846+
self.assertEqual(span.get_tag("operation_name"), "aws.sns")
847+
self.assertEqual(
848+
span.service,
849+
"sns",
850+
)
851+
self.assertEqual(
852+
span.get_tag("http.url"),
853+
None,
854+
)
855+
self.assertEqual(span.get_tag("endpoint"), None)
856+
self.assertEqual(span.get_tag("http.method"), None)
857+
self.assertEqual(
858+
span.get_tag("resource_names"),
859+
"serverlessTracingTopicPy",
860+
)
861+
self.assertEqual(span.get_tag("topicname"), "serverlessTracingTopicPy")
862+
self.assertEqual(
863+
span.get_tag("topic_arn"),
864+
"arn:aws:sns:sa-east-1:601427279990:serverlessTracingTopicPy",
865+
)
866+
self.assertEqual(
867+
span.get_tag("message_id"), "87056a47-f506-5d77-908b-303605d3b197"
868+
)
869+
self.assertEqual(span.get_tag("type"), "Notification")
870+
self.assertEqual(span.get_tag("subject"), None)
871+
self.assertEqual(span.start, 1643638421.637)
872+
self.assertEqual(span.span_type, "web")
873+
self.assertEqual(span.get_tag(InferredSpanInfo.TAG_SOURCE), "self")
874+
self.assertEqual(span.get_tag(InferredSpanInfo.SYNCHRONICITY), "async")
875+
876+
def test_create_inferred_span_from_sns_event_b64_msg_attr(self):
877+
event_sample_name = "sns-b64-msg-attribute"
878+
test_file = event_samples + event_sample_name + ".json"
840879
with open(test_file, "r") as event:
841880
event = json.load(event)
842881
ctx = get_mock_context()
@@ -1040,8 +1079,8 @@ def test_extract_dd_trace_context_for_eventbridge(self):
10401079
self.assertEqual(context["trace-id"], "12345")
10411080
self.assertEqual(context["parent-id"], "67890")
10421081

1043-
def test_extract_context_from_sqs_event(self):
1044-
event_sample_source = "sqs"
1082+
def test_extract_context_from_sqs_event_with_string_msg_attr(self):
1083+
event_sample_source = "sqs-string-msg-attribute"
10451084
test_file = event_samples + event_sample_source + ".json"
10461085
with open(test_file, "r") as event:
10471086
event = json.load(event)
@@ -1062,8 +1101,19 @@ def test_extract_context_from_sqs_batch_event(self):
10621101
self.assertEqual(context["parent-id"], "7431398482019833808")
10631102
self.assertEqual(context["sampling-priority"], "1")
10641103

1065-
def test_extract_context_from_sns_event(self):
1066-
event_sample_source = "sns"
1104+
def test_extract_context_from_sns_event_with_string_msg_attr(self):
1105+
event_sample_source = "sns-string-msg-attribute"
1106+
test_file = event_samples + event_sample_source + ".json"
1107+
with open(test_file, "r") as event:
1108+
event = json.load(event)
1109+
ctx = get_mock_context()
1110+
context, source = extract_dd_trace_context(event, ctx)
1111+
self.assertEqual(context["trace-id"], "4948377316357291421")
1112+
self.assertEqual(context["parent-id"], "6746998015037429512")
1113+
self.assertEqual(context["sampling-priority"], "1")
1114+
1115+
def test_extract_context_from_sns_event_with_b64_msg_attr(self):
1116+
event_sample_source = "sns-b64-msg-attribute"
10671117
test_file = event_samples + event_sample_source + ".json"
10681118
with open(test_file, "r") as event:
10691119
event = json.load(event)

tests/test_trigger.py

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -206,7 +206,8 @@ def test_event_source_s3(self):
206206

207207
def test_event_source_sns(self):
208208
event_sample_source = "sns"
209-
test_file = event_samples + event_sample_source + ".json"
209+
event_sample_name = "sns-string-msg-attribute"
210+
test_file = event_samples + event_sample_name + ".json"
210211
with open(test_file, "r") as event:
211212
event = json.load(event)
212213
ctx = get_mock_context()
@@ -220,7 +221,8 @@ def test_event_source_sns(self):
220221

221222
def test_event_source_sqs(self):
222223
event_sample_source = "sqs"
223-
test_file = event_samples + event_sample_source + ".json"
224+
event_sample_name = "sqs-string-msg-attribute"
225+
test_file = event_samples + event_sample_name + ".json"
224226
with open(test_file, "r") as event:
225227
event = json.load(event)
226228
ctx = get_mock_context()
@@ -455,8 +457,8 @@ def test_extract_trigger_tags_s3(self):
455457
)
456458

457459
def test_extract_trigger_tags_sns(self):
458-
event_sample_source = "sns"
459-
test_file = event_samples + event_sample_source + ".json"
460+
event_sample_name = "sns-string-msg-attribute"
461+
test_file = event_samples + event_sample_name + ".json"
460462
ctx = get_mock_context()
461463
with open(test_file, "r") as event:
462464
event = json.load(event)
@@ -470,8 +472,8 @@ def test_extract_trigger_tags_sns(self):
470472
)
471473

472474
def test_extract_trigger_tags_sqs(self):
473-
event_sample_source = "sqs"
474-
test_file = event_samples + event_sample_source + ".json"
475+
event_sample_name = "sqs-string-msg-attribute"
476+
test_file = event_samples + event_sample_name + ".json"
475477
ctx = get_mock_context()
476478
with open(test_file, "r") as event:
477479
event = json.load(event)

0 commit comments

Comments
 (0)