From 5cc036d9d8e90200a3722a24ea1aacb812c5d9a5 Mon Sep 17 00:00:00 2001 From: jean-philippe bempel Date: Thu, 27 Nov 2025 17:35:56 +0100 Subject: [PATCH 1/2] Make SymbolDB stand alone To be able to subscribe to symbol DB without enabling DI. Starting Symbol DB is still control from the backend. --- .../datadog/debugger/agent/DebuggerAgent.java | 95 +++++++++++++------ .../DefaultDebuggerConfigUpdaterTest.java | 2 + 2 files changed, 68 insertions(+), 29 deletions(-) diff --git a/dd-java-agent/agent-debugger/src/main/java/com/datadog/debugger/agent/DebuggerAgent.java b/dd-java-agent/agent-debugger/src/main/java/com/datadog/debugger/agent/DebuggerAgent.java index 6a493d95f9b..4962bca6a12 100644 --- a/dd-java-agent/agent-debugger/src/main/java/com/datadog/debugger/agent/DebuggerAgent.java +++ b/dd-java-agent/agent-debugger/src/main/java/com/datadog/debugger/agent/DebuggerAgent.java @@ -70,6 +70,7 @@ public class DebuggerAgent { static final AtomicBoolean exceptionReplayEnabled = new AtomicBoolean(); static final AtomicBoolean codeOriginEnabled = new AtomicBoolean(); static final AtomicBoolean distributedDebuggerEnabled = new AtomicBoolean(); + static final AtomicBoolean symDBEnabled = new AtomicBoolean(); private static ClassesToRetransformFinder classesToRetransformFinder; public static synchronized void run( @@ -89,10 +90,14 @@ public static synchronized void run( if (config.isDynamicInstrumentationEnabled()) { startDynamicInstrumentation(config); startCodeOriginForSpans(config); + startSymbolDatabase(config); if (config.getDynamicInstrumentationInstrumentTheWorld() != null) { setupInstrumentTheWorldTransformer(config, instrumentation, sink); } } + if (config.isSymbolDatabaseEnabled()) { + startSymbolDatabase(config); + } try { /* Note: shutdown hooks are tricky because JVM holds reference for them forever preventing @@ -165,24 +170,7 @@ public static void startDynamicInstrumentation(Config config) { return; } if (configurationPoller != null) { - if (config.isSymbolDatabaseEnabled()) { - initClassNameFilter(); - List scopeFilters = - Arrays.asList(new AvroFilter(), new ProtoFilter(), new WireFilter()); - SymbolAggregator symbolAggregator = - new SymbolAggregator( - classNameFilter, - scopeFilters, - sink.getSymbolSink(), - config.getSymbolDatabaseFlushThreshold()); - symbolAggregator.start(); - symDBEnablement = - new SymDBEnablement(instrumentation, config, symbolAggregator, classNameFilter); - if (config.isSymbolDatabaseForceUpload()) { - symDBEnablement.startSymbolExtraction(); - } - } - subscribeConfigurationPoller(config, configurationUpdater, symDBEnablement); + subscribeLiveDebugging(config, configurationUpdater); } else { LOGGER.debug("No configuration poller available from SharedCommunicationObjects"); } @@ -205,6 +193,66 @@ public static void stopDynamicInstrumentation() { } } + private static void subscribeLiveDebugging( + Config config, ConfigurationUpdater configurationUpdater) { + LOGGER.debug("Subscribing to Live Debugging..."); + configurationPoller.addListener( + Product.LIVE_DEBUGGING, new DebuggerProductChangesListener(config, configurationUpdater)); + if (symDBEnablement != null && !config.isSymbolDatabaseForceUpload()) { + LOGGER.debug("Subscribing to Symbol DB..."); + configurationPoller.addListener(Product.LIVE_DEBUGGING_SYMBOL_DB, symDBEnablement); + } + } + + public static void startSymbolDatabase(Config config) { + if (!symDBEnabled.compareAndSet(false, true)) { + return; + } + LOGGER.debug("Starting Symbol Database"); + commonInit(config); + initClassNameFilter(); + List scopeFilters = + Arrays.asList(new AvroFilter(), new ProtoFilter(), new WireFilter()); + SymbolAggregator symbolAggregator = + new SymbolAggregator( + classNameFilter, + scopeFilters, + sink.getSymbolSink(), + config.getSymbolDatabaseFlushThreshold()); + symbolAggregator.start(); + symDBEnablement = + new SymDBEnablement(instrumentation, config, symbolAggregator, classNameFilter); + if (config.isSymbolDatabaseForceUpload()) { + symDBEnablement.startSymbolExtraction(); + } + subscribeSymDB(symDBEnablement); + LOGGER.debug("Started Symbol Database"); + } + + private static void subscribeSymDB(SymDBEnablement symDBEnablement) { + LOGGER.debug("Subscribing to Symbol DB..."); + if (configurationPoller != null) { + configurationPoller.addListener(Product.LIVE_DEBUGGING_SYMBOL_DB, symDBEnablement); + } else { + LOGGER.debug("No configuration poller available from SharedCommunicationObjects"); + } + } + + public static void stopSymbolDatabase() { + if (!symDBEnabled.compareAndSet(true, false)) { + return; + } + LOGGER.info("Stopping Symbol Database"); + if (configurationPoller != null) { + configurationPoller.removeListeners(Product.LIVE_DEBUGGING_SYMBOL_DB); + } + SymDBEnablement localSymDBEnablement = symDBEnablement; + if (localSymDBEnablement != null) { + localSymDBEnablement.stopSymbolExtraction(); + symDBEnablement = null; + } + } + public static void startExceptionReplay(Config config) { if (!exceptionReplayEnabled.compareAndSet(false, true)) { return; @@ -369,17 +417,6 @@ private static void setupSourceFileTracking( instrumentation.addTransformer(sourceFileTrackingTransformer); } - private static void subscribeConfigurationPoller( - Config config, ConfigurationUpdater configurationUpdater, SymDBEnablement symDBEnablement) { - LOGGER.debug("Subscribing to Live Debugging..."); - configurationPoller.addListener( - Product.LIVE_DEBUGGING, new DebuggerProductChangesListener(config, configurationUpdater)); - if (symDBEnablement != null && !config.isSymbolDatabaseForceUpload()) { - LOGGER.debug("Subscribing to Symbol DB..."); - configurationPoller.addListener(Product.LIVE_DEBUGGING_SYMBOL_DB, symDBEnablement); - } - } - private static void unsubscribeConfigurationPoller() { if (configurationPoller != null) { configurationPoller.removeListeners(Product.LIVE_DEBUGGING); diff --git a/dd-java-agent/agent-debugger/src/test/java/com/datadog/debugger/agent/DefaultDebuggerConfigUpdaterTest.java b/dd-java-agent/agent-debugger/src/test/java/com/datadog/debugger/agent/DefaultDebuggerConfigUpdaterTest.java index 3f4fdc80919..de5833e08f9 100644 --- a/dd-java-agent/agent-debugger/src/test/java/com/datadog/debugger/agent/DefaultDebuggerConfigUpdaterTest.java +++ b/dd-java-agent/agent-debugger/src/test/java/com/datadog/debugger/agent/DefaultDebuggerConfigUpdaterTest.java @@ -7,6 +7,7 @@ import datadog.communication.ddagent.DDAgentFeaturesDiscovery; import datadog.communication.ddagent.SharedCommunicationObjects; +import datadog.remoteconfig.ConfigurationPoller; import datadog.trace.api.Config; import datadog.trace.api.debugger.DebuggerConfigUpdate; import java.lang.instrument.Instrumentation; @@ -17,6 +18,7 @@ class DefaultDebuggerConfigUpdaterTest { @Test public void enableDisable() { SharedCommunicationObjects sco = mock(SharedCommunicationObjects.class); + when(sco.configurationPoller(null)).thenReturn(mock(ConfigurationPoller.class)); when(sco.featuresDiscovery(any())).thenReturn(mock(DDAgentFeaturesDiscovery.class)); DebuggerAgent.run(Config.get(), mock(Instrumentation.class), sco); DefaultDebuggerConfigUpdater productConfigUpdater = From 9217cc8d5829a65dc5f7f956e50529b9cf4ad347 Mon Sep 17 00:00:00 2001 From: jean-philippe bempel Date: Thu, 4 Dec 2025 14:27:01 +0100 Subject: [PATCH 2/2] remove unnecessary code --- .../main/java/com/datadog/debugger/agent/DebuggerAgent.java | 4 ---- 1 file changed, 4 deletions(-) diff --git a/dd-java-agent/agent-debugger/src/main/java/com/datadog/debugger/agent/DebuggerAgent.java b/dd-java-agent/agent-debugger/src/main/java/com/datadog/debugger/agent/DebuggerAgent.java index 4962bca6a12..21328f20776 100644 --- a/dd-java-agent/agent-debugger/src/main/java/com/datadog/debugger/agent/DebuggerAgent.java +++ b/dd-java-agent/agent-debugger/src/main/java/com/datadog/debugger/agent/DebuggerAgent.java @@ -198,10 +198,6 @@ private static void subscribeLiveDebugging( LOGGER.debug("Subscribing to Live Debugging..."); configurationPoller.addListener( Product.LIVE_DEBUGGING, new DebuggerProductChangesListener(config, configurationUpdater)); - if (symDBEnablement != null && !config.isSymbolDatabaseForceUpload()) { - LOGGER.debug("Subscribing to Symbol DB..."); - configurationPoller.addListener(Product.LIVE_DEBUGGING_SYMBOL_DB, symDBEnablement); - } } public static void startSymbolDatabase(Config config) {