Skip to content

Commit 3c2015e

Browse files
authored
fix(debugging): make probe instances hashable (DataDog#13309)
Probes are mutable but have an identity that allows them to be hashed. We make sure that probe instances are hashable. This in turns makes code objects where probes are injected hashable and usable for lookups. ## Checklist - [x] PR author has checked that all the criteria below are met - The PR description includes an overview of the change - The PR description articulates the motivation for the change - The change includes tests OR the PR description describes a testing strategy - The PR description notes risks associated with the change, if any - Newly-added code is easy to change - The change follows the [library release note guidelines](https://ddtrace.readthedocs.io/en/stable/releasenotes.html) - The change includes or references documentation updates if necessary - Backport labels are set (if [applicable](https://ddtrace.readthedocs.io/en/latest/contributing.html#backporting)) ## Reviewer Checklist - [x] Reviewer has checked that all the criteria below are met - Title is accurate - All changes are related to the pull request's stated goal - Avoids breaking [API](https://ddtrace.readthedocs.io/en/stable/versioning.html#interfaces) changes - Testing strategy adequately addresses listed risks - Newly-added code is easy to change - Release note makes sense to a user of the library - If necessary, author has acknowledged and discussed the performance implications of this PR as reported in the benchmarks PR comment - Backport labels are set in a manner that is consistent with the [release branch maintenance policy](https://ddtrace.readthedocs.io/en/latest/contributing.html#backporting)
1 parent 5a646aa commit 3c2015e

File tree

4 files changed

+37
-9
lines changed

4 files changed

+37
-9
lines changed

ddtrace/debugging/_probe/model.py

Lines changed: 15 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,12 @@ class CaptureLimits:
6666
DEFAULT_CAPTURE_LIMITS = CaptureLimits()
6767

6868

69+
# NOTE: Probe dataclasses are mutable, but have an identity, so can be hashed.
70+
# When defining a probe class, the `eq` parameter of the `dataclass` decorator
71+
# should be set to `False` to allow the `__hash__` method from the base Probe
72+
# class to be used.
73+
74+
6975
@dataclass
7076
class Probe(abc.ABC):
7177
__context_creator__ = False
@@ -194,12 +200,12 @@ class MetricProbeMixin(AbstractProbeMixIn):
194200
value: Optional[DDExpression]
195201

196202

197-
@dataclass
203+
@dataclass(eq=False)
198204
class MetricLineProbe(Probe, LineLocationMixin, MetricProbeMixin, ProbeConditionMixin):
199205
pass
200206

201207

202-
@dataclass
208+
@dataclass(eq=False)
203209
class MetricFunctionProbe(Probe, FunctionLocationMixin, TimingMixin, MetricProbeMixin, ProbeConditionMixin):
204210
pass
205211

@@ -251,13 +257,13 @@ def __budget__(self) -> int:
251257
return 10 if self.take_snapshot else 100
252258

253259

254-
@dataclass
260+
@dataclass(eq=False)
255261
class LogLineProbe(Probe, LineLocationMixin, LogProbeMixin, ProbeConditionMixin, RateLimitMixin):
256262
def is_global_rate_limited(self) -> bool:
257263
return self.take_snapshot
258264

259265

260-
@dataclass
266+
@dataclass(eq=False)
261267
class LogFunctionProbe(Probe, FunctionLocationMixin, TimingMixin, LogProbeMixin, ProbeConditionMixin, RateLimitMixin):
262268
def is_global_rate_limited(self) -> bool:
263269
return self.take_snapshot
@@ -268,7 +274,7 @@ class SpanProbeMixin:
268274
pass
269275

270276

271-
@dataclass
277+
@dataclass(eq=False)
272278
class SpanFunctionProbe(Probe, FunctionLocationMixin, SpanProbeMixin, ProbeConditionMixin):
273279
__context_creator__: bool = field(default=True, init=False, repr=False, compare=False)
274280

@@ -296,12 +302,12 @@ class SpanDecorationMixin:
296302
decorations: List[SpanDecoration]
297303

298304

299-
@dataclass
305+
@dataclass(eq=False)
300306
class SpanDecorationLineProbe(Probe, LineLocationMixin, SpanDecorationMixin):
301307
pass
302308

303309

304-
@dataclass
310+
@dataclass(eq=False)
305311
class SpanDecorationFunctionProbe(Probe, FunctionLocationMixin, TimingMixin, SpanDecorationMixin):
306312
pass
307313

@@ -312,12 +318,12 @@ class SessionMixin:
312318
level: int
313319

314320

315-
@dataclass
321+
@dataclass(eq=False)
316322
class TriggerLineProbe(Probe, LineLocationMixin, SessionMixin, ProbeConditionMixin, RateLimitMixin):
317323
pass
318324

319325

320-
@dataclass
326+
@dataclass(eq=False)
321327
class TriggerFunctionProbe(Probe, FunctionLocationMixin, SessionMixin, ProbeConditionMixin, RateLimitMixin):
322328
pass
323329

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
fixes:
3+
- |
4+
dynamic instrumentation: fix incompatibility between code origin and
5+
dynamic instrumentation probe on exit span functions.

tests/debugging/probe/test_model.py

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,3 +43,17 @@ def test_mutability():
4343
before.update(after)
4444

4545
assert before == after
46+
47+
48+
def test_probe_hash():
49+
probe = create_log_line_probe(
50+
probe_id="test_mutability",
51+
version=2,
52+
condition=DDExpression(dsl="True", callable=dd_compile(True)),
53+
source_file="foo",
54+
line=1,
55+
template="",
56+
segments=[],
57+
)
58+
59+
assert hash(probe)

tests/debugging/test_debugger.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,9 @@ def simple_debugger_test(probe, func):
5959

6060
d.add_probes(probe)
6161

62+
# Check that we can still hash the code object
63+
assert hash(func.__code__)
64+
6265
try:
6366
func()
6467
except Exception:

0 commit comments

Comments
 (0)