datadog_lambda 6.98.0__tar.gz → 6.100.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {datadog_lambda-6.98.0 → datadog_lambda-6.100.0}/PKG-INFO +3 -2
- {datadog_lambda-6.98.0 → datadog_lambda-6.100.0}/datadog_lambda/metric.py +1 -0
- datadog_lambda-6.100.0/datadog_lambda/span_pointers.py +158 -0
- {datadog_lambda-6.98.0 → datadog_lambda-6.100.0}/datadog_lambda/thread_stats_writer.py +7 -1
- {datadog_lambda-6.98.0 → datadog_lambda-6.100.0}/datadog_lambda/tracing.py +17 -0
- {datadog_lambda-6.98.0 → datadog_lambda-6.100.0}/datadog_lambda/trigger.py +6 -0
- datadog_lambda-6.100.0/datadog_lambda/version.py +1 -0
- {datadog_lambda-6.98.0 → datadog_lambda-6.100.0}/datadog_lambda/wrapper.py +12 -7
- {datadog_lambda-6.98.0 → datadog_lambda-6.100.0}/pyproject.toml +2 -2
- datadog_lambda-6.98.0/datadog_lambda/version.py +0 -1
- {datadog_lambda-6.98.0 → datadog_lambda-6.100.0}/LICENSE +0 -0
- {datadog_lambda-6.98.0 → datadog_lambda-6.100.0}/LICENSE-3rdparty.csv +0 -0
- {datadog_lambda-6.98.0 → datadog_lambda-6.100.0}/NOTICE +0 -0
- {datadog_lambda-6.98.0 → datadog_lambda-6.100.0}/README.md +0 -0
- {datadog_lambda-6.98.0 → datadog_lambda-6.100.0}/datadog_lambda/__init__.py +0 -0
- {datadog_lambda-6.98.0 → datadog_lambda-6.100.0}/datadog_lambda/api.py +0 -0
- {datadog_lambda-6.98.0 → datadog_lambda-6.100.0}/datadog_lambda/cold_start.py +0 -0
- {datadog_lambda-6.98.0 → datadog_lambda-6.100.0}/datadog_lambda/constants.py +0 -0
- {datadog_lambda-6.98.0 → datadog_lambda-6.100.0}/datadog_lambda/dogstatsd.py +0 -0
- {datadog_lambda-6.98.0 → datadog_lambda-6.100.0}/datadog_lambda/extension.py +0 -0
- {datadog_lambda-6.98.0 → datadog_lambda-6.100.0}/datadog_lambda/handler.py +0 -0
- {datadog_lambda-6.98.0 → datadog_lambda-6.100.0}/datadog_lambda/logger.py +0 -0
- {datadog_lambda-6.98.0 → datadog_lambda-6.100.0}/datadog_lambda/module_name.py +0 -0
- {datadog_lambda-6.98.0 → datadog_lambda-6.100.0}/datadog_lambda/patch.py +0 -0
- {datadog_lambda-6.98.0 → datadog_lambda-6.100.0}/datadog_lambda/stats_writer.py +0 -0
- {datadog_lambda-6.98.0 → datadog_lambda-6.100.0}/datadog_lambda/statsd_writer.py +0 -0
- {datadog_lambda-6.98.0 → datadog_lambda-6.100.0}/datadog_lambda/tag_object.py +0 -0
- {datadog_lambda-6.98.0 → datadog_lambda-6.100.0}/datadog_lambda/tags.py +0 -0
- {datadog_lambda-6.98.0 → datadog_lambda-6.100.0}/datadog_lambda/xray.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: datadog_lambda
|
|
3
|
-
Version: 6.
|
|
3
|
+
Version: 6.100.0
|
|
4
4
|
Summary: The Datadog AWS Lambda Library
|
|
5
5
|
Home-page: https://github.com/DataDog/datadog-lambda-python
|
|
6
6
|
License: Apache-2.0
|
|
@@ -15,10 +15,11 @@ Classifier: Programming Language :: Python :: 3.9
|
|
|
15
15
|
Classifier: Programming Language :: Python :: 3.10
|
|
16
16
|
Classifier: Programming Language :: Python :: 3.11
|
|
17
17
|
Classifier: Programming Language :: Python :: 3.12
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
18
19
|
Provides-Extra: dev
|
|
19
20
|
Requires-Dist: boto3 (>=1.34.0,<2.0.0) ; extra == "dev"
|
|
20
21
|
Requires-Dist: datadog (>=0.41.0,<1.0.0)
|
|
21
|
-
Requires-Dist: ddtrace (>=2.
|
|
22
|
+
Requires-Dist: ddtrace (>=2.15.0)
|
|
22
23
|
Requires-Dist: flake8 (>=5.0.4,<6.0.0) ; extra == "dev"
|
|
23
24
|
Requires-Dist: pytest (>=8.0.0,<9.0.0) ; extra == "dev"
|
|
24
25
|
Requires-Dist: pytest-benchmark (>=4.0,<5.0) ; extra == "dev"
|
|
@@ -125,6 +125,7 @@ def flush_stats(lambda_context=None):
|
|
|
125
125
|
lambda_stats.flush()
|
|
126
126
|
|
|
127
127
|
if extension_thread_stats is not None:
|
|
128
|
+
tags = None
|
|
128
129
|
if lambda_context is not None:
|
|
129
130
|
tags = get_enhanced_metrics_tags(lambda_context)
|
|
130
131
|
split_arn = lambda_context.invoked_function_arn.split(":")
|
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
from itertools import chain
|
|
2
|
+
import logging
|
|
3
|
+
from typing import List
|
|
4
|
+
|
|
5
|
+
from ddtrace._trace.utils_botocore.span_pointers.dynamodb import (
|
|
6
|
+
_aws_dynamodb_item_span_pointer_description,
|
|
7
|
+
)
|
|
8
|
+
from ddtrace._trace.utils_botocore.span_pointers.s3 import (
|
|
9
|
+
_aws_s3_object_span_pointer_description,
|
|
10
|
+
)
|
|
11
|
+
from ddtrace._trace._span_pointer import _SpanPointerDirection
|
|
12
|
+
from ddtrace._trace._span_pointer import _SpanPointerDescription
|
|
13
|
+
from datadog_lambda.trigger import EventTypes
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
logger = logging.getLogger(__name__)
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
def calculate_span_pointers(
|
|
20
|
+
event_source,
|
|
21
|
+
event,
|
|
22
|
+
) -> List[_SpanPointerDescription]:
|
|
23
|
+
try:
|
|
24
|
+
if event_source.equals(EventTypes.S3):
|
|
25
|
+
return _calculate_s3_span_pointers_for_event(event)
|
|
26
|
+
|
|
27
|
+
elif event_source.equals(EventTypes.DYNAMODB):
|
|
28
|
+
return _calculate_dynamodb_span_pointers_for_event(event)
|
|
29
|
+
|
|
30
|
+
except Exception as e:
|
|
31
|
+
logger.warning(
|
|
32
|
+
"failed to calculate span pointers for event: %s",
|
|
33
|
+
e,
|
|
34
|
+
)
|
|
35
|
+
|
|
36
|
+
return []
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
def _calculate_s3_span_pointers_for_event(event) -> List[_SpanPointerDescription]:
|
|
40
|
+
# Example event:
|
|
41
|
+
# https://docs.aws.amazon.com/lambda/latest/dg/with-s3.html
|
|
42
|
+
|
|
43
|
+
return list(
|
|
44
|
+
chain.from_iterable(
|
|
45
|
+
_calculate_s3_span_pointers_for_event_record(record)
|
|
46
|
+
for record in event.get("Records", [])
|
|
47
|
+
)
|
|
48
|
+
)
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
def _calculate_s3_span_pointers_for_event_record(
|
|
52
|
+
record,
|
|
53
|
+
) -> List[_SpanPointerDescription]:
|
|
54
|
+
# Event types:
|
|
55
|
+
# https://docs.aws.amazon.com/AmazonS3/latest/userguide/notification-how-to-event-types-and-destinations.html
|
|
56
|
+
|
|
57
|
+
if record.get("eventName").startswith("ObjectCreated:"):
|
|
58
|
+
s3_information = record.get("s3", None)
|
|
59
|
+
if s3_information is not None:
|
|
60
|
+
return _calculate_s3_span_pointers_for_object_created_s3_information(
|
|
61
|
+
s3_information
|
|
62
|
+
)
|
|
63
|
+
|
|
64
|
+
return []
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
def _calculate_s3_span_pointers_for_object_created_s3_information(
|
|
68
|
+
s3_information,
|
|
69
|
+
) -> List[_SpanPointerDescription]:
|
|
70
|
+
try:
|
|
71
|
+
bucket = s3_information["bucket"]["name"]
|
|
72
|
+
key = s3_information["object"]["key"]
|
|
73
|
+
etag = s3_information["object"]["eTag"]
|
|
74
|
+
|
|
75
|
+
except KeyError as e:
|
|
76
|
+
logger.warning(
|
|
77
|
+
"missing s3 information required to make a span pointer: %s",
|
|
78
|
+
e,
|
|
79
|
+
)
|
|
80
|
+
return []
|
|
81
|
+
|
|
82
|
+
try:
|
|
83
|
+
return [
|
|
84
|
+
_aws_s3_object_span_pointer_description(
|
|
85
|
+
pointer_direction=_SpanPointerDirection.UPSTREAM,
|
|
86
|
+
bucket=bucket,
|
|
87
|
+
key=key,
|
|
88
|
+
etag=etag,
|
|
89
|
+
)
|
|
90
|
+
]
|
|
91
|
+
|
|
92
|
+
except Exception as e:
|
|
93
|
+
logger.warning(
|
|
94
|
+
"failed to generate S3 span pointer: %s",
|
|
95
|
+
e,
|
|
96
|
+
)
|
|
97
|
+
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
|
+
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
|
+
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 _table != "table" or _stream != "stream":
|
|
156
|
+
raise ValueError(f"unexpected eventSourceARN format: {event_source_arn}")
|
|
157
|
+
|
|
158
|
+
return table_name
|
|
@@ -27,8 +27,11 @@ class ThreadStatsWriter(StatsWriter):
|
|
|
27
27
|
Modified based on `datadog.threadstats.base.ThreadStats.flush()`,
|
|
28
28
|
to gain better control over exception handling.
|
|
29
29
|
"""
|
|
30
|
+
original_constant_tags = self.thread_stats.constant_tags.copy()
|
|
30
31
|
if tags:
|
|
31
|
-
|
|
32
|
+
# Temporarily add tags for this flush
|
|
33
|
+
self.thread_stats.constant_tags = original_constant_tags + tags
|
|
34
|
+
|
|
32
35
|
_, dists = self.thread_stats._get_aggregate_metrics_and_dists(float("inf"))
|
|
33
36
|
count_dists = len(dists)
|
|
34
37
|
if not count_dists:
|
|
@@ -62,6 +65,9 @@ class ThreadStatsWriter(StatsWriter):
|
|
|
62
65
|
logger.debug(
|
|
63
66
|
"Flush #%s failed", self.thread_stats.flush_count, exc_info=True
|
|
64
67
|
)
|
|
68
|
+
finally:
|
|
69
|
+
# Reset constant_tags to its original state
|
|
70
|
+
self.thread_stats.constant_tags = original_constant_tags
|
|
65
71
|
|
|
66
72
|
def stop(self):
|
|
67
73
|
self.thread_stats.stop()
|
|
@@ -407,6 +407,14 @@ def extract_context_from_step_functions(event, lambda_context):
|
|
|
407
407
|
return extract_context_from_lambda_context(lambda_context)
|
|
408
408
|
|
|
409
409
|
|
|
410
|
+
def is_legacy_lambda_step_function(event):
|
|
411
|
+
"""
|
|
412
|
+
Check if the event is a step function that called a legacy lambda
|
|
413
|
+
"""
|
|
414
|
+
event = event.get("Payload", {})
|
|
415
|
+
return "Execution" in event and "StateMachine" in event and "State" in event
|
|
416
|
+
|
|
417
|
+
|
|
410
418
|
def extract_context_custom_extractor(extractor, event, lambda_context):
|
|
411
419
|
"""
|
|
412
420
|
Extract Datadog trace context using a custom trace extractor function
|
|
@@ -1251,6 +1259,7 @@ def create_function_execution_span(
|
|
|
1251
1259
|
merge_xray_traces,
|
|
1252
1260
|
trigger_tags,
|
|
1253
1261
|
parent_span=None,
|
|
1262
|
+
span_pointers=None,
|
|
1254
1263
|
):
|
|
1255
1264
|
tags = None
|
|
1256
1265
|
if context:
|
|
@@ -1288,6 +1297,14 @@ def create_function_execution_span(
|
|
|
1288
1297
|
span.set_tags(tags)
|
|
1289
1298
|
if parent_span:
|
|
1290
1299
|
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
|
+
)
|
|
1291
1308
|
return span
|
|
1292
1309
|
|
|
1293
1310
|
|
|
@@ -299,6 +299,12 @@ def extract_http_tags(event):
|
|
|
299
299
|
if headers and headers.get("Referer"):
|
|
300
300
|
http_tags["http.referer"] = headers.get("Referer")
|
|
301
301
|
|
|
302
|
+
# Try to get `routeKey` from API GW v2; otherwise try to get `resource` from API GW v1
|
|
303
|
+
route = event.get("routeKey") or event.get("resource")
|
|
304
|
+
if route:
|
|
305
|
+
# "GET /my/endpoint" = > "/my/endpoint"
|
|
306
|
+
http_tags["http.route"] = route.split(" ")[-1]
|
|
307
|
+
|
|
302
308
|
return http_tags
|
|
303
309
|
|
|
304
310
|
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
__version__ = "6.100.0"
|
|
@@ -30,6 +30,7 @@ from datadog_lambda.metric import (
|
|
|
30
30
|
)
|
|
31
31
|
from datadog_lambda.module_name import modify_module_name
|
|
32
32
|
from datadog_lambda.patch import patch_all
|
|
33
|
+
from datadog_lambda.span_pointers import calculate_span_pointers
|
|
33
34
|
from datadog_lambda.tracing import (
|
|
34
35
|
extract_dd_trace_context,
|
|
35
36
|
create_dd_dummy_metadata_subsegment,
|
|
@@ -44,6 +45,7 @@ from datadog_lambda.tracing import (
|
|
|
44
45
|
is_authorizer_response,
|
|
45
46
|
tracer,
|
|
46
47
|
propagator,
|
|
48
|
+
is_legacy_lambda_step_function,
|
|
47
49
|
)
|
|
48
50
|
from datadog_lambda.trigger import (
|
|
49
51
|
extract_trigger_tags,
|
|
@@ -277,6 +279,8 @@ class _LambdaDecorator(object):
|
|
|
277
279
|
self.response = None
|
|
278
280
|
set_cold_start(init_timestamp_ns)
|
|
279
281
|
submit_invocations_metric(context)
|
|
282
|
+
if is_legacy_lambda_step_function(event):
|
|
283
|
+
event = event["Payload"]
|
|
280
284
|
self.trigger_tags = extract_trigger_tags(event, context)
|
|
281
285
|
# Extract Datadog trace context and source from incoming requests
|
|
282
286
|
dd_context, trace_context_source, event_source = extract_dd_trace_context(
|
|
@@ -304,14 +308,15 @@ class _LambdaDecorator(object):
|
|
|
304
308
|
event, context, event_source, self.decode_authorizer_context
|
|
305
309
|
)
|
|
306
310
|
self.span = create_function_execution_span(
|
|
307
|
-
context,
|
|
308
|
-
self.function_name,
|
|
309
|
-
is_cold_start(),
|
|
310
|
-
is_proactive_init(),
|
|
311
|
-
trace_context_source,
|
|
312
|
-
self.merge_xray_traces,
|
|
313
|
-
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,
|
|
314
318
|
parent_span=self.inferred_span,
|
|
319
|
+
span_pointers=calculate_span_pointers(event_source, event),
|
|
315
320
|
)
|
|
316
321
|
else:
|
|
317
322
|
set_correlation_ids()
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[tool.poetry]
|
|
2
2
|
name = "datadog_lambda"
|
|
3
|
-
version = "6.
|
|
3
|
+
version = "6.100.0"
|
|
4
4
|
description = "The Datadog AWS Lambda Library"
|
|
5
5
|
authors = ["Datadog, Inc. <dev@datadoghq.com>"]
|
|
6
6
|
license = "Apache-2.0"
|
|
@@ -27,7 +27,7 @@ classifiers = [
|
|
|
27
27
|
python = ">=3.8.0,<4"
|
|
28
28
|
datadog = ">=0.41.0,<1.0.0"
|
|
29
29
|
wrapt = "^1.11.2"
|
|
30
|
-
ddtrace = ">=2.
|
|
30
|
+
ddtrace = ">=2.15.0"
|
|
31
31
|
ujson = ">=5.9.0"
|
|
32
32
|
boto3 = { version = "^1.34.0", optional = true }
|
|
33
33
|
requests = { version ="^2.22.0", optional = true }
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
__version__ = "6.98.0"
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|