datadog_lambda 6.110.0__py3-none-any.whl → 7.112.0__py3-none-any.whl

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/tracing.py CHANGED
@@ -32,6 +32,8 @@ from ddtrace import patch
32
32
  from ddtrace import __version__ as ddtrace_version
33
33
  from ddtrace.propagation.http import HTTPPropagator
34
34
  from ddtrace.trace import Context, Span, tracer
35
+
36
+ from datadog_lambda.config import config
35
37
  from datadog_lambda import __version__ as datadog_lambda_version
36
38
  from datadog_lambda.trigger import (
37
39
  _EventSource,
@@ -42,10 +44,7 @@ from datadog_lambda.trigger import (
42
44
  EventSubtypes,
43
45
  )
44
46
 
45
- dd_trace_otel_enabled = (
46
- os.environ.get("DD_TRACE_OTEL_ENABLED", "false").lower() == "true"
47
- )
48
- if dd_trace_otel_enabled:
47
+ if config.otel_enabled:
49
48
  from opentelemetry.trace import set_tracer_provider
50
49
  from ddtrace.opentelemetry import TracerProvider
51
50
 
@@ -55,18 +54,11 @@ if dd_trace_otel_enabled:
55
54
  logger = logging.getLogger(__name__)
56
55
 
57
56
  dd_trace_context = None
58
- dd_tracing_enabled = os.environ.get("DD_TRACE_ENABLED", "false").lower() == "true"
59
- if dd_tracing_enabled:
57
+ if config.telemetry_enabled:
60
58
  # Enable the telemetry client if the user has opted in
61
- if (
62
- os.environ.get("DD_INSTRUMENTATION_TELEMETRY_ENABLED", "false").lower()
63
- == "true"
64
- ):
65
- from ddtrace.internal.telemetry import telemetry_writer
59
+ from ddtrace.internal.telemetry import telemetry_writer
66
60
 
67
- telemetry_writer.enable()
68
-
69
- is_lambda_context = os.environ.get(XrayDaemon.FUNCTION_NAME_HEADER_NAME) != ""
61
+ telemetry_writer.enable()
70
62
 
71
63
  propagator = HTTPPropagator()
72
64
 
@@ -75,6 +67,24 @@ HIGHER_64_BITS = "HIGHER_64_BITS"
75
67
  LOWER_64_BITS = "LOWER_64_BITS"
76
68
 
77
69
 
70
+ def _dsm_set_checkpoint(context_json, event_type, arn):
71
+ if not config.data_streams_enabled:
72
+ return
73
+
74
+ if not arn:
75
+ return
76
+
77
+ try:
78
+ from ddtrace.data_streams import set_consume_checkpoint
79
+
80
+ carrier_get = lambda k: context_json and context_json.get(k) # noqa: E731
81
+ set_consume_checkpoint(event_type, arn, carrier_get, manual_checkpoint=False)
82
+ except Exception as e:
83
+ logger.debug(
84
+ f"DSM:Failed to set consume checkpoint for {event_type} {arn}: {e}"
85
+ )
86
+
87
+
78
88
  def _convert_xray_trace_id(xray_trace_id):
79
89
  """
80
90
  Convert X-Ray trace id (hex)'s last 63 bits to a Datadog trace id (int).
@@ -97,7 +107,7 @@ def _convert_xray_sampling(xray_sampled):
97
107
 
98
108
 
99
109
  def _get_xray_trace_context():
100
- if not is_lambda_context:
110
+ if not config.is_lambda_context:
101
111
  return None
102
112
 
103
113
  xray_trace_entity = parse_xray_header(
@@ -210,7 +220,9 @@ def create_sns_event(message):
210
220
  }
211
221
 
212
222
 
213
- def extract_context_from_sqs_or_sns_event_or_context(event, lambda_context):
223
+ def extract_context_from_sqs_or_sns_event_or_context(
224
+ event, lambda_context, event_source
225
+ ):
214
226
  """
215
227
  Extract Datadog trace context from an SQS event.
216
228
 
@@ -222,7 +234,10 @@ def extract_context_from_sqs_or_sns_event_or_context(event, lambda_context):
222
234
  Lambda Context.
223
235
 
224
236
  Falls back to lambda context if no trace data is found in the SQS message attributes.
237
+ Set a DSM checkpoint if DSM is enabled and the method for context propagation is supported.
225
238
  """
239
+ source_arn = ""
240
+ event_type = "sqs" if event_source.equals(EventTypes.SQS) else "sns"
226
241
 
227
242
  # EventBridge => SQS
228
243
  try:
@@ -234,6 +249,7 @@ def extract_context_from_sqs_or_sns_event_or_context(event, lambda_context):
234
249
 
235
250
  try:
236
251
  first_record = event.get("Records")[0]
252
+ source_arn = first_record.get("eventSourceARN", "")
237
253
 
238
254
  # logic to deal with SNS => SQS event
239
255
  if "body" in first_record:
@@ -249,6 +265,9 @@ def extract_context_from_sqs_or_sns_event_or_context(event, lambda_context):
249
265
  msg_attributes = first_record.get("messageAttributes")
250
266
  if msg_attributes is None:
251
267
  sns_record = first_record.get("Sns") or {}
268
+ # SNS->SQS event would extract SNS arn without this check
269
+ if event_source.equals(EventTypes.SNS):
270
+ source_arn = sns_record.get("TopicArn", "")
252
271
  msg_attributes = sns_record.get("MessageAttributes") or {}
253
272
  dd_payload = msg_attributes.get("_datadog")
254
273
  if dd_payload:
@@ -280,8 +299,9 @@ def extract_context_from_sqs_or_sns_event_or_context(event, lambda_context):
280
299
  logger.debug(
281
300
  "Failed to extract Step Functions context from SQS/SNS event."
282
301
  )
283
-
284
- return propagator.extract(dd_data)
302
+ context = propagator.extract(dd_data)
303
+ _dsm_set_checkpoint(dd_data, event_type, source_arn)
304
+ return context
285
305
  else:
286
306
  # Handle case where trace context is injected into attributes.AWSTraceHeader
287
307
  # example: Root=1-654321ab-000000001234567890abcdef;Parent=0123456789abcdef;Sampled=1
@@ -304,9 +324,13 @@ def extract_context_from_sqs_or_sns_event_or_context(event, lambda_context):
304
324
  span_id=int(x_ray_context["parent_id"], 16),
305
325
  sampling_priority=float(x_ray_context["sampled"]),
306
326
  )
327
+ # Still want to set a DSM checkpoint even if DSM context not propagated
328
+ _dsm_set_checkpoint(None, event_type, source_arn)
307
329
  return extract_context_from_lambda_context(lambda_context)
308
330
  except Exception as e:
309
331
  logger.debug("The trace extractor returned with error %s", e)
332
+ # Still want to set a DSM checkpoint even if DSM context not propagated
333
+ _dsm_set_checkpoint(None, event_type, source_arn)
310
334
  return extract_context_from_lambda_context(lambda_context)
311
335
 
312
336
 
@@ -365,9 +389,12 @@ def extract_context_from_eventbridge_event(event, lambda_context):
365
389
  def extract_context_from_kinesis_event(event, lambda_context):
366
390
  """
367
391
  Extract datadog trace context from a Kinesis Stream's base64 encoded data string
392
+ Set a DSM checkpoint if DSM is enabled and the method for context propagation is supported.
368
393
  """
394
+ source_arn = ""
369
395
  try:
370
396
  record = get_first_record(event)
397
+ source_arn = record.get("eventSourceARN", "")
371
398
  kinesis = record.get("kinesis")
372
399
  if not kinesis:
373
400
  return extract_context_from_lambda_context(lambda_context)
@@ -381,10 +408,13 @@ def extract_context_from_kinesis_event(event, lambda_context):
381
408
  data_obj = json.loads(data_str)
382
409
  dd_ctx = data_obj.get("_datadog")
383
410
  if dd_ctx:
384
- return propagator.extract(dd_ctx)
411
+ context = propagator.extract(dd_ctx)
412
+ _dsm_set_checkpoint(dd_ctx, "kinesis", source_arn)
413
+ return context
385
414
  except Exception as e:
386
415
  logger.debug("The trace extractor returned with error %s", e)
387
-
416
+ # Still want to set a DSM checkpoint even if DSM context not propagated
417
+ _dsm_set_checkpoint(None, "kinesis", source_arn)
388
418
  return extract_context_from_lambda_context(lambda_context)
389
419
 
390
420
 
@@ -602,7 +632,7 @@ def extract_dd_trace_context(
602
632
  )
603
633
  elif event_source.equals(EventTypes.SNS) or event_source.equals(EventTypes.SQS):
604
634
  context = extract_context_from_sqs_or_sns_event_or_context(
605
- event, lambda_context
635
+ event, lambda_context, event_source
606
636
  )
607
637
  elif event_source.equals(EventTypes.EVENTBRIDGE):
608
638
  context = extract_context_from_eventbridge_event(event, lambda_context)
@@ -639,13 +669,11 @@ def get_dd_trace_context_obj():
639
669
  automatically, but this function can be used to manually inject the trace
640
670
  context to an outgoing request.
641
671
  """
642
- if dd_tracing_enabled:
672
+ if config.trace_enabled:
643
673
  dd_trace_py_context = _get_dd_trace_py_context()
644
674
  if _is_context_complete(dd_trace_py_context):
645
675
  return dd_trace_py_context
646
676
 
647
- global dd_trace_context
648
-
649
677
  try:
650
678
  xray_context = _get_xray_trace_context() # xray (sub)segment
651
679
  except Exception as e:
@@ -690,10 +718,10 @@ def set_correlation_ids():
690
718
 
691
719
  TODO: Remove me when Datadog tracer is natively supported in Lambda.
692
720
  """
693
- if not is_lambda_context:
721
+ if not config.is_lambda_context:
694
722
  logger.debug("set_correlation_ids is only supported in LambdaContext")
695
723
  return
696
- if dd_tracing_enabled:
724
+ if config.trace_enabled:
697
725
  logger.debug("using ddtrace implementation for spans")
698
726
  return
699
727
 
@@ -850,13 +878,14 @@ def create_inferred_span_from_lambda_function_url_event(event, context):
850
878
  http = request_context.get("http")
851
879
  method = http.get("method") if http else None
852
880
  path = http.get("path") if http else None
881
+ http_url = f"https://{domain}{path}"
853
882
  resource = f"{method} {path}"
854
883
  tags = {
855
884
  "operation_name": "aws.lambda.url",
856
- "http.url": domain + path,
885
+ "http.url": http_url,
857
886
  "endpoint": path,
858
887
  "http.method": method,
859
- "resource_names": domain + path,
888
+ "resource_names": resource,
860
889
  "request_id": context.aws_request_id,
861
890
  }
862
891
  request_time_epoch = request_context.get("timeEpoch")
@@ -868,7 +897,7 @@ def create_inferred_span_from_lambda_function_url_event(event, context):
868
897
  InferredSpanInfo.set_tags(tags, tag_source="self", synchronicity="sync")
869
898
  if span:
870
899
  span.set_tags(tags)
871
- span.start_ns = int(request_time_epoch) * 1e6
900
+ span.start_ns = int(request_time_epoch * 1e6)
872
901
  return span
873
902
 
874
903
 
@@ -948,6 +977,7 @@ def create_inferred_span_from_api_gateway_websocket_event(
948
977
  request_context = event.get("requestContext")
949
978
  domain = request_context.get("domainName")
950
979
  endpoint = request_context.get("routeKey")
980
+ http_url = f"https://{domain}{endpoint}"
951
981
  api_id = request_context.get("apiId")
952
982
 
953
983
  service_name = determine_service_name(
@@ -955,7 +985,7 @@ def create_inferred_span_from_api_gateway_websocket_event(
955
985
  )
956
986
  tags = {
957
987
  "operation_name": "aws.apigateway.websocket",
958
- "http.url": domain + endpoint,
988
+ "http.url": http_url,
959
989
  "endpoint": endpoint,
960
990
  "resource_names": endpoint,
961
991
  "apiid": api_id,
@@ -1007,11 +1037,12 @@ def create_inferred_span_from_api_gateway_event(
1007
1037
  )
1008
1038
  method = event.get("httpMethod")
1009
1039
  path = event.get("path")
1040
+ http_url = f"https://{domain}{path}"
1010
1041
  resource_path = _get_resource_path(event, request_context)
1011
1042
  resource = f"{method} {resource_path}"
1012
1043
  tags = {
1013
1044
  "operation_name": "aws.apigateway.rest",
1014
- "http.url": domain + path,
1045
+ "http.url": http_url,
1015
1046
  "endpoint": path,
1016
1047
  "http.method": method,
1017
1048
  "resource_names": resource,
@@ -1073,12 +1104,13 @@ def create_inferred_span_from_http_api_event(
1073
1104
  http = request_context.get("http") or {}
1074
1105
  method = http.get("method")
1075
1106
  path = event.get("rawPath")
1107
+ http_url = f"https://{domain}{path}"
1076
1108
  resource_path = _get_resource_path(event, request_context)
1077
1109
  resource = f"{method} {resource_path}"
1078
1110
  tags = {
1079
1111
  "operation_name": "aws.httpapi",
1080
1112
  "endpoint": path,
1081
- "http.url": domain + path,
1113
+ "http.url": http_url,
1082
1114
  "http.method": http.get("method"),
1083
1115
  "http.protocol": http.get("protocol"),
1084
1116
  "http.source_ip": http.get("sourceIp"),
@@ -1476,7 +1508,7 @@ def emit_telemetry_on_exception_outside_of_handler(
1476
1508
  Emit an enhanced error metric and create a span for exceptions occurring outside the handler
1477
1509
  """
1478
1510
  submit_errors_metric(None)
1479
- if dd_tracing_enabled:
1511
+ if config.trace_enabled:
1480
1512
  span = tracer.trace(
1481
1513
  "aws.lambda",
1482
1514
  service="aws.lambda",
datadog_lambda/trigger.py CHANGED
@@ -153,7 +153,7 @@ def parse_event_source(event: dict) -> _EventSource:
153
153
  event_source = _EventSource(EventTypes.STEPFUNCTIONS)
154
154
 
155
155
  event_record = get_first_record(event)
156
- if event_record:
156
+ if event_record and isinstance(event_record, dict):
157
157
  aws_event_source = event_record.get("eventSource") or event_record.get(
158
158
  "EventSource"
159
159
  )
@@ -301,7 +301,7 @@ def extract_http_tags(event):
301
301
  if request_context and request_context.get("stage"):
302
302
  domain_name = request_context.get("domainName")
303
303
  if domain_name:
304
- http_tags["http.url"] = domain_name
304
+ http_tags["http.url"] = f"https://{domain_name}"
305
305
 
306
306
  path = request_context.get("path")
307
307
  method = request_context.get("httpMethod")
datadog_lambda/version.py CHANGED
@@ -1 +1 @@
1
- __version__ = "6.110.0"
1
+ __version__ = "7.112.0"
datadog_lambda/wrapper.py CHANGED
@@ -9,6 +9,7 @@ import ujson as json
9
9
  from importlib import import_module
10
10
  from time import time_ns
11
11
 
12
+ from datadog_lambda.asm import asm_set_context, asm_start_response, asm_start_request
12
13
  from datadog_lambda.extension import should_use_extension, flush_extension
13
14
  from datadog_lambda.cold_start import (
14
15
  set_cold_start,
@@ -17,19 +18,19 @@ from datadog_lambda.cold_start import (
17
18
  is_new_sandbox,
18
19
  ColdStartTracer,
19
20
  )
21
+ from datadog_lambda.config import config
20
22
  from datadog_lambda.constants import (
21
23
  TraceContextSource,
22
24
  XraySubsegment,
23
25
  Headers,
24
26
  )
25
27
  from datadog_lambda.module_name import modify_module_name
26
- from datadog_lambda.patch import patch_all
27
28
  from datadog_lambda.span_pointers import calculate_span_pointers
29
+ from datadog_lambda.tag_object import tag_object
28
30
  from datadog_lambda.tracing import (
29
31
  extract_dd_trace_context,
30
32
  create_dd_dummy_metadata_subsegment,
31
33
  inject_correlation_ids,
32
- dd_tracing_enabled,
33
34
  mark_trace_as_error_for_5xx_responses,
34
35
  set_correlation_ids,
35
36
  set_dd_trace_py_root,
@@ -45,64 +46,20 @@ from datadog_lambda.trigger import (
45
46
  extract_http_status_code_tag,
46
47
  )
47
48
 
48
- profiling_env_var = os.environ.get("DD_PROFILING_ENABLED", "false").lower() == "true"
49
- if profiling_env_var:
49
+ if config.profiling_enabled:
50
50
  from ddtrace.profiling import profiler
51
51
 
52
- llmobs_env_var = os.environ.get("DD_LLMOBS_ENABLED", "false").lower() in ("true", "1")
53
- if llmobs_env_var:
52
+ if config.llmobs_enabled:
54
53
  from ddtrace.llmobs import LLMObs
55
54
 
56
- exception_replay_env_var = os.environ.get(
57
- "DD_EXCEPTION_REPLAY_ENABLED", "false"
58
- ).lower() in ("true", "1")
59
- if exception_replay_env_var:
55
+ if config.exception_replay_enabled:
60
56
  from ddtrace.debugging._exception.replay import SpanExceptionHandler
61
57
  from ddtrace.debugging._uploader import LogsIntakeUploaderV1
62
58
 
63
59
  logger = logging.getLogger(__name__)
64
60
 
65
- DD_FLUSH_TO_LOG = "DD_FLUSH_TO_LOG"
66
- DD_LOGS_INJECTION = "DD_LOGS_INJECTION"
67
- DD_MERGE_XRAY_TRACES = "DD_MERGE_XRAY_TRACES"
68
- AWS_LAMBDA_FUNCTION_NAME = "AWS_LAMBDA_FUNCTION_NAME"
69
- DD_LOCAL_TEST = "DD_LOCAL_TEST"
70
- DD_TRACE_EXTRACTOR = "DD_TRACE_EXTRACTOR"
71
- DD_TRACE_MANAGED_SERVICES = "DD_TRACE_MANAGED_SERVICES"
72
- DD_ENCODE_AUTHORIZER_CONTEXT = "DD_ENCODE_AUTHORIZER_CONTEXT"
73
- DD_DECODE_AUTHORIZER_CONTEXT = "DD_DECODE_AUTHORIZER_CONTEXT"
74
- DD_COLD_START_TRACING = "DD_COLD_START_TRACING"
75
- DD_MIN_COLD_START_DURATION = "DD_MIN_COLD_START_DURATION"
76
- DD_COLD_START_TRACE_SKIP_LIB = "DD_COLD_START_TRACE_SKIP_LIB"
77
- DD_CAPTURE_LAMBDA_PAYLOAD = "DD_CAPTURE_LAMBDA_PAYLOAD"
78
- DD_CAPTURE_LAMBDA_PAYLOAD_MAX_DEPTH = "DD_CAPTURE_LAMBDA_PAYLOAD_MAX_DEPTH"
79
61
  DD_REQUESTS_SERVICE_NAME = "DD_REQUESTS_SERVICE_NAME"
80
62
  DD_SERVICE = "DD_SERVICE"
81
- DD_ENV = "DD_ENV"
82
-
83
-
84
- def get_env_as_int(env_key, default_value: int) -> int:
85
- try:
86
- return int(os.environ.get(env_key, default_value))
87
- except Exception as e:
88
- logger.warn(
89
- f"Failed to parse {env_key} as int. Using default value: {default_value}. Error: {e}"
90
- )
91
- return default_value
92
-
93
-
94
- dd_capture_lambda_payload_enabled = (
95
- os.environ.get(DD_CAPTURE_LAMBDA_PAYLOAD, "false").lower() == "true"
96
- )
97
-
98
- if dd_capture_lambda_payload_enabled:
99
- import datadog_lambda.tag_object as tag_object
100
-
101
- tag_object.max_depth = get_env_as_int(
102
- DD_CAPTURE_LAMBDA_PAYLOAD_MAX_DEPTH, tag_object.max_depth
103
- )
104
-
105
- env_env_var = os.environ.get(DD_ENV, None)
106
63
 
107
64
  init_timestamp_ns = time_ns()
108
65
 
@@ -159,56 +116,16 @@ class _LambdaDecorator(object):
159
116
  """Executes when the wrapped function gets wrapped"""
160
117
  try:
161
118
  self.func = func
162
- self.flush_to_log = os.environ.get(DD_FLUSH_TO_LOG, "").lower() == "true"
163
- self.logs_injection = (
164
- os.environ.get(DD_LOGS_INJECTION, "true").lower() == "true"
165
- )
166
- self.merge_xray_traces = (
167
- os.environ.get(DD_MERGE_XRAY_TRACES, "false").lower() == "true"
168
- )
169
- self.function_name = os.environ.get(AWS_LAMBDA_FUNCTION_NAME, "function")
170
- self.service = os.environ.get(DD_SERVICE, None)
171
- self.extractor_env = os.environ.get(DD_TRACE_EXTRACTOR, None)
172
119
  self.trace_extractor = None
173
120
  self.span = None
174
121
  self.inferred_span = None
175
- depends_on_dd_tracing_enabled = (
176
- lambda original_boolean: dd_tracing_enabled and original_boolean
177
- )
178
- self.make_inferred_span = depends_on_dd_tracing_enabled(
179
- os.environ.get(DD_TRACE_MANAGED_SERVICES, "true").lower() == "true"
180
- )
181
- self.encode_authorizer_context = depends_on_dd_tracing_enabled(
182
- os.environ.get(DD_ENCODE_AUTHORIZER_CONTEXT, "true").lower() == "true"
183
- )
184
- self.decode_authorizer_context = depends_on_dd_tracing_enabled(
185
- os.environ.get(DD_DECODE_AUTHORIZER_CONTEXT, "true").lower() == "true"
186
- )
187
- self.cold_start_tracing = depends_on_dd_tracing_enabled(
188
- os.environ.get(DD_COLD_START_TRACING, "true").lower() == "true"
189
- )
190
- self.min_cold_start_trace_duration = get_env_as_int(
191
- DD_MIN_COLD_START_DURATION, 3
192
- )
193
- self.local_testing_mode = os.environ.get(
194
- DD_LOCAL_TEST, "false"
195
- ).lower() in ("true", "1")
196
- self.cold_start_trace_skip_lib = [
197
- "ddtrace.internal.compat",
198
- "ddtrace.filters",
199
- ]
200
- if DD_COLD_START_TRACE_SKIP_LIB in os.environ:
201
- try:
202
- self.cold_start_trace_skip_lib = os.environ[
203
- DD_COLD_START_TRACE_SKIP_LIB
204
- ].split(",")
205
- except Exception:
206
- logger.debug(f"Malformatted for env {DD_COLD_START_TRACE_SKIP_LIB}")
207
122
  self.response = None
208
- if profiling_env_var:
209
- self.prof = profiler.Profiler(env=env_env_var, service=self.service)
210
- if self.extractor_env:
211
- extractor_parts = self.extractor_env.rsplit(".", 1)
123
+
124
+ if config.profiling_enabled:
125
+ self.prof = profiler.Profiler(env=config.env, service=config.service)
126
+
127
+ if config.trace_extractor:
128
+ extractor_parts = config.trace_extractor.rsplit(".", 1)
212
129
  if len(extractor_parts) == 2:
213
130
  (mod_name, extractor_name) = extractor_parts
214
131
  modified_extractor_name = modify_module_name(mod_name)
@@ -216,7 +133,7 @@ class _LambdaDecorator(object):
216
133
  self.trace_extractor = getattr(extractor_module, extractor_name)
217
134
 
218
135
  # Inject trace correlation ids to logs
219
- if self.logs_injection:
136
+ if config.logs_injection:
220
137
  inject_correlation_ids()
221
138
 
222
139
  # This prevents a breaking change in ddtrace v0.49 regarding the service name
@@ -224,15 +141,13 @@ class _LambdaDecorator(object):
224
141
  os.environ[DD_REQUESTS_SERVICE_NAME] = os.environ.get(
225
142
  DD_SERVICE, "aws.lambda"
226
143
  )
227
- # Patch third-party libraries for tracing
228
- patch_all()
229
144
 
230
145
  # Enable LLM Observability
231
- if llmobs_env_var:
146
+ if config.llmobs_enabled:
232
147
  LLMObs.enable()
233
148
 
234
149
  # Enable Exception Replay
235
- if exception_replay_env_var:
150
+ if config.exception_replay_enabled:
236
151
  logger.debug("Enabling exception replay")
237
152
  SpanExceptionHandler.enable()
238
153
 
@@ -247,10 +162,9 @@ class _LambdaDecorator(object):
247
162
  self.response = self.func(event, context, **kwargs)
248
163
  return self.response
249
164
  except Exception:
250
- if not should_use_extension:
251
- from datadog_lambda.metric import submit_errors_metric
165
+ from datadog_lambda.metric import submit_errors_metric
252
166
 
253
- submit_errors_metric(context)
167
+ submit_errors_metric(context)
254
168
 
255
169
  if self.span:
256
170
  self.span.set_traceback()
@@ -302,7 +216,7 @@ class _LambdaDecorator(object):
302
216
  event,
303
217
  context,
304
218
  extractor=self.trace_extractor,
305
- decode_authorizer_context=self.decode_authorizer_context,
219
+ decode_authorizer_context=config.decode_authorizer_context,
306
220
  )
307
221
  self.event_source = event_source
308
222
  # Create a Datadog X-Ray subsegment with the trace context
@@ -316,26 +230,32 @@ class _LambdaDecorator(object):
316
230
  XraySubsegment.TRACE_KEY,
317
231
  )
318
232
 
319
- if dd_tracing_enabled:
320
- set_dd_trace_py_root(trace_context_source, self.merge_xray_traces)
321
- if self.make_inferred_span:
233
+ if config.trace_enabled:
234
+ set_dd_trace_py_root(trace_context_source, config.merge_xray_traces)
235
+ if config.make_inferred_span:
322
236
  self.inferred_span = create_inferred_span(
323
- event, context, event_source, self.decode_authorizer_context
237
+ event, context, event_source, config.decode_authorizer_context
324
238
  )
239
+
240
+ if config.appsec_enabled:
241
+ asm_set_context(event_source)
242
+
325
243
  self.span = create_function_execution_span(
326
244
  context=context,
327
- function_name=self.function_name,
245
+ function_name=config.function_name,
328
246
  is_cold_start=is_cold_start(),
329
247
  is_proactive_init=is_proactive_init(),
330
248
  trace_context_source=trace_context_source,
331
- merge_xray_traces=self.merge_xray_traces,
249
+ merge_xray_traces=config.merge_xray_traces,
332
250
  trigger_tags=self.trigger_tags,
333
251
  parent_span=self.inferred_span,
334
252
  span_pointers=calculate_span_pointers(event_source, event),
335
253
  )
254
+ if config.appsec_enabled:
255
+ asm_start_request(self.span, event, event_source, self.trigger_tags)
336
256
  else:
337
257
  set_correlation_ids()
338
- if profiling_env_var and is_new_sandbox():
258
+ if config.profiling_enabled and is_new_sandbox():
339
259
  self.prof.start(stop_on_exit=False, profile_children=True)
340
260
  logger.debug("datadog_lambda_wrapper _before() done")
341
261
  except Exception as e:
@@ -354,25 +274,34 @@ class _LambdaDecorator(object):
354
274
  create_dd_dummy_metadata_subsegment(
355
275
  self.trigger_tags, XraySubsegment.LAMBDA_FUNCTION_TAGS_KEY
356
276
  )
357
- should_trace_cold_start = self.cold_start_tracing and is_new_sandbox()
277
+ should_trace_cold_start = config.cold_start_tracing and is_new_sandbox()
358
278
  if should_trace_cold_start:
359
279
  trace_ctx = tracer.current_trace_context()
360
280
 
361
281
  if self.span:
362
- if dd_capture_lambda_payload_enabled:
363
- tag_object.tag_object(self.span, "function.request", event)
364
- tag_object.tag_object(self.span, "function.response", self.response)
282
+ if config.capture_payload_enabled:
283
+ tag_object(self.span, "function.request", event)
284
+ tag_object(self.span, "function.response", self.response)
365
285
 
366
286
  if status_code:
367
287
  self.span.set_tag("http.status_code", status_code)
288
+
289
+ if config.appsec_enabled:
290
+ asm_start_response(
291
+ self.span,
292
+ status_code,
293
+ self.event_source,
294
+ response=self.response,
295
+ )
296
+
368
297
  self.span.finish()
369
298
 
370
299
  if self.inferred_span:
371
300
  if status_code:
372
301
  self.inferred_span.set_tag("http.status_code", status_code)
373
302
 
374
- if self.service:
375
- self.inferred_span.set_tag("peer.service", self.service)
303
+ if config.service:
304
+ self.inferred_span.set_tag("peer.service", config.service)
376
305
 
377
306
  if InferredSpanInfo.is_async(self.inferred_span) and self.span:
378
307
  self.inferred_span.finish(finish_time=self.span.start)
@@ -384,33 +313,35 @@ class _LambdaDecorator(object):
384
313
  following_span = self.span or self.inferred_span
385
314
  ColdStartTracer(
386
315
  tracer,
387
- self.function_name,
316
+ config.function_name,
388
317
  following_span.start_ns,
389
318
  trace_ctx,
390
- self.min_cold_start_trace_duration,
391
- self.cold_start_trace_skip_lib,
319
+ config.min_cold_start_trace_duration,
320
+ config.cold_start_trace_skip_lib,
392
321
  ).trace()
393
322
  except Exception as e:
394
323
  logger.debug("Failed to create cold start spans. %s", e)
395
324
 
396
- if not self.flush_to_log or should_use_extension:
325
+ if not config.flush_to_log or should_use_extension:
397
326
  from datadog_lambda.metric import flush_stats
398
327
 
399
328
  flush_stats(context)
400
- if should_use_extension and self.local_testing_mode:
329
+ if should_use_extension and config.local_test:
401
330
  # when testing locally, the extension does not know when an
402
331
  # invocation completes because it does not have access to the
403
332
  # logs api
404
333
  flush_extension()
405
334
 
406
- if llmobs_env_var:
335
+ if config.llmobs_enabled:
407
336
  LLMObs.flush()
408
337
 
409
338
  # Flush exception replay
410
- if exception_replay_env_var:
339
+ if config.exception_replay_enabled:
411
340
  LogsIntakeUploaderV1._instance.periodic()
412
341
 
413
- if self.encode_authorizer_context and is_authorizer_response(self.response):
342
+ if config.encode_authorizer_context and is_authorizer_response(
343
+ self.response
344
+ ):
414
345
  self._inject_authorizer_span_headers(
415
346
  event.get("requestContext", {}).get("requestId")
416
347
  )
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: datadog_lambda
3
- Version: 6.110.0
3
+ Version: 7.112.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
@@ -19,7 +19,7 @@ Classifier: Programming Language :: Python :: 3.13
19
19
  Provides-Extra: dev
20
20
  Requires-Dist: botocore (>=1.34.0,<2.0.0) ; extra == "dev"
21
21
  Requires-Dist: datadog (>=0.51.0,<1.0.0)
22
- Requires-Dist: ddtrace (>=2.20.0,<4)
22
+ Requires-Dist: ddtrace (>=3.10.2,<4)
23
23
  Requires-Dist: flake8 (>=5.0.4,<6.0.0) ; extra == "dev"
24
24
  Requires-Dist: pytest (>=8.0.0,<9.0.0) ; extra == "dev"
25
25
  Requires-Dist: pytest-benchmark (>=4.0,<5.0) ; extra == "dev"