Skip to content

Commit 5fe80f9

Browse files
committed
feat(di): enable code origins for entry spans when di is enabled
- Extract `SpanCodeOriginProcessorEntry` base class to handle entry span processing - Enable entry-only code origins when DI is enabled and span code origins aren't explicitly disabled - Refactor `SpanCodeOriginProcessor` to inherit from entry processor for code reuse - Update product lifecycle to conditionally enable entry vs full span processing Refs: DEBUG-3787
1 parent 92b4a36 commit 5fe80f9

File tree

2 files changed

+51
-15
lines changed

2 files changed

+51
-15
lines changed

ddtrace/debugging/_origin/span.py

Lines changed: 39 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -196,12 +196,44 @@ def __exit__(self, exc_type, exc_value, traceback):
196196

197197

198198
@dataclass
199-
class SpanCodeOriginProcessor(SpanProcessor):
199+
class SpanCodeOriginProcessorEntry(SpanProcessor):
200200
__uploader__ = LogsIntakeUploaderV1
201201

202-
_instance: t.Optional["SpanCodeOriginProcessor"] = None
202+
_entry_instance: t.Optional["SpanCodeOriginProcessorEntry"] = None
203203
_handler: t.Optional[t.Callable] = None
204204

205+
@classmethod
206+
def enable(cls):
207+
if cls._entry_instance is not None:
208+
return
209+
210+
cls._entry_instance = cls()
211+
212+
# Register code origin for span with the snapshot uploader
213+
cls.__uploader__.register(UploaderProduct.CODE_ORIGIN_SPAN)
214+
215+
# Register the entrypoint wrapping for entry spans
216+
cls._handler = handler = partial(wrap_entrypoint, cls.__uploader__.get_collector())
217+
core.on("service_entrypoint.patch", handler)
218+
219+
@classmethod
220+
def disable(cls):
221+
if cls._entry_instance is None:
222+
return
223+
224+
# Unregister the entrypoint wrapping for entry spans
225+
core.reset_listeners("service_entrypoint.patch", cls._handler)
226+
# Unregister code origin for span with the snapshot uploader
227+
cls.__uploader__.unregister(UploaderProduct.CODE_ORIGIN_SPAN)
228+
229+
cls._handler = None
230+
cls._entry_instance = None
231+
232+
233+
@dataclass
234+
class SpanCodeOriginProcessor(SpanCodeOriginProcessorEntry):
235+
_instance: t.Optional["SpanCodeOriginProcessor"] = None
236+
205237
def on_span_start(self, span: Span) -> None:
206238
if span.span_type not in EXIT_SPAN_TYPES:
207239
return
@@ -264,29 +296,21 @@ def enable(cls):
264296

265297
instance = cls._instance = cls()
266298

267-
# Register code origin for span with the snapshot uploader
268-
cls.__uploader__.register(UploaderProduct.CODE_ORIGIN_SPAN)
269-
270299
# Register the processor for exit spans
271300
instance.register()
272301

273-
# Register the entrypoint wrapping for entry spans
274-
cls._handler = handler = partial(wrap_entrypoint, cls.__uploader__.get_collector())
275-
core.on("service_entrypoint.patch", handler)
302+
# Enable entry spans. This is idempotent so multiple calls are safe if CO is enabled
303+
# after DI via remote configuration.
304+
super().enable()
276305

277306
@classmethod
278307
def disable(cls):
279308
if cls._instance is None:
280309
return
281310

282-
# Unregister the entrypoint wrapping for entry spans
283-
core.reset_listeners("service_entrypoint.patch", cls._handler)
284-
cls._handler = None
311+
# Disable entry spans
312+
super().disable()
285313

286314
# Unregister the processor for exit spans
287315
cls._instance.unregister()
288-
289-
# Unregister code origin for span with the snapshot uploader
290-
cls.__uploader__.unregister(UploaderProduct.CODE_ORIGIN_SPAN)
291-
292316
cls._instance = None

ddtrace/debugging/_products/code_origin/span.py

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
1+
from ddtrace.settings._core import ValueSource
12
from ddtrace.settings.code_origin import config
3+
from ddtrace.settings.dynamic_instrumentation import config as di_config
24

35

46
# TODO[gab]: Uncomment this when the feature is ready
@@ -14,6 +16,12 @@ def start():
1416
from ddtrace.debugging._origin.span import SpanCodeOriginProcessor
1517

1618
SpanCodeOriginProcessor.enable()
19+
# If dynamic instrumentation is enabled, and code origin for spans is not explicitly disabled,
20+
# we'll enable entry spans only.
21+
elif di_config.enabled and config.value_source("DD_CODE_ORIGIN_FOR_SPANS_ENABLED") == ValueSource.DEFAULT:
22+
from ddtrace.debugging._origin.span import SpanCodeOriginProcessorEntry
23+
24+
SpanCodeOriginProcessorEntry.enable()
1725

1826

1927
def restart(join=False):
@@ -25,6 +33,10 @@ def stop(join=False):
2533
from ddtrace.debugging._origin.span import SpanCodeOriginProcessor
2634

2735
SpanCodeOriginProcessor.disable()
36+
elif di_config.enabled:
37+
from ddtrace.debugging._origin.span import SpanCodeOriginProcessorEntry
38+
39+
SpanCodeOriginProcessorEntry.disable()
2840

2941

3042
def at_exit(join=False):

0 commit comments

Comments
 (0)