datadog_lambda 8.127.0__tar.gz → 8.129.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 (32) hide show
  1. {datadog_lambda-8.127.0 → datadog_lambda-8.129.0}/PKG-INFO +3 -2
  2. {datadog_lambda-8.127.0 → datadog_lambda-8.129.0}/README.md +1 -0
  3. {datadog_lambda-8.127.0 → datadog_lambda-8.129.0}/datadog_lambda/cold_start.py +5 -1
  4. {datadog_lambda-8.127.0 → datadog_lambda-8.129.0}/datadog_lambda/config.py +11 -0
  5. {datadog_lambda-8.127.0 → datadog_lambda-8.129.0}/datadog_lambda/tracing.py +247 -19
  6. datadog_lambda-8.129.0/datadog_lambda/version.py +1 -0
  7. {datadog_lambda-8.127.0 → datadog_lambda-8.129.0}/pyproject.toml +2 -2
  8. datadog_lambda-8.127.0/datadog_lambda/version.py +0 -1
  9. {datadog_lambda-8.127.0 → datadog_lambda-8.129.0}/LICENSE +0 -0
  10. {datadog_lambda-8.127.0 → datadog_lambda-8.129.0}/LICENSE-3rdparty.csv +0 -0
  11. {datadog_lambda-8.127.0 → datadog_lambda-8.129.0}/NOTICE +0 -0
  12. {datadog_lambda-8.127.0 → datadog_lambda-8.129.0}/datadog_lambda/__init__.py +0 -0
  13. {datadog_lambda-8.127.0 → datadog_lambda-8.129.0}/datadog_lambda/api.py +0 -0
  14. {datadog_lambda-8.127.0 → datadog_lambda-8.129.0}/datadog_lambda/asm.py +0 -0
  15. {datadog_lambda-8.127.0 → datadog_lambda-8.129.0}/datadog_lambda/constants.py +0 -0
  16. {datadog_lambda-8.127.0 → datadog_lambda-8.129.0}/datadog_lambda/dogstatsd.py +0 -0
  17. {datadog_lambda-8.127.0 → datadog_lambda-8.129.0}/datadog_lambda/durable.py +0 -0
  18. {datadog_lambda-8.127.0 → datadog_lambda-8.129.0}/datadog_lambda/extension.py +0 -0
  19. {datadog_lambda-8.127.0 → datadog_lambda-8.129.0}/datadog_lambda/handler.py +0 -0
  20. {datadog_lambda-8.127.0 → datadog_lambda-8.129.0}/datadog_lambda/logger.py +0 -0
  21. {datadog_lambda-8.127.0 → datadog_lambda-8.129.0}/datadog_lambda/metric.py +0 -0
  22. {datadog_lambda-8.127.0 → datadog_lambda-8.129.0}/datadog_lambda/module_name.py +0 -0
  23. {datadog_lambda-8.127.0 → datadog_lambda-8.129.0}/datadog_lambda/patch.py +0 -0
  24. {datadog_lambda-8.127.0 → datadog_lambda-8.129.0}/datadog_lambda/span_pointers.py +0 -0
  25. {datadog_lambda-8.127.0 → datadog_lambda-8.129.0}/datadog_lambda/stats_writer.py +0 -0
  26. {datadog_lambda-8.127.0 → datadog_lambda-8.129.0}/datadog_lambda/statsd_writer.py +0 -0
  27. {datadog_lambda-8.127.0 → datadog_lambda-8.129.0}/datadog_lambda/tag_object.py +0 -0
  28. {datadog_lambda-8.127.0 → datadog_lambda-8.129.0}/datadog_lambda/tags.py +0 -0
  29. {datadog_lambda-8.127.0 → datadog_lambda-8.129.0}/datadog_lambda/thread_stats_writer.py +0 -0
  30. {datadog_lambda-8.127.0 → datadog_lambda-8.129.0}/datadog_lambda/trigger.py +0 -0
  31. {datadog_lambda-8.127.0 → datadog_lambda-8.129.0}/datadog_lambda/wrapper.py +0 -0
  32. {datadog_lambda-8.127.0 → datadog_lambda-8.129.0}/datadog_lambda/xray.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: datadog_lambda
3
- Version: 8.127.0
3
+ Version: 8.129.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
@@ -32,7 +32,7 @@ Requires-Dist: ujson (>=5.10.0,<5.12.0) ; python_version >= "3.8" and python_ver
32
32
  Requires-Dist: ujson (>=5.12.0,<6.0.0) ; python_version >= "3.10"
33
33
  Requires-Dist: urllib3 (>=1.25.4,<1.27) ; python_version >= "3.8" and python_version < "3.10"
34
34
  Requires-Dist: urllib3 (>=2.6.3,<3.0.0) ; python_version >= "3.10"
35
- Requires-Dist: wrapt (>=1.11.2,<2.0.0)
35
+ Requires-Dist: wrapt (>=1.11.2,!=2.2.0,<3)
36
36
  Project-URL: Repository, https://github.com/DataDog/datadog-lambda-python
37
37
  Description-Content-Type: text/markdown
38
38
 
@@ -68,6 +68,7 @@ Besides the environment variables supported by dd-trace-py, the datadog-lambda-p
68
68
  | DD_CAPTURE_LAMBDA_PAYLOAD | [Captures incoming and outgoing AWS Lambda payloads][1] in the Datadog APM spans for Lambda invocations. | `false` |
69
69
  | DD_CAPTURE_LAMBDA_PAYLOAD_MAX_DEPTH | Determines the level of detail captured from AWS Lambda payloads, which are then assigned as tags for the `aws.lambda` span. It specifies the nesting depth of the JSON payload structure to process. Once the specified maximum depth is reached, the tag's value is set to the stringified value of any nested elements beyond this level. <br> For example, given the input payload: <pre>{<br> "lv1" : {<br> "lv2": {<br> "lv3": "val"<br> }<br> }<br>}</pre> If the depth is set to `2`, the resulting tag's key is set to `function.request.lv1.lv2` and the value is `{\"lv3\": \"val\"}`. <br> If the depth is set to `0`, the resulting tag's key is set to `function.request` and value is `{\"lv1\":{\"lv2\":{\"lv3\": \"val\"}}}` | `10` |
70
70
  | DD_EXCEPTION_REPLAY_ENABLED | When set to `true`, the Lambda will run with Error Tracking Exception Replay enabled, capturing local variables. | `false` |
71
+ | DD_DSM_EXCHANGE_NAME | If you are using Datadog Data Streams Monitoring and propagating context through Amazon Event Bridge, this variable specifies the name of the EventBridge EventBus. The name of the bus is *not* passed through in the event payload and therefore cannot be automatically inferred at consume time. | `false` |
71
72
 
72
73
 
73
74
  ## Opening Issues
@@ -30,6 +30,7 @@ Besides the environment variables supported by dd-trace-py, the datadog-lambda-p
30
30
  | DD_CAPTURE_LAMBDA_PAYLOAD | [Captures incoming and outgoing AWS Lambda payloads][1] in the Datadog APM spans for Lambda invocations. | `false` |
31
31
  | DD_CAPTURE_LAMBDA_PAYLOAD_MAX_DEPTH | Determines the level of detail captured from AWS Lambda payloads, which are then assigned as tags for the `aws.lambda` span. It specifies the nesting depth of the JSON payload structure to process. Once the specified maximum depth is reached, the tag's value is set to the stringified value of any nested elements beyond this level. <br> For example, given the input payload: <pre>{<br> "lv1" : {<br> "lv2": {<br> "lv3": "val"<br> }<br> }<br>}</pre> If the depth is set to `2`, the resulting tag's key is set to `function.request.lv1.lv2` and the value is `{\"lv3\": \"val\"}`. <br> If the depth is set to `0`, the resulting tag's key is set to `function.request` and value is `{\"lv1\":{\"lv2\":{\"lv3\": \"val\"}}}` | `10` |
32
32
  | DD_EXCEPTION_REPLAY_ENABLED | When set to `true`, the Lambda will run with Error Tracking Exception Replay enabled, capturing local variables. | `false` |
33
+ | DD_DSM_EXCHANGE_NAME | If you are using Datadog Data Streams Monitoring and propagating context through Amazon Event Bridge, this variable specifies the name of the EventBridge EventBus. The name of the bus is *not* passed through in the event payload and therefore cannot be automatically inferred at consume time. | `false` |
33
34
 
34
35
 
35
36
  ## Opening Issues
@@ -202,7 +202,11 @@ class ColdStartTracer(object):
202
202
  cold_start_span = self.create_cold_start_span(cold_start_span_start_time_ns)
203
203
  while root_nodes:
204
204
  root_node = root_nodes.pop()
205
- parent = root_node.context or cold_start_span
205
+ # Modules lazily imported during the invocation hang off the function
206
+ # span, not the span active at import time: nesting them under a
207
+ # client span (e.g. a DynamoDB call) makes the backend peer service
208
+ # pipeline map that client's host to the import span's service.
209
+ parent = self.trace_ctx if root_node.context else cold_start_span
206
210
  self.trace_tree(root_node, parent)
207
211
  self.finish_span(cold_start_span, cold_start_span_end_time_ns)
208
212
 
@@ -75,6 +75,13 @@ class Config:
75
75
  add_span_pointers = _get_env("DD_BOTOCORE_ADD_SPAN_POINTERS", "true", as_bool)
76
76
  trace_extractor = _get_env("DD_TRACE_EXTRACTOR")
77
77
 
78
+ aws_service_representation_enabled = _get_env(
79
+ "DD_TRACE_AWS_SERVICE_REPRESENTATION_ENABLED", "true", as_bool
80
+ )
81
+ remove_integration_service_names_enabled = _get_env(
82
+ "DD_TRACE_REMOVE_INTEGRATION_SERVICE_NAMES_ENABLED", "false", as_bool
83
+ )
84
+
78
85
  enhanced_metrics_enabled = _get_env("DD_ENHANCED_METRICS", "true", as_bool)
79
86
 
80
87
  flush_in_thread = _get_env("DD_FLUSH_IN_THREAD", "false", as_bool)
@@ -89,6 +96,10 @@ class Config:
89
96
  data_streams_enabled = _get_env(
90
97
  "DD_DATA_STREAMS_ENABLED", "false", as_bool, depends_on_tracing=True
91
98
  )
99
+ # EventBridge bus name used as the DSM `exchange` tag. The bus name is not
100
+ # present in the inbound event, so it must be provided explicitly to allow
101
+ # the consume checkpoint to pair with the EventBridge produce checkpoint.
102
+ dsm_exchange_name = _get_env("DD_DSM_EXCHANGE_NAME")
92
103
  appsec_enabled = _get_env("DD_APPSEC_ENABLED", "false", as_bool)
93
104
  sca_enabled = _get_env("DD_APPSEC_SCA_ENABLED", "false", as_bool)
94
105
 
@@ -83,6 +83,47 @@ def _dsm_set_checkpoint(context_json, event_type, arn):
83
83
  )
84
84
 
85
85
 
86
+ def _dsm_set_eventbridge_checkpoint(context_json, detail_type):
87
+ """Set a DSM consume checkpoint for an EventBridge event.
88
+
89
+ When ddtrace >= 4.14 is present the public ``tags`` parameter is used to
90
+ attach the ``exchange:`` edge tag (sourced from ``DD_DSM_EXCHANGE_NAME``).
91
+ On older installs the checkpoint is still emitted, just without the
92
+ exchange tag.
93
+ """
94
+ if not config.data_streams_enabled or not detail_type:
95
+ return
96
+
97
+ try:
98
+ from ddtrace.data_streams import set_consume_checkpoint
99
+
100
+ carrier_get = lambda k: context_json and context_json.get(k) # noqa: E731
101
+ try:
102
+ tags = (
103
+ ["exchange:" + config.dsm_exchange_name]
104
+ if config.dsm_exchange_name
105
+ else None
106
+ )
107
+ set_consume_checkpoint(
108
+ "eventbridge",
109
+ detail_type,
110
+ carrier_get,
111
+ manual_checkpoint=False,
112
+ tags=tags,
113
+ )
114
+ except TypeError:
115
+ # ddtrace < 4.14 has no `tags` parameter. Retry without it, but
116
+ # keep `manual_checkpoint=False` so the checkpoint stays
117
+ # consistent with every other consume checkpoint.
118
+ set_consume_checkpoint(
119
+ "eventbridge", detail_type, carrier_get, manual_checkpoint=False
120
+ )
121
+ except Exception as e:
122
+ logger.debug(
123
+ f"DSM:Failed to set consume checkpoint for eventbridge {detail_type}: {e}"
124
+ )
125
+
126
+
86
127
  def _convert_xray_trace_id(xray_trace_id):
87
128
  """
88
129
  Convert X-Ray trace id (hex)'s last 63 bits to a Datadog trace id (int).
@@ -251,11 +292,21 @@ def extract_context_from_sqs_or_sns_event_or_context(
251
292
  source_arn = ""
252
293
  event_type = "sqs" if event_source.equals(EventTypes.SQS) else "sns"
253
294
 
254
- # EventBridge => SQS
295
+ # EventBridge => SQS. `dsm_handled` is True when the batch contained at
296
+ # least one EventBridge delivery and DSM checkpoints were already set
297
+ # per-record; in that case the regular SQS path below must not set another
298
+ # checkpoint for the first record or it would be double counted.
299
+ dsm_handled = False
255
300
  try:
256
- context = _extract_context_from_eventbridge_sqs_event(event)
257
- if _is_context_complete(context):
258
- return context
301
+ (
302
+ context,
303
+ is_eventbridge_sqs,
304
+ dsm_handled,
305
+ ) = _extract_context_from_eventbridge_sqs_event(event)
306
+ if is_eventbridge_sqs:
307
+ if _is_context_complete(context):
308
+ return context
309
+ return extract_context_from_lambda_context(lambda_context)
259
310
  except Exception:
260
311
  logger.debug("Failed extracting context as EventBridge to SQS.")
261
312
 
@@ -312,7 +363,8 @@ def extract_context_from_sqs_or_sns_event_or_context(
312
363
  "Failed to extract Step Functions context from SQS/SNS event."
313
364
  )
314
365
  context = propagator.extract(dd_data)
315
- _dsm_set_checkpoint(dd_data, event_type, source_arn)
366
+ if not dsm_handled:
367
+ _dsm_set_checkpoint(dd_data, event_type, source_arn)
316
368
  return context
317
369
  else:
318
370
  # Handle case where trace context is injected into attributes.AWSTraceHeader
@@ -337,12 +389,14 @@ def extract_context_from_sqs_or_sns_event_or_context(
337
389
  sampling_priority=float(x_ray_context["sampled"]),
338
390
  )
339
391
  # Still want to set a DSM checkpoint even if DSM context not propagated
340
- _dsm_set_checkpoint(None, event_type, source_arn)
392
+ if not dsm_handled:
393
+ _dsm_set_checkpoint(None, event_type, source_arn)
341
394
  return extract_context_from_lambda_context(lambda_context)
342
395
  except Exception as e:
343
396
  logger.debug("The trace extractor returned with error %s", e)
344
397
  # Still want to set a DSM checkpoint even if DSM context not propagated
345
- _dsm_set_checkpoint(None, event_type, source_arn)
398
+ if not dsm_handled:
399
+ _dsm_set_checkpoint(None, event_type, source_arn)
346
400
  return extract_context_from_lambda_context(lambda_context)
347
401
 
348
402
 
@@ -353,22 +407,190 @@ def _extract_context_from_eventbridge_sqs_event(event):
353
407
 
354
408
  This is only possible if first record in `Records` contains a
355
409
  `body` field which contains the EventBridge `detail` as a JSON string.
410
+
411
+ Returns a tuple ``(context, is_eventbridge_sqs, dsm_handled)``:
412
+
413
+ * ``context`` / ``is_eventbridge_sqs`` describe the trace context and are
414
+ derived only from the first record, since that is the record whose trace
415
+ context becomes the Lambda's parent.
416
+ * ``dsm_handled`` reports whether this function already set DSM checkpoints
417
+ for the batch. It is ``True`` whenever *any* record in the batch is an
418
+ EventBridge delivery, so the caller must not set its own SQS checkpoint
419
+ (which would double count the first record).
356
420
  """
357
- first_record = event.get("Records")[0]
358
- body_str = first_record.get("body")
359
- body = json.loads(body_str)
360
- detail = body.get("detail")
361
- dd_context = detail.get("_datadog")
421
+ records = event.get("Records")
422
+ if not records:
423
+ return None, False, False
424
+
425
+ first_record = records[0]
426
+ dd_context, is_eventbridge_sqs = _extract_eventbridge_sqs_record_context(
427
+ first_record
428
+ )
429
+
430
+ # Set a consume checkpoint for every record in the batch whenever the batch
431
+ # contains at least one EventBridge delivery. Each record is classified
432
+ # independently so a mixed batch (EventBridge deliveries alongside direct
433
+ # SQS sends, in either order) uses the correct carrier per record. The
434
+ # message is consumed from the SQS queue, so it follows SQS conventions
435
+ # (type:sqs, topic:queue ARN).
436
+ dsm_handled = _dsm_set_eventbridge_sqs_batch_checkpoints(records)
437
+
438
+ if not is_eventbridge_sqs:
439
+ return None, False, dsm_handled
362
440
 
363
441
  if is_step_function_event(dd_context):
364
442
  try:
365
- return extract_context_from_step_functions(dd_context, None)
443
+ return (
444
+ extract_context_from_step_functions(dd_context, None),
445
+ True,
446
+ dsm_handled,
447
+ )
366
448
  except Exception:
367
449
  logger.debug(
368
450
  "Failed to extract Step Functions context from EventBridge to SQS event."
369
451
  )
370
452
 
371
- return propagator.extract(dd_context)
453
+ return propagator.extract(dd_context), True, dsm_handled
454
+
455
+
456
+ def _dsm_set_eventbridge_sqs_batch_checkpoints(records):
457
+ """Set a per-record SQS DSM consume checkpoint for an EventBridge -> SQS
458
+ batch.
459
+
460
+ Returns ``True`` when the batch contains at least one EventBridge delivery
461
+ (and checkpoints were therefore this function's responsibility), otherwise
462
+ ``False`` so the caller can fall back to its regular SQS checkpoint path.
463
+ Each record is classified independently: EventBridge records use the
464
+ carrier embedded in ``body.detail._datadog`` while other records fall back
465
+ to the SQS ``messageAttributes._datadog`` carrier.
466
+ """
467
+ if not config.data_streams_enabled:
468
+ return False
469
+
470
+ record_carriers = []
471
+ batch_has_eventbridge = False
472
+ for record in records:
473
+ record_context, is_eventbridge_record = _extract_eventbridge_sqs_record_context(
474
+ record
475
+ )
476
+ if is_eventbridge_record:
477
+ batch_has_eventbridge = True
478
+ else:
479
+ try:
480
+ record_context = _extract_sqs_record_message_attribute_context(record)
481
+ except Exception:
482
+ record_context = None
483
+ record_carriers.append(record_context)
484
+
485
+ if not batch_has_eventbridge:
486
+ return False
487
+
488
+ for record, record_context in zip(records, record_carriers):
489
+ try:
490
+ _dsm_set_checkpoint(record_context, "sqs", record.get("eventSourceARN", ""))
491
+ except Exception:
492
+ logger.debug(
493
+ "Failed to set DSM checkpoint for an EventBridge to SQS record."
494
+ )
495
+
496
+ return True
497
+
498
+
499
+ def _extract_eventbridge_sqs_record_context(record):
500
+ """Classify a single SQS record as an EventBridge delivery and return its
501
+ DSM carrier.
502
+
503
+ Returns a tuple ``(dd_context, is_eventbridge)``. A record is only treated
504
+ as EventBridge when its ``body`` is a JSON object carrying the EventBridge
505
+ envelope fields (``detail`` object plus ``detail-type`` and ``source``). A
506
+ non-JSON or non-envelope body is not an error here: it simply means the
507
+ record is a regular SQS message, so the caller can fall back to the SQS
508
+ message attribute carrier instead.
509
+ """
510
+ body_str = record.get("body")
511
+ try:
512
+ body = json.loads(body_str)
513
+ except (ValueError, TypeError):
514
+ return None, False
515
+
516
+ if not isinstance(body, dict):
517
+ return None, False
518
+
519
+ detail = body.get("detail")
520
+ if not (
521
+ isinstance(detail, dict) and body.get("detail-type") and body.get("source")
522
+ ):
523
+ return None, False
524
+
525
+ return detail.get("_datadog"), True
526
+
527
+
528
+ def _extract_sqs_record_message_attribute_context(record):
529
+ """Return the ``_datadog`` carrier for a non-EventBridge SQS record.
530
+
531
+ A record in an SQS batch may itself be an SNS notification (an SNS => SQS
532
+ subscription without raw message delivery), in which case the attributes
533
+ live in the SNS envelope inside ``body`` rather than in the record's own
534
+ ``messageAttributes``. Both shapes are handled here so that a mixed batch
535
+ (EventBridge deliveries alongside SNS deliveries on the same queue) does
536
+ not lose the SNS DSM context.
537
+ """
538
+ msg_attributes = record.get("messageAttributes")
539
+
540
+ if not msg_attributes:
541
+ sns_record = _parse_sns_notification_from_sqs_body(record) or {}
542
+ msg_attributes = sns_record.get("MessageAttributes") or {}
543
+
544
+ return _decode_dd_message_attribute(msg_attributes.get("_datadog"))
545
+
546
+
547
+ def _parse_sns_notification_from_sqs_body(record):
548
+ """Return the SNS envelope carried in an SQS record's ``body``, if any.
549
+
550
+ Returns ``None`` when the body is not an SNS notification, which simply
551
+ means the record is a direct SQS send.
552
+ """
553
+ try:
554
+ body = json.loads(record.get("body"))
555
+ except (ValueError, TypeError):
556
+ return None
557
+
558
+ if (
559
+ isinstance(body, dict)
560
+ and body.get("Type", "") == "Notification"
561
+ and "TopicArn" in body
562
+ ):
563
+ return body
564
+
565
+ return None
566
+
567
+
568
+ def _decode_dd_message_attribute(dd_payload):
569
+ """Decode a ``_datadog`` SQS/SNS message attribute into a carrier dict.
570
+
571
+ SQS uses ``dataType`` with ``stringValue``/``binaryValue`` while SNS uses
572
+ ``Type`` with ``Value``; both are supported.
573
+ """
574
+ if not dd_payload:
575
+ return None
576
+
577
+ dd_json_data = None
578
+ dd_json_data_type = dd_payload.get("Type") or dd_payload.get("dataType")
579
+ if dd_json_data_type == "Binary":
580
+ import base64
581
+
582
+ dd_json_data = dd_payload.get("binaryValue") or dd_payload.get("Value")
583
+ if dd_json_data:
584
+ dd_json_data = base64.b64decode(dd_json_data)
585
+ elif dd_json_data_type == "String":
586
+ dd_json_data = dd_payload.get("stringValue") or dd_payload.get("Value")
587
+ else:
588
+ logger.debug(
589
+ "Datadog Lambda Python only supports extracting trace"
590
+ "context from String or Binary SQS/SNS message attributes"
591
+ )
592
+
593
+ return json.loads(dd_json_data) if dd_json_data else None
372
594
 
373
595
 
374
596
  def extract_context_from_eventbridge_event(event, lambda_context):
@@ -380,8 +602,11 @@ def extract_context_from_eventbridge_event(event, lambda_context):
380
602
  that header.
381
603
  """
382
604
  try:
383
- detail = event.get("detail")
605
+ detail = event.get("detail") or {}
384
606
  dd_context = detail.get("_datadog")
607
+
608
+ _dsm_set_eventbridge_checkpoint(dd_context, event.get("detail-type"))
609
+
385
610
  if not dd_context:
386
611
  return extract_context_from_lambda_context(lambda_context)
387
612
 
@@ -906,11 +1131,14 @@ def determine_service_name(
906
1131
  if mapped_service:
907
1132
  return mapped_service
908
1133
 
1134
+ # When integration service names are removed, inferred (synthetic) spans use
1135
+ # the base service name (DD_SERVICE) instead of the AWS resource/instance
1136
+ # representation.
1137
+ if config.remove_integration_service_names_enabled and config.service:
1138
+ return config.service
1139
+
909
1140
  # Check if AWS service representation is disabled
910
- aws_service_representation = os.environ.get(
911
- "DD_TRACE_AWS_SERVICE_REPRESENTATION_ENABLED", ""
912
- ).lower()
913
- if aws_service_representation in ("false", "0"):
1141
+ if not config.aws_service_representation_enabled:
914
1142
  return fallback
915
1143
 
916
1144
  # Use extracted_key if it exists and is not empty, otherwise use fallback
@@ -0,0 +1 @@
1
+ __version__ = "8.129.0"
@@ -1,6 +1,6 @@
1
1
  [tool.poetry]
2
2
  name = "datadog_lambda"
3
- version = "8.127.0"
3
+ version = "8.129.0"
4
4
  description = "The Datadog AWS Lambda Library"
5
5
  authors = ["Datadog, Inc. <dev@datadoghq.com>"]
6
6
  license = "Apache-2.0"
@@ -28,7 +28,7 @@ classifiers = [
28
28
  [tool.poetry.dependencies]
29
29
  python = ">=3.8.0,<3.15"
30
30
  datadog = ">=0.51.0,<1.0.0"
31
- wrapt = "^1.11.2"
31
+ wrapt = ">=1.11.2,!=2.2.0,<3"
32
32
  ddtrace = [
33
33
  {version = ">=3.19.1,<4", python = ">=3.8,<3.10"},
34
34
  {version = ">=4.1.1,<5,!=4.6.*", python = ">=3.10"}
@@ -1 +0,0 @@
1
- __version__ = "8.127.0"