Skip to content

Commit c52970f

Browse files
[SVLS-5265] S3 Event Handler Span Pointers (#513)
Adding Span Pointers for the upstream S3 objects when a lambda is triggered by an S3 ObjectCreated event.
1 parent d97d9bb commit c52970f

File tree

8 files changed

+403
-216
lines changed

8 files changed

+403
-216
lines changed

Diff for: datadog_lambda/span_pointers.py

+91
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
from itertools import chain
2+
import logging
3+
from typing import List
4+
5+
from ddtrace._trace.utils_botocore.span_pointers import (
6+
_aws_s3_object_span_pointer_description,
7+
)
8+
from ddtrace._trace._span_pointer import _SpanPointerDirection
9+
from ddtrace._trace._span_pointer import _SpanPointerDescription
10+
from datadog_lambda.trigger import EventTypes
11+
12+
13+
logger = logging.getLogger(__name__)
14+
15+
16+
def calculate_span_pointers(
17+
event_source,
18+
event,
19+
) -> List[_SpanPointerDescription]:
20+
try:
21+
if event_source.equals(EventTypes.S3):
22+
return _calculate_s3_span_pointers_for_event(event)
23+
24+
except Exception as e:
25+
logger.warning(
26+
"failed to calculate span pointers for event: %s",
27+
str(e),
28+
)
29+
30+
return []
31+
32+
33+
def _calculate_s3_span_pointers_for_event(event) -> List[_SpanPointerDescription]:
34+
# Example event:
35+
# https://docs.aws.amazon.com/lambda/latest/dg/with-s3.html
36+
37+
return list(
38+
chain.from_iterable(
39+
_calculate_s3_span_pointers_for_event_record(record)
40+
for record in event.get("Records", [])
41+
)
42+
)
43+
44+
45+
def _calculate_s3_span_pointers_for_event_record(
46+
record,
47+
) -> List[_SpanPointerDescription]:
48+
# Event types:
49+
# https://docs.aws.amazon.com/AmazonS3/latest/userguide/notification-how-to-event-types-and-destinations.html
50+
51+
if record.get("eventName").startswith("ObjectCreated:"):
52+
s3_information = record.get("s3", None)
53+
if s3_information is not None:
54+
return _calculate_s3_span_pointers_for_object_created_s3_information(
55+
s3_information
56+
)
57+
58+
return []
59+
60+
61+
def _calculate_s3_span_pointers_for_object_created_s3_information(
62+
s3_information,
63+
) -> List[_SpanPointerDescription]:
64+
try:
65+
bucket = s3_information["bucket"]["name"]
66+
key = s3_information["object"]["key"]
67+
etag = s3_information["object"]["eTag"]
68+
69+
except KeyError as e:
70+
logger.warning(
71+
"missing s3 information required to make a span pointer: %s",
72+
str(e),
73+
)
74+
return []
75+
76+
try:
77+
return [
78+
_aws_s3_object_span_pointer_description(
79+
pointer_direction=_SpanPointerDirection.UPSTREAM,
80+
bucket=bucket,
81+
key=key,
82+
etag=etag,
83+
)
84+
]
85+
86+
except Exception as e:
87+
logger.warning(
88+
"failed to generate S3 span pointer: %s",
89+
str(e),
90+
)
91+
return []

Diff for: datadog_lambda/tracing.py

+9
Original file line numberDiff line numberDiff line change
@@ -1259,6 +1259,7 @@ def create_function_execution_span(
12591259
merge_xray_traces,
12601260
trigger_tags,
12611261
parent_span=None,
1262+
span_pointers=None,
12621263
):
12631264
tags = None
12641265
if context:
@@ -1296,6 +1297,14 @@ def create_function_execution_span(
12961297
span.set_tags(tags)
12971298
if parent_span:
12981299
span.parent_id = parent_span.span_id
1300+
if span_pointers:
1301+
for span_pointer_description in span_pointers:
1302+
span._add_span_pointer(
1303+
pointer_kind=span_pointer_description.pointer_kind,
1304+
pointer_direction=span_pointer_description.pointer_direction,
1305+
pointer_hash=span_pointer_description.pointer_hash,
1306+
extra_attributes=span_pointer_description.extra_attributes,
1307+
)
12991308
return span
13001309

13011310

Diff for: datadog_lambda/wrapper.py

+9-7
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@
3030
)
3131
from datadog_lambda.module_name import modify_module_name
3232
from datadog_lambda.patch import patch_all
33+
from datadog_lambda.span_pointers import calculate_span_pointers
3334
from datadog_lambda.tracing import (
3435
extract_dd_trace_context,
3536
create_dd_dummy_metadata_subsegment,
@@ -307,14 +308,15 @@ def _before(self, event, context):
307308
event, context, event_source, self.decode_authorizer_context
308309
)
309310
self.span = create_function_execution_span(
310-
context,
311-
self.function_name,
312-
is_cold_start(),
313-
is_proactive_init(),
314-
trace_context_source,
315-
self.merge_xray_traces,
316-
self.trigger_tags,
311+
context=context,
312+
function_name=self.function_name,
313+
is_cold_start=is_cold_start(),
314+
is_proactive_init=is_proactive_init(),
315+
trace_context_source=trace_context_source,
316+
merge_xray_traces=self.merge_xray_traces,
317+
trigger_tags=self.trigger_tags,
317318
parent_span=self.inferred_span,
319+
span_pointers=calculate_span_pointers(event_source, event),
318320
)
319321
else:
320322
set_correlation_ids()

0 commit comments

Comments
 (0)