Skip to content

Commit 47c0dab

Browse files
committed
emit telemetry and raise during init
1 parent 4297a7c commit 47c0dab

File tree

7 files changed

+41
-76
lines changed

7 files changed

+41
-76
lines changed

datadog_lambda/handler.py

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,8 @@
99
import os
1010
from time import time_ns
1111

12-
from datadog_lambda.wrapper import datadog_lambda_wrapper, error_fallback_handler
12+
from datadog_lambda.tracing import emit_telemetry_on_exception_outside_of_handler
13+
from datadog_lambda.wrapper import datadog_lambda_wrapper
1314
from datadog_lambda.module_name import modify_module_name
1415

1516

@@ -34,8 +35,12 @@ class HandlerError(Exception):
3435
handler_load_start_time_ns = time_ns()
3536
handler_module = import_module(modified_mod_name)
3637
handler_func = getattr(handler_module, handler_name)
37-
handler = datadog_lambda_wrapper(handler_func)
3838
except Exception as e:
39-
handler = error_fallback_handler(
40-
e, modified_mod_name, time_ns() - handler_load_start_time_ns
39+
emit_telemetry_on_exception_outside_of_handler(
40+
e,
41+
modified_mod_name,
42+
handler_load_start_time_ns,
4143
)
44+
raise
45+
46+
handler = datadog_lambda_wrapper(handler_func)

datadog_lambda/tags.py

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -55,9 +55,12 @@ def parse_lambda_tags_from_arn(lambda_context):
5555

5656
def get_enhanced_metrics_tags(lambda_context):
5757
"""Get the list of tags to apply to enhanced metrics"""
58-
tags = parse_lambda_tags_from_arn(lambda_context)
58+
if lambda_context:
59+
tags = parse_lambda_tags_from_arn(lambda_context)
60+
tags.append(f"memorysize:{lambda_context.memory_limit_in_mb}")
61+
else:
62+
tags = []
5963
tags.append(get_cold_start_tag())
60-
tags.append(f"memorysize:{lambda_context.memory_limit_in_mb}")
6164
tags.append(runtime_tag)
6265
tags.append(library_version_tag)
6366
return tags

datadog_lambda/tracing.py

Lines changed: 5 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,6 @@
99
import traceback
1010
import ujson as json
1111
from datetime import datetime, timezone
12-
from time import time_ns
1312
from typing import Optional, Dict
1413

1514
from datadog_lambda.metric import submit_errors_metric
@@ -1325,35 +1324,30 @@ def is_async(span: Span) -> bool:
13251324

13261325

13271326
def emit_telemetry_on_exception_outside_of_handler(
1328-
context, exception, resource_name, handler_load_duration
1327+
exception, resource_name, handler_load_start_time_ns
13291328
):
13301329
"""
1331-
Emit an enhanced error metric and create a span for exceptions occuring outside of the handler
1330+
Emit an enhanced error metric and create a span for exceptions occurring outside the handler
13321331
"""
1333-
submit_errors_metric(context)
1332+
submit_errors_metric(None)
13341333
if dd_tracing_enabled:
13351334
span = tracer.trace(
13361335
"aws.lambda",
13371336
service="aws.lambda",
13381337
resource=resource_name,
13391338
span_type="serverless",
13401339
)
1341-
span.start_ns = time_ns() - handler_load_duration
1340+
span.start_ns = handler_load_start_time_ns
13421341

13431342
tags = {
13441343
"error.status": 500,
13451344
"error.type": type(exception).__name__,
13461345
"error.message": exception,
1347-
"error.stack": "".join(
1348-
traceback.format_exception(
1349-
type(exception), exception, exception.__traceback__
1350-
)
1351-
),
1346+
"error.stack": traceback.format_exc(),
13521347
"resource_names": resource_name,
13531348
"resource.name": resource_name,
13541349
"operation_name": "aws.lambda",
13551350
"status": "error",
1356-
"request_id": context.aws_request_id,
13571351
}
13581352
span.set_tags(tags)
13591353
span.error = 1

datadog_lambda/wrapper.py

Lines changed: 0 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,6 @@
4444
is_authorizer_response,
4545
tracer,
4646
propagator,
47-
emit_telemetry_on_exception_outside_of_handler,
4847
)
4948
from datadog_lambda.trigger import (
5049
extract_trigger_tags,
@@ -383,31 +382,9 @@ def _after(self, event, context):
383382
logger.error(format_err_with_traceback(e))
384383

385384

386-
class _ErrorFallbackHandler(object):
387-
"""
388-
Fallback handler for when an exception occurs outside of the handler function.
389-
Emits telemetry and re-raises the exception.
390-
"""
391-
392-
def __init__(self, exception, modified_mod_name, handler_load_duration_ns):
393-
self.exception = exception
394-
self.modified_mod_name = modified_mod_name
395-
self.handler_load_duration_ns = handler_load_duration_ns
396-
397-
def __call__(self, event, context, **kwargs):
398-
emit_telemetry_on_exception_outside_of_handler(
399-
context,
400-
self.exception,
401-
self.modified_mod_name,
402-
self.handler_load_duration_ns,
403-
)
404-
raise self.exception
405-
406-
407385
def format_err_with_traceback(e):
408386
tb = traceback.format_exc().replace("\n", "\r")
409387
return f"Error {e}. Traceback: {tb}"
410388

411389

412390
datadog_lambda_wrapper = _LambdaDecorator
413-
error_fallback_handler = _ErrorFallbackHandler

tests/test_handler.py

Lines changed: 5 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -30,37 +30,33 @@ def test_dd_lambda_handler_env_var_malformed(self):
3030
)
3131

3232
@patch.dict(os.environ, {"DD_LAMBDA_HANDLER": "nonsense.nonsense"}, clear=True)
33-
@patch("datadog_lambda.wrapper.emit_telemetry_on_exception_outside_of_handler")
33+
@patch("datadog_lambda.tracing.emit_telemetry_on_exception_outside_of_handler")
3434
@patch("time.time_ns", return_value=42)
3535
def test_exception_importing_module(self, mock_time, mock_emit_telemetry):
3636
with self.assertRaises(ModuleNotFoundError) as test_context:
3737
import datadog_lambda.handler
3838

39-
lambda_context = get_mock_context()
40-
datadog_lambda.handler.handler.__call__(None, lambda_context)
4139
mock_emit_telemetry.assert_called_once_with(
42-
lambda_context, test_context.exception, "nonsense", 0
40+
test_context.exception, "nonsense", 42
4341
)
4442

4543
@patch.dict(os.environ, {"DD_LAMBDA_HANDLER": "nonsense.nonsense"}, clear=True)
4644
@patch("importlib.import_module", return_value=None)
47-
@patch("datadog_lambda.wrapper.emit_telemetry_on_exception_outside_of_handler")
45+
@patch("datadog_lambda.tracing.emit_telemetry_on_exception_outside_of_handler")
4846
@patch("time.time_ns", return_value=42)
4947
def test_exception_getting_handler_func(
5048
self, mock_time, mock_emit_telemetry, mock_import
5149
):
5250
with self.assertRaises(AttributeError) as test_context:
5351
import datadog_lambda.handler
5452

55-
lambda_context = get_mock_context()
56-
datadog_lambda.handler.handler.__call__(None, lambda_context)
5753
mock_emit_telemetry.assert_called_once_with(
58-
lambda_context, test_context.exception, "nonsense", 0
54+
test_context.exception, "nonsense", 42
5955
)
6056

6157
@patch.dict(os.environ, {"DD_LAMBDA_HANDLER": "nonsense.nonsense"}, clear=True)
6258
@patch("importlib.import_module")
63-
@patch("datadog_lambda.wrapper.emit_telemetry_on_exception_outside_of_handler")
59+
@patch("datadog_lambda.tracing.emit_telemetry_on_exception_outside_of_handler")
6460
@patch("datadog_lambda.wrapper.datadog_lambda_wrapper")
6561
def test_handler_success(
6662
self, mock_lambda_wrapper, mock_emit_telemetry, mock_import
@@ -72,8 +68,5 @@ def nonsense():
7268

7369
import datadog_lambda.handler
7470

75-
lambda_context = get_mock_context()
76-
datadog_lambda.handler.handler.__call__(None, lambda_context)
77-
7871
mock_emit_telemetry.assert_not_called()
7972
mock_lambda_wrapper.assert_called_once_with(mock_import().nonsense)

tests/test_tracing.py

Lines changed: 8 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -2006,23 +2006,22 @@ def test_deterministic_m5_hash__always_leading_with_zero(self):
20062006
class TestExceptionOutsideHandler(unittest.TestCase):
20072007
@patch("datadog_lambda.tracing.dd_tracing_enabled", True)
20082008
@patch("datadog_lambda.tracing.submit_errors_metric")
2009-
@patch("datadog_lambda.tracing.time_ns", return_value=100)
2009+
@patch("time.time_ns", return_value=42)
20102010
def test_exception_outside_handler_tracing_enabled(
20112011
self, mock_time, mock_submit_errors_metric
20122012
):
20132013
fake_error = ValueError("Some error message")
20142014
resource_name = "my_handler"
20152015
span_type = "aws.lambda"
20162016
mock_span = Mock()
2017-
context = get_mock_context()
20182017
with patch(
20192018
"datadog_lambda.tracing.tracer.trace", return_value=mock_span
20202019
) as mock_trace:
20212020
emit_telemetry_on_exception_outside_of_handler(
2022-
context, fake_error, resource_name, 42
2021+
fake_error, resource_name, 42
20232022
)
20242023

2025-
mock_submit_errors_metric.assert_called_once_with(context)
2024+
mock_submit_errors_metric.assert_called_once_with(None)
20262025

20272026
mock_trace.assert_called_once_with(
20282027
span_type,
@@ -2035,35 +2034,29 @@ def test_exception_outside_handler_tracing_enabled(
20352034
"error.status": 500,
20362035
"error.type": "ValueError",
20372036
"error.message": fake_error,
2038-
"error.stack": "".join(
2039-
traceback.format_exception(
2040-
type(fake_error), fake_error, fake_error.__traceback__
2041-
)
2042-
),
2037+
"error.stack": traceback.format_exc(),
20432038
"resource_names": resource_name,
20442039
"resource.name": resource_name,
20452040
"operation_name": span_type,
20462041
"status": "error",
2047-
"request_id": context.aws_request_id,
20482042
}
20492043
)
20502044
mock_span.finish.assert_called_once()
20512045
assert mock_span.error == 1
2052-
assert mock_span.start_ns == 58
2046+
assert mock_span.start_ns == 42
20532047

20542048
@patch("datadog_lambda.tracing.dd_tracing_enabled", False)
20552049
@patch("datadog_lambda.tracing.submit_errors_metric")
2056-
@patch("datadog_lambda.tracing.time_ns", return_value=100)
2050+
@patch("time.time_ns", return_value=42)
20572051
def test_exception_outside_handler_tracing_disabled(
20582052
self, mock_time, mock_submit_errors_metric
20592053
):
20602054
fake_error = ValueError("Some error message")
20612055
resource_name = "my_handler"
2062-
context = get_mock_context()
20632056
with patch("datadog_lambda.tracing.tracer.trace") as mock_trace:
20642057
emit_telemetry_on_exception_outside_of_handler(
2065-
context, fake_error, resource_name, 42
2058+
fake_error, resource_name, 42
20662059
)
20672060

2068-
mock_submit_errors_metric.assert_called_once_with(context)
2061+
mock_submit_errors_metric.assert_called_once_with(None)
20692062
mock_trace.assert_not_called()

tests/test_wrapper.py

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -220,8 +220,8 @@ def lambda_handler(event, context):
220220
"account_id:123457598159",
221221
"functionname:python-layer-test",
222222
"resource:python-layer-test",
223-
"cold_start:true",
224223
"memorysize:256",
224+
"cold_start:true",
225225
"runtime:python3.9",
226226
"datadog_lambda:v6.6.6",
227227
"dd_lambda_layer:datadog-python39_X.X.X",
@@ -251,8 +251,8 @@ def lambda_handler(event, context):
251251
"account_id:123457598159",
252252
"functionname:python-layer-test",
253253
"resource:python-layer-test",
254-
"cold_start:true",
255254
"memorysize:256",
255+
"cold_start:true",
256256
"runtime:python3.9",
257257
"datadog_lambda:v6.6.6",
258258
"dd_lambda_layer:datadog-python39_X.X.X",
@@ -267,8 +267,8 @@ def lambda_handler(event, context):
267267
"account_id:123457598159",
268268
"functionname:python-layer-test",
269269
"resource:python-layer-test",
270-
"cold_start:true",
271270
"memorysize:256",
271+
"cold_start:true",
272272
"runtime:python3.9",
273273
"datadog_lambda:v6.6.6",
274274
"dd_lambda_layer:datadog-python39_X.X.X",
@@ -306,8 +306,8 @@ def lambda_handler(event, context):
306306
"account_id:123457598159",
307307
"functionname:python-layer-test",
308308
"resource:python-layer-test",
309-
"cold_start:true",
310309
"memorysize:256",
310+
"cold_start:true",
311311
"runtime:python3.9",
312312
"datadog_lambda:v6.6.6",
313313
"dd_lambda_layer:datadog-python39_X.X.X",
@@ -322,8 +322,8 @@ def lambda_handler(event, context):
322322
"account_id:123457598159",
323323
"functionname:python-layer-test",
324324
"resource:python-layer-test",
325-
"cold_start:true",
326325
"memorysize:256",
326+
"cold_start:true",
327327
"runtime:python3.9",
328328
"datadog_lambda:v6.6.6",
329329
"dd_lambda_layer:datadog-python39_X.X.X",
@@ -358,8 +358,8 @@ def lambda_handler(event, context):
358358
"account_id:123457598159",
359359
"functionname:python-layer-test",
360360
"resource:python-layer-test",
361-
"cold_start:true",
362361
"memorysize:256",
362+
"cold_start:true",
363363
"runtime:python3.9",
364364
"datadog_lambda:v6.6.6",
365365
"dd_lambda_layer:datadog-python39_X.X.X",
@@ -374,8 +374,8 @@ def lambda_handler(event, context):
374374
"account_id:123457598159",
375375
"functionname:python-layer-test",
376376
"resource:python-layer-test",
377-
"cold_start:false",
378377
"memorysize:256",
378+
"cold_start:false",
379379
"runtime:python3.9",
380380
"datadog_lambda:v6.6.6",
381381
"dd_lambda_layer:datadog-python39_X.X.X",
@@ -408,8 +408,8 @@ def lambda_handler(event, context):
408408
"account_id:123457598159",
409409
"functionname:python-layer-test",
410410
"resource:python-layer-test:Latest",
411-
"cold_start:true",
412411
"memorysize:256",
412+
"cold_start:true",
413413
"runtime:python3.9",
414414
"datadog_lambda:v6.6.6",
415415
"dd_lambda_layer:datadog-python39_X.X.X",
@@ -442,8 +442,8 @@ def lambda_handler(event, context):
442442
"functionname:python-layer-test",
443443
"executedversion:1",
444444
"resource:python-layer-test:My_alias-1",
445-
"cold_start:true",
446445
"memorysize:256",
446+
"cold_start:true",
447447
"runtime:python3.9",
448448
"datadog_lambda:v6.6.6",
449449
"dd_lambda_layer:datadog-python39_X.X.X",

0 commit comments

Comments
 (0)