Skip to content

Commit b2e02d7

Browse files
committed
Datadog wrapper should never break the wrapped Lambda function
1 parent ebeee64 commit b2e02d7

File tree

2 files changed

+36
-26
lines changed

2 files changed

+36
-26
lines changed

datadog_lambda/wrapper.py

Lines changed: 33 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -53,37 +53,45 @@ class _LambdaDecorator(object):
5353
and extracts/injects trace context.
5454
"""
5555

56-
_force_new = False
56+
_force_wrap = False
5757

5858
def __new__(cls, func):
5959
"""
6060
If the decorator is accidentally applied to the same function multiple times,
61-
only the first one takes effect.
61+
wrap only once.
6262
63-
If _force_new, always return a real decorator, useful for unit tests.
63+
If _force_wrap, always return a real decorator, useful for unit tests.
6464
"""
65-
if cls._force_new or not getattr(func, "_dd_wrapped", False):
66-
wrapped = super(_LambdaDecorator, cls).__new__(cls)
67-
wrapped._dd_wrapped = True
68-
return wrapped
69-
else:
70-
return _NoopDecorator(func)
65+
try:
66+
if cls._force_wrap or not isinstance(func, _LambdaDecorator):
67+
wrapped = super(_LambdaDecorator, cls).__new__(cls)
68+
logger.debug("datadog_lambda_wrapper wrapped")
69+
return wrapped
70+
else:
71+
logger.debug("datadog_lambda_wrapper already wrapped")
72+
return _NoopDecorator(func)
73+
except Exception:
74+
traceback.print_exc()
75+
return func
7176

7277
def __init__(self, func):
7378
"""Executes when the wrapped function gets wrapped"""
74-
self.func = func
75-
self.flush_to_log = os.environ.get("DD_FLUSH_TO_LOG", "").lower() == "true"
76-
self.logs_injection = (
77-
os.environ.get("DD_LOGS_INJECTION", "true").lower() == "true"
78-
)
79-
80-
# Inject trace correlation ids to logs
81-
if self.logs_injection:
82-
inject_correlation_ids()
83-
84-
# Patch HTTP clients to propagate Datadog trace context
85-
patch_all()
86-
logger.debug("datadog_lambda_wrapper initialized")
79+
try:
80+
self.func = func
81+
self.flush_to_log = os.environ.get("DD_FLUSH_TO_LOG", "").lower() == "true"
82+
self.logs_injection = (
83+
os.environ.get("DD_LOGS_INJECTION", "true").lower() == "true"
84+
)
85+
86+
# Inject trace correlation ids to logs
87+
if self.logs_injection:
88+
inject_correlation_ids()
89+
90+
# Patch HTTP clients to propagate Datadog trace context
91+
patch_all()
92+
logger.debug("datadog_lambda_wrapper initialized")
93+
except Exception:
94+
traceback.print_exc()
8795

8896
def __call__(self, event, context, **kwargs):
8997
"""Executes when the wrapped function gets called"""
@@ -97,21 +105,23 @@ def __call__(self, event, context, **kwargs):
97105
self._after(event, context)
98106

99107
def _before(self, event, context):
100-
set_cold_start()
101108
try:
109+
set_cold_start()
102110
submit_invocations_metric(context)
103111
# Extract Datadog trace context from incoming requests
104112
extract_dd_trace_context(event)
105113

106114
# Set log correlation ids using extracted trace context
107115
set_correlation_ids()
116+
logger.debug("datadog_lambda_wrapper _before() done")
108117
except Exception:
109118
traceback.print_exc()
110119

111120
def _after(self, event, context):
112121
try:
113122
if not self.flush_to_log:
114123
lambda_stats.flush(float("inf"))
124+
logger.debug("datadog_lambda_wrapper _after() done")
115125
except Exception:
116126
traceback.print_exc()
117127

tests/test_wrapper.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ class TestDatadogLambdaWrapper(unittest.TestCase):
2626
def setUp(self):
2727
# Force @datadog_lambda_wrapper to always create a real
2828
# (not no-op) wrapper.
29-
datadog_lambda_wrapper._force_new = True
29+
datadog_lambda_wrapper._force_wrap = True
3030

3131
patcher = patch("datadog_lambda.metric.lambda_stats")
3232
self.mock_metric_lambda_stats = patcher.start()
@@ -265,9 +265,9 @@ def test_only_one_wrapper_in_use(self):
265265
def lambda_handler(event, context):
266266
lambda_metric("test.metric", 100)
267267

268-
# Turn off _force_new to emulate the nested wrapper scenario,
268+
# Turn off _force_wrap to emulate the nested wrapper scenario,
269269
# the second @datadog_lambda_wrapper should actually be no-op.
270-
datadog_lambda_wrapper._force_new = False
270+
datadog_lambda_wrapper._force_wrap = False
271271

272272
lambda_handler_double_wrapped = datadog_lambda_wrapper(lambda_handler)
273273

0 commit comments

Comments
 (0)