Skip to content

Commit 03a6393

Browse files
feat: [SVLS-5677] DynamoDB Stream event span pointers
1 parent 67dbea5 commit 03a6393

File tree

2 files changed

+128
-0
lines changed

2 files changed

+128
-0
lines changed

datadog_lambda/span_pointers.py

+67
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,9 @@
22
import logging
33
from typing import List
44

5+
from ddtrace._trace.utils_botocore.span_pointers.dynamodb import (
6+
_aws_dynamodb_item_span_pointer_description,
7+
)
58
from ddtrace._trace.utils_botocore.span_pointers.s3 import (
69
_aws_s3_object_span_pointer_description,
710
)
@@ -21,6 +24,9 @@ def calculate_span_pointers(
2124
if event_source.equals(EventTypes.S3):
2225
return _calculate_s3_span_pointers_for_event(event)
2326

27+
elif event_source.equals(EventTypes.DYNAMODB):
28+
return _calculate_dynamodb_span_pointers_for_event(event)
29+
2430
except Exception as e:
2531
logger.warning(
2632
"failed to calculate span pointers for event: %s",
@@ -89,3 +95,64 @@ def _calculate_s3_span_pointers_for_object_created_s3_information(
8995
str(e),
9096
)
9197
return []
98+
99+
100+
def _calculate_dynamodb_span_pointers_for_event(event) -> List[_SpanPointerDescription]:
101+
# Example event:
102+
# https://docs.aws.amazon.com/lambda/latest/dg/with-ddb.html
103+
104+
return list(
105+
chain.from_iterable(
106+
_calculate_dynamodb_span_pointers_for_event_record(record)
107+
for record in event.get("Records", [])
108+
)
109+
)
110+
111+
112+
def _calculate_dynamodb_span_pointers_for_event_record(
113+
record,
114+
) -> List[_SpanPointerDescription]:
115+
try:
116+
table_name = _extract_table_name_from_dynamodb_stream_record(record)
117+
primary_key = record["dynamodb"]["Keys"]
118+
119+
except Exception as e:
120+
logger.warning(
121+
"missing DynamoDB information required to make a span pointer: %s",
122+
str(e),
123+
)
124+
return []
125+
126+
try:
127+
return [
128+
_aws_dynamodb_item_span_pointer_description(
129+
pointer_direction=_SpanPointerDirection.UPSTREAM,
130+
table_name=table_name,
131+
primary_key=primary_key,
132+
)
133+
]
134+
135+
except Exception as e:
136+
logger.warning(
137+
"failed to generate DynamoDB span pointer: %s",
138+
str(e),
139+
)
140+
return []
141+
142+
143+
def _extract_table_name_from_dynamodb_stream_record(record) -> str:
144+
# Example eventSourceARN:
145+
# arn:aws:dynamodb:us-east-2:123456789012:table/my-table/stream/2024-06-10T19:26:16.525
146+
event_source_arn = record["eventSourceARN"]
147+
148+
[_arn, _aws, _dynamodb, _region, _account, dynamodb_info] = event_source_arn.split(
149+
":", maxsplit=5
150+
)
151+
if _arn != "arn" or _aws != "aws" or _dynamodb != "dynamodb":
152+
raise ValueError(f"unexpected eventSourceARN format: {event_source_arn}")
153+
154+
[_table, table_name, _stream, _timestamp] = dynamodb_info.split("/")
155+
if not _table == "table" or not _stream == "stream":
156+
raise ValueError(f"unexpected eventSourceARN format: {event_source_arn}")
157+
158+
return table_name

tests/test_span_pointers.py

+61
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,67 @@ class SpanPointersCase(NamedTuple):
8080
},
8181
span_pointers=[],
8282
),
83+
SpanPointersCase(
84+
name="empty dynamodb event",
85+
event_source=_EventSource(EventTypes.DYNAMODB),
86+
event={},
87+
span_pointers=[],
88+
),
89+
SpanPointersCase(
90+
name="sensible dynamodb event",
91+
event_source=_EventSource(EventTypes.DYNAMODB),
92+
event={
93+
"Records": [
94+
{
95+
"eventSourceARN": "arn:aws:dynamodb:us-west-2:123456789012:table/some-table/stream/2015-06-27T00:48:05.899",
96+
"dynamodb": {
97+
"Keys": {
98+
"some-key": {"S": "some-value"},
99+
},
100+
},
101+
},
102+
{
103+
"eventSourceARN": "arn:aws:dynamodb:us-west-2:123456789012:table/some-table/stream/2015-06-27T00:48:05.899",
104+
"dynamodb": {
105+
"Keys": {
106+
"some-key": {"S": "some-other-value"},
107+
},
108+
},
109+
},
110+
],
111+
},
112+
span_pointers=[
113+
_SpanPointerDescription(
114+
pointer_kind="aws.dynamodb.item",
115+
pointer_direction=_SpanPointerDirection.UPSTREAM,
116+
pointer_hash="7f1aee721472bcb48701d45c7c7f7821",
117+
extra_attributes={},
118+
),
119+
_SpanPointerDescription(
120+
pointer_kind="aws.dynamodb.item",
121+
pointer_direction=_SpanPointerDirection.UPSTREAM,
122+
pointer_hash="36b820424312a6069bd3f2185f1af584",
123+
extra_attributes={},
124+
),
125+
],
126+
),
127+
SpanPointersCase(
128+
name="malformed dynamodb event",
129+
event_source=_EventSource(EventTypes.DYNAMODB),
130+
event={
131+
"Records": [
132+
{
133+
"eventSourceARN": "arn:aws:dynamodb:us-west-2:123456789012:table/some-table", # missing stream info
134+
"dynamodb": {
135+
"Keys": {
136+
"some-key": {"S": "some-value"},
137+
},
138+
},
139+
},
140+
],
141+
},
142+
span_pointers=[],
143+
),
83144
],
84145
ids=lambda test_case: test_case.name,
85146
)

0 commit comments

Comments
 (0)