Skip to content

Commit f92a00e

Browse files
committed
fix wrapping context-lazy wrapping context compat
1 parent 45733c9 commit f92a00e

File tree

5 files changed

+60
-2
lines changed

5 files changed

+60
-2
lines changed

ddtrace/debugging/_function/discovery.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -139,7 +139,10 @@ def resolve(self) -> FullyNamedFunction:
139139
msg = "Cannot resolve pair with no code object"
140140
raise ValueError(msg)
141141

142-
if self.function is not None:
142+
# Check that the function we have cached is not a wrapper layer that
143+
# has been unwrapped. In this case we need to resolve the new function
144+
# from the code object.
145+
if (_ := self.function) is not None and _.__name__ != "<unwrapped>":
143146
return cast(FullyNamedFunction, self.function)
144147

145148
code = self.code

ddtrace/internal/wrapping/__init__.py

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -322,6 +322,13 @@ def unwrap(wf, wrapper):
322322
# current one.
323323
f = cast(FunctionType, wf)
324324
f.__code__ = inner.__code__
325+
326+
# Mark the function as unwrapped via its name. There might be references
327+
# to this function elsewhere and this would signal that the function has
328+
# been unwrapped and that another function object is referencing the
329+
# original code object.
330+
inner.__name__ = "<unwrapped>"
331+
325332
try:
326333
# Update the link to the next layer.
327334
inner_wf = cast(WrappedFunction, inner)

ddtrace/internal/wrapping/context.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -394,6 +394,12 @@ def wrap(self) -> None:
394394
if self._trampoline is not None:
395395
return
396396

397+
# If the function is already universally wrapped so it's less expensive
398+
# to do the normal wrapping.
399+
if _UniversalWrappingContext.is_wrapped(self.__wrapped__):
400+
super().wrap()
401+
return
402+
397403
def trampoline(_, args, kwargs):
398404
with tl:
399405
f = t.cast(WrappedFunction, self.__wrapped__)

tests/debugging/mocking.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -177,7 +177,7 @@ def assert_single_snapshot(self):
177177

178178
assert len(self.test_queue) == 1
179179

180-
yield self.test_queue[0]
180+
yield self.test_queue.pop(0)
181181

182182

183183
@contextmanager

tests/debugging/test_debugger.py

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -642,6 +642,48 @@ def test_debugger_line_probe_on_lazy_wrapped_function(stuff):
642642
assert snapshot.probe.probe_id == "line-probe-lazy-wrapping"
643643

644644

645+
def test_debugger_function_probe_on_lazy_wrapped_function(stuff):
646+
from ddtrace.internal.wrapping.context import LazyWrappingContext
647+
648+
class LWC(LazyWrappingContext):
649+
def __enter__(self):
650+
self.entered = True
651+
return super().__enter__()
652+
653+
(c := LWC(stuff.Stuff.instancestuff)).wrap()
654+
655+
with debugger() as d:
656+
d.add_probes(
657+
probe := create_snapshot_function_probe(
658+
probe_id="function-probe-lazy-wrapping",
659+
module="tests.submod.stuff",
660+
func_qname="Stuff.instancestuff",
661+
rate=float("inf"),
662+
)
663+
)
664+
665+
stuff.Stuff().instancestuff(42)
666+
667+
d.remove_probes(probe)
668+
669+
assert c.entered
670+
671+
with d.assert_single_snapshot() as snapshot:
672+
assert snapshot.probe.probe_id == "function-probe-lazy-wrapping"
673+
674+
# Test that we can re-instrument the function correctly and that we
675+
# don't accidentally instrument the temporary trampoline instead.
676+
677+
d.add_probes(probe)
678+
679+
stuff.Stuff().instancestuff(42)
680+
681+
d.remove_probes(probe)
682+
683+
with d.assert_single_snapshot() as snapshot:
684+
assert snapshot.probe.probe_id == "function-probe-lazy-wrapping"
685+
686+
645687
def test_probe_status_logging(remote_config_worker, stuff):
646688
assert remoteconfig_poller.status == ServiceStatus.STOPPED
647689

0 commit comments

Comments
 (0)