datadog_lambda 6.99.0__tar.gz → 6.101.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.
Files changed (30) hide show
  1. {datadog_lambda-6.99.0 → datadog_lambda-6.101.0}/PKG-INFO +3 -2
  2. datadog_lambda-6.101.0/datadog_lambda/span_pointers.py +168 -0
  3. {datadog_lambda-6.99.0 → datadog_lambda-6.101.0}/datadog_lambda/thread_stats_writer.py +7 -1
  4. {datadog_lambda-6.99.0 → datadog_lambda-6.101.0}/datadog_lambda/tracing.py +4 -1
  5. {datadog_lambda-6.99.0 → datadog_lambda-6.101.0}/datadog_lambda/trigger.py +6 -0
  6. datadog_lambda-6.101.0/datadog_lambda/version.py +1 -0
  7. {datadog_lambda-6.99.0 → datadog_lambda-6.101.0}/pyproject.toml +2 -2
  8. datadog_lambda-6.99.0/datadog_lambda/span_pointers.py +0 -91
  9. datadog_lambda-6.99.0/datadog_lambda/version.py +0 -1
  10. {datadog_lambda-6.99.0 → datadog_lambda-6.101.0}/LICENSE +0 -0
  11. {datadog_lambda-6.99.0 → datadog_lambda-6.101.0}/LICENSE-3rdparty.csv +0 -0
  12. {datadog_lambda-6.99.0 → datadog_lambda-6.101.0}/NOTICE +0 -0
  13. {datadog_lambda-6.99.0 → datadog_lambda-6.101.0}/README.md +0 -0
  14. {datadog_lambda-6.99.0 → datadog_lambda-6.101.0}/datadog_lambda/__init__.py +0 -0
  15. {datadog_lambda-6.99.0 → datadog_lambda-6.101.0}/datadog_lambda/api.py +0 -0
  16. {datadog_lambda-6.99.0 → datadog_lambda-6.101.0}/datadog_lambda/cold_start.py +0 -0
  17. {datadog_lambda-6.99.0 → datadog_lambda-6.101.0}/datadog_lambda/constants.py +0 -0
  18. {datadog_lambda-6.99.0 → datadog_lambda-6.101.0}/datadog_lambda/dogstatsd.py +0 -0
  19. {datadog_lambda-6.99.0 → datadog_lambda-6.101.0}/datadog_lambda/extension.py +0 -0
  20. {datadog_lambda-6.99.0 → datadog_lambda-6.101.0}/datadog_lambda/handler.py +0 -0
  21. {datadog_lambda-6.99.0 → datadog_lambda-6.101.0}/datadog_lambda/logger.py +0 -0
  22. {datadog_lambda-6.99.0 → datadog_lambda-6.101.0}/datadog_lambda/metric.py +0 -0
  23. {datadog_lambda-6.99.0 → datadog_lambda-6.101.0}/datadog_lambda/module_name.py +0 -0
  24. {datadog_lambda-6.99.0 → datadog_lambda-6.101.0}/datadog_lambda/patch.py +0 -0
  25. {datadog_lambda-6.99.0 → datadog_lambda-6.101.0}/datadog_lambda/stats_writer.py +0 -0
  26. {datadog_lambda-6.99.0 → datadog_lambda-6.101.0}/datadog_lambda/statsd_writer.py +0 -0
  27. {datadog_lambda-6.99.0 → datadog_lambda-6.101.0}/datadog_lambda/tag_object.py +0 -0
  28. {datadog_lambda-6.99.0 → datadog_lambda-6.101.0}/datadog_lambda/tags.py +0 -0
  29. {datadog_lambda-6.99.0 → datadog_lambda-6.101.0}/datadog_lambda/wrapper.py +0 -0
  30. {datadog_lambda-6.99.0 → datadog_lambda-6.101.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.99.0
3
+ Version: 6.101.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.14.1)
22
+ Requires-Dist: ddtrace (>=2.16.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"
@@ -0,0 +1,168 @@
1
+ from itertools import chain
2
+ import logging
3
+ import os
4
+ from typing import List
5
+
6
+ from ddtrace._trace._span_pointer import _SpanPointerDirection
7
+ from ddtrace._trace._span_pointer import _SpanPointerDescription
8
+ from datadog_lambda.trigger import EventTypes
9
+
10
+
11
+ logger = logging.getLogger(__name__)
12
+
13
+
14
+ dd_botocore_add_span_pointers = os.environ.get(
15
+ "DD_BOTOCORE_ADD_SPAN_POINTERS", "true"
16
+ ).lower() in ("true", "1")
17
+
18
+
19
+ def calculate_span_pointers(
20
+ event_source,
21
+ event,
22
+ botocore_add_span_pointers=dd_botocore_add_span_pointers,
23
+ ) -> List[_SpanPointerDescription]:
24
+ try:
25
+ if botocore_add_span_pointers:
26
+ if event_source.equals(EventTypes.S3):
27
+ return _calculate_s3_span_pointers_for_event(event)
28
+
29
+ elif event_source.equals(EventTypes.DYNAMODB):
30
+ return _calculate_dynamodb_span_pointers_for_event(event)
31
+
32
+ except Exception as e:
33
+ logger.warning(
34
+ "failed to calculate span pointers for event: %s",
35
+ e,
36
+ )
37
+
38
+ return []
39
+
40
+
41
+ def _calculate_s3_span_pointers_for_event(event) -> List[_SpanPointerDescription]:
42
+ # Example event:
43
+ # https://docs.aws.amazon.com/lambda/latest/dg/with-s3.html
44
+
45
+ return list(
46
+ chain.from_iterable(
47
+ _calculate_s3_span_pointers_for_event_record(record)
48
+ for record in event.get("Records", [])
49
+ )
50
+ )
51
+
52
+
53
+ def _calculate_s3_span_pointers_for_event_record(
54
+ record,
55
+ ) -> List[_SpanPointerDescription]:
56
+ # Event types:
57
+ # https://docs.aws.amazon.com/AmazonS3/latest/userguide/notification-how-to-event-types-and-destinations.html
58
+
59
+ if record.get("eventName").startswith("ObjectCreated:"):
60
+ s3_information = record.get("s3", None)
61
+ if s3_information is not None:
62
+ return _calculate_s3_span_pointers_for_object_created_s3_information(
63
+ s3_information
64
+ )
65
+
66
+ return []
67
+
68
+
69
+ def _calculate_s3_span_pointers_for_object_created_s3_information(
70
+ s3_information,
71
+ ) -> List[_SpanPointerDescription]:
72
+ try:
73
+ bucket = s3_information["bucket"]["name"]
74
+ key = s3_information["object"]["key"]
75
+ etag = s3_information["object"]["eTag"]
76
+
77
+ except KeyError as e:
78
+ logger.warning(
79
+ "missing s3 information required to make a span pointer: %s",
80
+ e,
81
+ )
82
+ return []
83
+
84
+ try:
85
+ from ddtrace._trace.utils_botocore.span_pointers.s3 import (
86
+ _aws_s3_object_span_pointer_description,
87
+ )
88
+
89
+ return [
90
+ _aws_s3_object_span_pointer_description(
91
+ pointer_direction=_SpanPointerDirection.UPSTREAM,
92
+ bucket=bucket,
93
+ key=key,
94
+ etag=etag,
95
+ )
96
+ ]
97
+
98
+ except Exception as e:
99
+ logger.warning(
100
+ "failed to generate S3 span pointer: %s",
101
+ e,
102
+ )
103
+ return []
104
+
105
+
106
+ def _calculate_dynamodb_span_pointers_for_event(event) -> List[_SpanPointerDescription]:
107
+ # Example event:
108
+ # https://docs.aws.amazon.com/lambda/latest/dg/with-ddb.html
109
+
110
+ return list(
111
+ chain.from_iterable(
112
+ _calculate_dynamodb_span_pointers_for_event_record(record)
113
+ for record in event.get("Records", [])
114
+ )
115
+ )
116
+
117
+
118
+ def _calculate_dynamodb_span_pointers_for_event_record(
119
+ record,
120
+ ) -> List[_SpanPointerDescription]:
121
+ try:
122
+ table_name = _extract_table_name_from_dynamodb_stream_record(record)
123
+ primary_key = record["dynamodb"]["Keys"]
124
+
125
+ except Exception as e:
126
+ logger.warning(
127
+ "missing DynamoDB information required to make a span pointer: %s",
128
+ e,
129
+ )
130
+ return []
131
+
132
+ try:
133
+ from ddtrace._trace.utils_botocore.span_pointers.dynamodb import (
134
+ _aws_dynamodb_item_span_pointer_description,
135
+ )
136
+
137
+ return [
138
+ _aws_dynamodb_item_span_pointer_description(
139
+ pointer_direction=_SpanPointerDirection.UPSTREAM,
140
+ table_name=table_name,
141
+ primary_key=primary_key,
142
+ )
143
+ ]
144
+
145
+ except Exception as e:
146
+ logger.warning(
147
+ "failed to generate DynamoDB span pointer: %s",
148
+ e,
149
+ )
150
+ return []
151
+
152
+
153
+ def _extract_table_name_from_dynamodb_stream_record(record) -> str:
154
+ # Example eventSourceARN:
155
+ # arn:aws:dynamodb:us-east-2:123456789012:table/my-table/stream/2024-06-10T19:26:16.525
156
+ event_source_arn = record["eventSourceARN"]
157
+
158
+ [_arn, _aws, _dynamodb, _region, _account, dynamodb_info] = event_source_arn.split(
159
+ ":", maxsplit=5
160
+ )
161
+ if _arn != "arn" or _aws != "aws" or _dynamodb != "dynamodb":
162
+ raise ValueError(f"unexpected eventSourceARN format: {event_source_arn}")
163
+
164
+ [_table, table_name, _stream, _timestamp] = dynamodb_info.split("/")
165
+ if _table != "table" or _stream != "stream":
166
+ raise ValueError(f"unexpected eventSourceARN format: {event_source_arn}")
167
+
168
+ 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
- self.thread_stats.constant_tags = self.thread_stats.constant_tags + tags
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()
@@ -411,7 +411,10 @@ def is_legacy_lambda_step_function(event):
411
411
  """
412
412
  Check if the event is a step function that called a legacy lambda
413
413
  """
414
- event = event.get("Payload", {})
414
+ if not isinstance(event, dict) or "Payload" not in event:
415
+ return False
416
+
417
+ event = event.get("Payload")
415
418
  return "Execution" in event and "StateMachine" in event and "State" in event
416
419
 
417
420
 
@@ -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.101.0"
@@ -1,6 +1,6 @@
1
1
  [tool.poetry]
2
2
  name = "datadog_lambda"
3
- version = "6.99.0"
3
+ version = "6.101.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.14.1"
30
+ ddtrace = ">=2.16.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,91 +0,0 @@
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 []
@@ -1 +0,0 @@
1
- __version__ = "6.99.0"
File without changes