From 1c380dbb1f5581698187277479c611f04c8a435e Mon Sep 17 00:00:00 2001 From: jean-philippe bempel Date: Fri, 3 Oct 2025 18:34:20 +0200 Subject: [PATCH 1/3] Fix Exception Probes to not emit any probe status filter on probe definition type --- .../debugger/agent/ConfigurationUpdater.java | 5 +++ .../debugger/agent/DebuggerTransformer.java | 4 +++ .../datadog/debugger/sink/DebuggerSink.java | 6 +++- .../ExceptionDebuggerIntegrationTest.java | 10 +++--- .../InProductEnablementIntegrationTest.java | 4 +-- .../ServerAppDebuggerIntegrationTest.java | 31 ++++++++++--------- 6 files changed, 38 insertions(+), 22 deletions(-) diff --git a/dd-java-agent/agent-debugger/src/main/java/com/datadog/debugger/agent/ConfigurationUpdater.java b/dd-java-agent/agent-debugger/src/main/java/com/datadog/debugger/agent/ConfigurationUpdater.java index 3575f1bf3b0..32d331c3813 100644 --- a/dd-java-agent/agent-debugger/src/main/java/com/datadog/debugger/agent/ConfigurationUpdater.java +++ b/dd-java-agent/agent-debugger/src/main/java/com/datadog/debugger/agent/ConfigurationUpdater.java @@ -7,6 +7,7 @@ import static datadog.trace.api.telemetry.LogCollector.SEND_TELEMETRY; import com.datadog.debugger.instrumentation.InstrumentationResult; +import com.datadog.debugger.probe.ExceptionProbe; import com.datadog.debugger.probe.LogProbe; import com.datadog.debugger.probe.ProbeDefinition; import com.datadog.debugger.probe.Sampled; @@ -176,6 +177,10 @@ private void handleProbesChanges(ConfigurationComparer changes, Configuration ne private void reportReceived(ConfigurationComparer changes) { for (ProbeDefinition def : changes.getAddedDefinitions()) { + if (def instanceof ExceptionProbe) { + // do not report received for exception probes + continue; + } sink.addReceived(def.getProbeId()); } for (ProbeDefinition def : changes.getRemovedDefinitions()) { diff --git a/dd-java-agent/agent-debugger/src/main/java/com/datadog/debugger/agent/DebuggerTransformer.java b/dd-java-agent/agent-debugger/src/main/java/com/datadog/debugger/agent/DebuggerTransformer.java index 5182f7cda17..8da2db9fd8c 100644 --- a/dd-java-agent/agent-debugger/src/main/java/com/datadog/debugger/agent/DebuggerTransformer.java +++ b/dd-java-agent/agent-debugger/src/main/java/com/datadog/debugger/agent/DebuggerTransformer.java @@ -590,6 +590,10 @@ private void handleInstrumentationResult( if (listener != null) { listener.instrumentationResult(definition, result); } + if (definition instanceof ExceptionProbe) { + // do not report diagnostics for exception probes + continue; + } List diagnosticMessages = result.getDiagnostics().get(definition.getProbeId()); if (!result.getDiagnostics().isEmpty()) { diff --git a/dd-java-agent/agent-debugger/src/main/java/com/datadog/debugger/sink/DebuggerSink.java b/dd-java-agent/agent-debugger/src/main/java/com/datadog/debugger/sink/DebuggerSink.java index 3d2a74dd0df..f9ac43b5d0e 100644 --- a/dd-java-agent/agent-debugger/src/main/java/com/datadog/debugger/sink/DebuggerSink.java +++ b/dd-java-agent/agent-debugger/src/main/java/com/datadog/debugger/sink/DebuggerSink.java @@ -1,6 +1,7 @@ package com.datadog.debugger.sink; import com.datadog.debugger.instrumentation.DiagnosticMessage; +import com.datadog.debugger.probe.ExceptionProbe; import com.datadog.debugger.uploader.BatchUploader; import com.datadog.debugger.util.DebuggerMetrics; import datadog.trace.api.Config; @@ -123,7 +124,10 @@ public void addSnapshot(Snapshot snapshot) { if (!added) { debuggerMetrics.count(DROPPED_REQ_METRIC, 1); } else { - probeStatusSink.addEmitting(snapshot.getProbe().getProbeId()); + if (!(snapshot.getProbe() instanceof ExceptionProbe)) { + // do not report emitting for exception probes + probeStatusSink.addEmitting(snapshot.getProbe().getProbeId()); + } } } diff --git a/dd-smoke-tests/debugger-integration-tests/src/test/java/datadog/smoketest/ExceptionDebuggerIntegrationTest.java b/dd-smoke-tests/debugger-integration-tests/src/test/java/datadog/smoketest/ExceptionDebuggerIntegrationTest.java index 225495ffc7a..05da20b349b 100644 --- a/dd-smoke-tests/debugger-integration-tests/src/test/java/datadog/smoketest/ExceptionDebuggerIntegrationTest.java +++ b/dd-smoke-tests/debugger-integration-tests/src/test/java/datadog/smoketest/ExceptionDebuggerIntegrationTest.java @@ -49,7 +49,7 @@ protected ProcessBuilder createProcessBuilder(Path logFilePath, String... params void testSimpleSingleFrameException() throws Exception { appUrl = startAppAndAndGetUrl(); execute(appUrl, TRACED_METHOD_NAME, "oops"); // instrumenting first exception - waitForInstrumentation(appUrl); + waitForInstrumentation(appUrl, SERVER_DEBUGGER_TEST_APP_CLASS, false); execute(appUrl, TRACED_METHOD_NAME, "oops"); // collecting snapshots and sending them registerTraceListener(this::receiveExceptionReplayTrace); registerSnapshotListener(this::receiveSnapshot); @@ -116,7 +116,7 @@ void testNoSubsequentCaptureAfterFirst() throws Exception { void test3CapturedFrames() throws Exception { appUrl = startAppAndAndGetUrl(); execute(appUrl, TRACED_METHOD_NAME, "deepOops"); // instrumenting first exception - waitForInstrumentation(appUrl); + waitForInstrumentation(appUrl, SERVER_DEBUGGER_TEST_APP_CLASS, false); execute(appUrl, TRACED_METHOD_NAME, "deepOops"); // collecting snapshots and sending them registerTraceListener(this::receiveExceptionReplayTrace); registerSnapshotListener(this::receiveSnapshot); @@ -173,7 +173,7 @@ void test5CapturedFrames() throws Exception { additionalJvmArgs.add("-Ddd.exception.replay.capture.max.frames=5"); appUrl = startAppAndAndGetUrl(); execute(appUrl, TRACED_METHOD_NAME, "deepOops"); // instrumenting first exception - waitForInstrumentation(appUrl); + waitForInstrumentation(appUrl, SERVER_DEBUGGER_TEST_APP_CLASS, false); execute(appUrl, TRACED_METHOD_NAME, "deepOops"); // collecting snapshots and sending them registerTraceListener(this::receiveExceptionReplayTrace); registerSnapshotListener(this::receiveSnapshot); @@ -249,7 +249,7 @@ void test5CapturedFrames() throws Exception { void test3CapturedRecursiveFrames() throws Exception { appUrl = startAppAndAndGetUrl(); execute(appUrl, TRACED_METHOD_NAME, "recursiveOops"); // instrumenting first exception - waitForInstrumentation(appUrl); + waitForInstrumentation(appUrl, SERVER_DEBUGGER_TEST_APP_CLASS, false); execute(appUrl, TRACED_METHOD_NAME, "recursiveOops"); // collecting snapshots and sending them registerTraceListener(this::receiveExceptionReplayTrace); registerSnapshotListener(this::receiveSnapshot); @@ -296,7 +296,7 @@ void testLambdaHiddenFrames() throws Exception { additionalJvmArgs.add("-XX:+ShowHiddenFrames"); appUrl = startAppAndAndGetUrl(); execute(appUrl, TRACED_METHOD_NAME, "lambdaOops"); // instrumenting first exception - waitForInstrumentation(appUrl); + waitForInstrumentation(appUrl, SERVER_DEBUGGER_TEST_APP_CLASS, false); execute(appUrl, TRACED_METHOD_NAME, "lambdaOops"); // collecting snapshots and sending them registerTraceListener(this::receiveExceptionReplayTrace); registerSnapshotListener(this::receiveSnapshot); diff --git a/dd-smoke-tests/debugger-integration-tests/src/test/java/datadog/smoketest/InProductEnablementIntegrationTest.java b/dd-smoke-tests/debugger-integration-tests/src/test/java/datadog/smoketest/InProductEnablementIntegrationTest.java index 9277d71a968..7b0065232ef 100644 --- a/dd-smoke-tests/debugger-integration-tests/src/test/java/datadog/smoketest/InProductEnablementIntegrationTest.java +++ b/dd-smoke-tests/debugger-integration-tests/src/test/java/datadog/smoketest/InProductEnablementIntegrationTest.java @@ -51,7 +51,7 @@ void testDynamicInstrumentationEnablementWithLineProbe() throws Exception { setCurrentConfiguration(createConfig(probe)); waitForFeatureStarted(appUrl, "Dynamic Instrumentation"); execute(appUrl, "topLevelMethod", ""); - waitForInstrumentation(appUrl, "datadog.smoketest.debugger.TopLevel"); + waitForInstrumentation(appUrl, "datadog.smoketest.debugger.TopLevel", true); // disable DI setConfigOverrides(createConfigOverrides(false, false)); waitForFeatureStopped(appUrl, "Dynamic Instrumentation"); @@ -81,7 +81,7 @@ void testExceptionReplayEnablement() throws Exception { setConfigOverrides(createConfigOverrides(false, true)); waitForFeatureStarted(appUrl, "Exception Replay"); execute(appUrl, TRACED_METHOD_NAME, "oops"); // instrumenting first exception - waitForInstrumentation(appUrl); + waitForInstrumentation(appUrl, SERVER_DEBUGGER_TEST_APP_CLASS, false); // disable ER setConfigOverrides(createConfigOverrides(false, false)); waitForFeatureStopped(appUrl, "Exception Replay"); diff --git a/dd-smoke-tests/debugger-integration-tests/src/test/java/datadog/smoketest/ServerAppDebuggerIntegrationTest.java b/dd-smoke-tests/debugger-integration-tests/src/test/java/datadog/smoketest/ServerAppDebuggerIntegrationTest.java index 816544a31d7..fa44b4f5e79 100644 --- a/dd-smoke-tests/debugger-integration-tests/src/test/java/datadog/smoketest/ServerAppDebuggerIntegrationTest.java +++ b/dd-smoke-tests/debugger-integration-tests/src/test/java/datadog/smoketest/ServerAppDebuggerIntegrationTest.java @@ -99,25 +99,28 @@ protected void execute(String appUrl, String methodName, String arg) throws IOEx } protected void waitForInstrumentation(String appUrl) throws Exception { - waitForInstrumentation(appUrl, SERVER_DEBUGGER_TEST_APP_CLASS); + waitForInstrumentation(appUrl, SERVER_DEBUGGER_TEST_APP_CLASS, true); } - protected void waitForInstrumentation(String appUrl, String className) throws Exception { + protected void waitForInstrumentation( + String appUrl, String className, boolean waitOnProbeStatuses) throws Exception { String url = String.format(appUrl + "/waitForInstrumentation?classname=%s", className); LOG.info("waitForInstrumentation with url={}", url); sendRequest(url); - AtomicBoolean received = new AtomicBoolean(); - AtomicBoolean installed = new AtomicBoolean(); - registerProbeStatusListener( - probeStatus -> { - if (probeStatus.getDiagnostics().getStatus() == ProbeStatus.Status.RECEIVED) { - received.set(true); - } - if (probeStatus.getDiagnostics().getStatus() == ProbeStatus.Status.INSTALLED) { - installed.set(true); - } - }); - processRequests(() -> received.get() && installed.get()); + if (waitOnProbeStatuses) { + AtomicBoolean received = new AtomicBoolean(); + AtomicBoolean installed = new AtomicBoolean(); + registerProbeStatusListener( + probeStatus -> { + if (probeStatus.getDiagnostics().getStatus() == ProbeStatus.Status.RECEIVED) { + received.set(true); + } + if (probeStatus.getDiagnostics().getStatus() == ProbeStatus.Status.INSTALLED) { + installed.set(true); + } + }); + processRequests(() -> received.get() && installed.get()); + } LOG.info("instrumentation done"); } From 7798aabbac5c9d4cee30ef3feed41f18e11fa543 Mon Sep 17 00:00:00 2001 From: jean-philippe bempel Date: Mon, 6 Oct 2025 09:23:18 +0200 Subject: [PATCH 2/3] fix tests --- .../src/test/groovy/datadog/smoketest/MavenSmokeTest.groovy | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dd-smoke-tests/maven/src/test/groovy/datadog/smoketest/MavenSmokeTest.groovy b/dd-smoke-tests/maven/src/test/groovy/datadog/smoketest/MavenSmokeTest.groovy index 8a56ab596a6..dae2782c22b 100644 --- a/dd-smoke-tests/maven/src/test/groovy/datadog/smoketest/MavenSmokeTest.groovy +++ b/dd-smoke-tests/maven/src/test/groovy/datadog/smoketest/MavenSmokeTest.groovy @@ -247,7 +247,7 @@ class MavenSmokeTest extends CiVisibilitySmokeTest { def additionalDynamicTags = ["content.meta.['_dd.debug.error.3.snapshot_id']", "content.meta.['_dd.debug.error.exception_id']"] verifyEventsAndCoverages(projectName, "maven", mavenVersion, mockBackend.waitForEvents(7), mockBackend.waitForCoverages(0), additionalDynamicTags) - verifySnapshotLogs(mockBackend.waitForLogs(5), 1, 2) + verifySnapshotLogs(mockBackend.waitForLogs(2), 0, 2) where: projectName | mavenVersion From 2dac9e5ffc07871be9df095ebaa278458befd329 Mon Sep 17 00:00:00 2001 From: jean-philippe bempel Date: Mon, 6 Oct 2025 10:42:48 +0200 Subject: [PATCH 3/3] fix tests --- .../datadog/trace/civisibility/CiVisibilitySmokeTest.groovy | 2 +- .../test/groovy/datadog/smoketest/JUnitConsoleSmokeTest.groovy | 2 +- .../src/test/groovy/datadog/smoketest/MavenSmokeTest.groovy | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/dd-java-agent/agent-ci-visibility/civisibility-test-fixtures/src/main/groovy/datadog/trace/civisibility/CiVisibilitySmokeTest.groovy b/dd-java-agent/agent-ci-visibility/civisibility-test-fixtures/src/main/groovy/datadog/trace/civisibility/CiVisibilitySmokeTest.groovy index d434360d14c..d10ff6f35ef 100644 --- a/dd-java-agent/agent-ci-visibility/civisibility-test-fixtures/src/main/groovy/datadog/trace/civisibility/CiVisibilitySmokeTest.groovy +++ b/dd-java-agent/agent-ci-visibility/civisibility-test-fixtures/src/main/groovy/datadog/trace/civisibility/CiVisibilitySmokeTest.groovy @@ -149,7 +149,7 @@ abstract class CiVisibilitySmokeTest extends Specification { assert logs.findAll { log -> ((String) log.message).endsWith("is emitting.") }.size() == expectedCount } - private static verifySnapshots(List> logs, expectedCount) { + protected static verifySnapshots(List> logs, expectedCount) { assert logs.size() == expectedCount def requiredLogFields = ["logger.name", "logger.method", "dd.spanid", "dd.traceid"] diff --git a/dd-smoke-tests/junit-console/src/test/groovy/datadog/smoketest/JUnitConsoleSmokeTest.groovy b/dd-smoke-tests/junit-console/src/test/groovy/datadog/smoketest/JUnitConsoleSmokeTest.groovy index 82fa45225a6..3d4d54ff308 100644 --- a/dd-smoke-tests/junit-console/src/test/groovy/datadog/smoketest/JUnitConsoleSmokeTest.groovy +++ b/dd-smoke-tests/junit-console/src/test/groovy/datadog/smoketest/JUnitConsoleSmokeTest.groovy @@ -59,7 +59,7 @@ class JUnitConsoleSmokeTest extends CiVisibilitySmokeTest { def additionalDynamicTags = ["content.meta.['_dd.debug.error.6.snapshot_id']", "content.meta.['_dd.debug.error.exception_id']"] verifyEventsAndCoverages(projectName, "junit-console", "headless", mockBackend.waitForEvents(7), mockBackend.waitForCoverages(0), additionalDynamicTags) - verifySnapshotLogs(mockBackend.waitForLogs(5), 1, 2) + verifySnapshots(mockBackend.waitForLogs(2), 2) where: projectName = "test_junit_console_failed_test_replay" diff --git a/dd-smoke-tests/maven/src/test/groovy/datadog/smoketest/MavenSmokeTest.groovy b/dd-smoke-tests/maven/src/test/groovy/datadog/smoketest/MavenSmokeTest.groovy index dae2782c22b..9778a0763f1 100644 --- a/dd-smoke-tests/maven/src/test/groovy/datadog/smoketest/MavenSmokeTest.groovy +++ b/dd-smoke-tests/maven/src/test/groovy/datadog/smoketest/MavenSmokeTest.groovy @@ -247,7 +247,7 @@ class MavenSmokeTest extends CiVisibilitySmokeTest { def additionalDynamicTags = ["content.meta.['_dd.debug.error.3.snapshot_id']", "content.meta.['_dd.debug.error.exception_id']"] verifyEventsAndCoverages(projectName, "maven", mavenVersion, mockBackend.waitForEvents(7), mockBackend.waitForCoverages(0), additionalDynamicTags) - verifySnapshotLogs(mockBackend.waitForLogs(2), 0, 2) + verifySnapshots(mockBackend.waitForLogs(2), 2) where: projectName | mavenVersion