From e2925ac3ed48ace9d239aabca9f7895d93368759 Mon Sep 17 00:00:00 2001 From: jean-philippe bempel Date: Mon, 22 Sep 2025 15:32:01 +0200 Subject: [PATCH 1/3] Disable exit spans change some info level to debug --- .../debugger/agent/ConfigurationUpdater.java | 4 +- .../debugger/agent/DebuggerTransformer.java | 68 +++++++++---------- .../codeorigin/DefaultCodeOriginRecorder.java | 4 ++ 3 files changed, 40 insertions(+), 36 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 8f5d910285f..3575f1bf3b0 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 @@ -131,7 +131,7 @@ private void applyNewConfiguration(Configuration newConfiguration) { } currentConfiguration = newConfiguration; if (changes.hasProbeRelatedChanges()) { - LOGGER.info("Applying new probe configuration, changes: {}", changes); + LOGGER.debug("Applying new probe configuration, changes: {}", changes); handleProbesChanges(changes, newConfiguration); } } finally { @@ -208,7 +208,7 @@ private void recordInstrumentationProgress( private void retransformClasses(List> classesToBeTransformed) { for (Class clazz : classesToBeTransformed) { try { - LOGGER.info("Re-transforming class: {}", clazz.getTypeName()); + LOGGER.debug("Re-transforming class: {}", clazz.getTypeName()); instrumentation.retransformClasses(clazz); } catch (Exception ex) { ExceptionHelper.logException(LOGGER, ex, "Re-transform error:"); 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 f74999726ff..121f2a553ad 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 @@ -76,7 +76,7 @@ * debugger configuration */ public class DebuggerTransformer implements ClassFileTransformer { - private static final Logger log = LoggerFactory.getLogger(DebuggerTransformer.class); + private static final Logger LOGGER = LoggerFactory.getLogger(DebuggerTransformer.class); private static final String CANNOT_FIND_METHOD = "Cannot find method %s::%s%s"; private static final String INSTRUMENTATION_FAILS = "Instrumentation fails for %s"; private static final String CANNOT_FIND_LINE = "No executable code was found at %s:L%s"; @@ -148,7 +148,7 @@ public DebuggerTransformer( } else if (itwType.equals("line")) { probeCreator = this::createLineProbes; } else { - log.warn( + LOGGER.warn( "Invalid value for 'dd.debugger.instrument-the-world' property: {}. " + "Valid values are 'method' or 'line'.", itwType); @@ -202,7 +202,7 @@ private void processITWFiles( for (String fileName : fileNames) { Path excludePath = Paths.get(fileName); if (!Files.exists(excludePath)) { - log.warn("Cannot find exclude file: {}", excludePath); + LOGGER.warn("Cannot find exclude file: {}", excludePath); continue; } try { @@ -223,7 +223,7 @@ private void processITWFiles( classes.add(line); }); } catch (IOException ex) { - log.warn("Error reading exclude file '{}' for Instrument-The-World: ", fileName, ex); + LOGGER.warn("Error reading exclude file '{}' for Instrument-The-World: ", fileName, ex); } } } @@ -250,7 +250,7 @@ public byte[] transform( if (definitions.isEmpty()) { return null; } - log.debug("Matching definitions for class[{}]: {}", fullyQualifiedClassName, definitions); + LOGGER.debug("Matching definitions for class[{}]: {}", fullyQualifiedClassName, definitions); if (!instrumentationIsAllowed(fullyQualifiedClassName, definitions)) { return null; } @@ -260,14 +260,14 @@ public byte[] transform( if (transformed) { return writeClassFile(definitions, loader, classFilePath, classNode); } - // This is an info log because in case of SourceFile definition and multiple top-level + // We are logging this because in case of SourceFile definition and multiple top-level // classes, type may match, but there is one classfile per top-level class so source file // will match, but not the classfile. // e.g. Main.java contains Main & TopLevel class, line numbers are in TopLevel class - log.info( + LOGGER.debug( "type {} matched but no transformation for definitions: {}", classFilePath, definitions); } catch (Throwable ex) { - log.warn("Cannot transform: ", ex); + LOGGER.warn("Cannot transform: ", ex); reportInstrumentationFails(definitions, fullyQualifiedClassName); } return null; @@ -275,7 +275,7 @@ public byte[] transform( private boolean skipInstrumentation(ClassLoader loader, String classFilePath) { if (definitionMatcher.isEmpty()) { - log.debug("No debugger definitions present."); + LOGGER.debug("No debugger definitions present."); return true; } if (classFilePath == null) { @@ -311,7 +311,7 @@ private byte[] transformTheWorld( location = codeSource.getLocation(); } } - log.debug( + LOGGER.debug( "Parsing class '{}' {}B loaded from loader='{}' location={}", classFilePath, classfileBuffer.length, @@ -320,7 +320,7 @@ private byte[] transformTheWorld( ClassNode classNode = parseClassFile(classFilePath, classfileBuffer); if (isClassLoaderRelated(classNode)) { // Skip ClassLoader classes - log.debug("Skipping ClassLoader class: {}", classFilePath); + LOGGER.debug("Skipping ClassLoader class: {}", classFilePath); excludeClasses.add(classFilePath); return null; } @@ -337,10 +337,10 @@ private byte[] transformTheWorld( if (transformed) { return writeClassFile(probes, loader, classFilePath, classNode); } else { - log.debug("Class not transformed: {}", classFilePath); + LOGGER.debug("Class not transformed: {}", classFilePath); } } catch (Throwable ex) { - log.warn("Cannot transform: ", ex); + LOGGER.warn("Cannot transform: ", ex); writeToInstrumentationLog(classFilePath); } return null; @@ -354,7 +354,7 @@ private boolean isMethodIncludedForTransformation( } String fqnMethod = classNode.name + "::" + methodNode.name; if (excludeMethods.contains(fqnMethod)) { - log.debug("Skipping method: {}", fqnMethod); + LOGGER.debug("Skipping method: {}", fqnMethod); return false; } return methodNames.add(methodNode.name); @@ -404,7 +404,7 @@ private synchronized void writeToInstrumentationLog(String classFilePath) { writer.write(classFilePath); writer.write("\n"); } catch (Exception ex) { - log.warn("Cannot write to instrumentation.log", ex); + LOGGER.warn("Cannot write to instrumentation.log", ex); } } @@ -443,7 +443,7 @@ private boolean isIncludedForTransformation(String classFilePath) { private boolean instrumentationIsAllowed( String fullyQualifiedClassName, List definitions) { if (denyListHelper.isDenied(fullyQualifiedClassName)) { - log.info("Instrumentation denied for {}", fullyQualifiedClassName); + LOGGER.debug("Instrumentation denied for {}", fullyQualifiedClassName); InstrumentationResult result = InstrumentationResult.Factory.blocked( fullyQualifiedClassName, @@ -455,7 +455,7 @@ private boolean instrumentationIsAllowed( return false; } if (!allowListHelper.isAllowAll() && !allowListHelper.isAllowed(fullyQualifiedClassName)) { - log.info("Instrumentation not allowed for {}", fullyQualifiedClassName); + LOGGER.debug("Instrumentation not allowed for {}", fullyQualifiedClassName); InstrumentationResult result = InstrumentationResult.Factory.blocked( fullyQualifiedClassName, @@ -487,11 +487,11 @@ private byte[] writeClassFile( classNode.version = Opcodes.V1_8; } ClassWriter writer = new SafeClassWriter(loader); - log.debug("Generating bytecode for class: {}", Strings.getClassName(classFilePath)); + LOGGER.debug("Generating bytecode for class: {}", Strings.getClassName(classFilePath)); try { classNode.accept(writer); } catch (Throwable t) { - log.error("Cannot write classfile for class: {} Exception: ", classFilePath, t); + LOGGER.error("Cannot write classfile for class: {} Exception: ", classFilePath, t); reportInstrumentationFails(definitions, Strings.getClassName(classFilePath)); return null; } @@ -526,8 +526,8 @@ private void verifyByteCode(String classFilePath, byte[] classFile) { printWriter.flush(); String result = stringWriter.toString(); if (!result.isEmpty()) { - log.warn("Verification of instrumented class {} failed", classFilePath); - log.debug("Verify result: {}", stringWriter); + LOGGER.warn("Verification of instrumented class {} failed", classFilePath); + LOGGER.debug("Verify result: {}", stringWriter); throw new RuntimeException("Generated bytecode is invalid for " + classFilePath); } } @@ -560,9 +560,9 @@ private boolean performInstrumentation( if (matchingDefs.isEmpty()) { continue; } - if (log.isDebugEnabled()) { + if (LOGGER.isDebugEnabled()) { List probeIds = matchingDefs.stream().map(ProbeDefinition::getId).collect(toList()); - log.debug( + LOGGER.debug( "Instrumenting method: {}.{}{} for probe ids: {}", fullyQualifiedClassName, methodNode.name, @@ -627,7 +627,7 @@ private void reportErrorForAllProbes(List definitions, String m private void addDiagnostics( ProbeDefinition definition, List diagnosticMessages) { debuggerSink.addDiagnostics(definition.getProbeId(), diagnosticMessages); - log.debug("Diagnostic messages for definition[{}]: {}", definition, diagnosticMessages); + LOGGER.debug("Diagnostic messages for definition[{}]: {}", definition, diagnosticMessages); } private void notifyBlockedDefinitions( @@ -658,7 +658,7 @@ private InstrumentationResult applyInstrumentation( status = definition.instrument(methodInfo, probeDiagnostics, toInstrumentInfo.probeIds); } } catch (Throwable t) { - log.warn("Exception during instrumentation: ", t); + LOGGER.warn("Exception during instrumentation: ", t); status = InstrumentationResult.Status.ERROR; addDiagnosticForAllProbes( new DiagnosticMessage(DiagnosticMessage.Kind.ERROR, t), diagnostics); @@ -694,7 +694,7 @@ private List filterAndSortDefinitions( // and therefore need to be instrumented once // note: exception probes are log probes and are handled the same way if (!Config.get().isDistributedDebuggerEnabled() && definition instanceof TriggerProbe) { - log.debug( + LOGGER.debug( "The distributed debugger feature is disabled. Trigger probes will not be installed."); } else if (isCapturedContextProbe(definition)) { if (definition.isLineProbe()) { @@ -871,7 +871,7 @@ private List matchMethodDescription( } } } catch (Exception ex) { - log.warn("Cannot match method: {}", ex.toString()); + LOGGER.warn("Cannot match method: {}", ex.toString()); } return result; } @@ -888,22 +888,22 @@ private MethodNode matchSourceFile( if (matchingMethods != null) { matchingMethods.forEach( methodNode -> { - log.debug("Found lineNode {} method: {}", matchingLine, methodNode.name); + LOGGER.debug("Found lineNode {} method: {}", matchingLine, methodNode.name); }); // pick the first matching method. // TODO need a way to disambiguate if multiple methods match the same line return matchingMethods.isEmpty() ? null : matchingMethods.get(0); } - log.debug("Cannot find line: {} in class {}", matchingLine, classNode.name); + LOGGER.debug("Cannot find line: {} in class {}", matchingLine, classNode.name); return null; } private void dumpInstrumentedClassFile(String className, byte[] data) { if (config.isDynamicInstrumentationClassFileDumpEnabled()) { - log.debug("Generated bytecode len: {}", data.length); + LOGGER.debug("Generated bytecode len: {}", data.length); Path classFilePath = dumpClassFile(className, data); if (classFilePath != null) { - log.debug("Instrumented class saved as: {}", classFilePath.toString()); + LOGGER.debug("Instrumented class saved as: {}", classFilePath.toString()); } } } @@ -912,7 +912,7 @@ private void dumpOriginalClassFile(String className, byte[] classfileBuffer) { if (config.isDynamicInstrumentationClassFileDumpEnabled()) { Path classFilePath = dumpClassFile(className + "_orig", classfileBuffer); if (classFilePath != null) { - log.debug("Original class saved as: {}", classFilePath.toString()); + LOGGER.debug("Original class saved as: {}", classFilePath.toString()); } } } @@ -924,7 +924,7 @@ private static Path dumpClassFile(String className, byte[] classfileBuffer) { Files.write(classFilePath, classfileBuffer, StandardOpenOption.CREATE); return classFilePath; } catch (IOException e) { - log.error("", e); + LOGGER.error("", e); return null; } } @@ -981,7 +981,7 @@ protected String getCommonSuperClass(String type1, String type2) { } return common.getInternalName(); } catch (Exception ex) { - ExceptionHelper.logException(log, ex, "getCommonSuperClass failed: "); + ExceptionHelper.logException(LOGGER, ex, "getCommonSuperClass failed: "); return tpDatadogClassLoader.describe("java.lang.Object").resolve().getInternalName(); } } diff --git a/dd-java-agent/agent-debugger/src/main/java/com/datadog/debugger/codeorigin/DefaultCodeOriginRecorder.java b/dd-java-agent/agent-debugger/src/main/java/com/datadog/debugger/codeorigin/DefaultCodeOriginRecorder.java index aa99436c500..0b6d0c7b75f 100644 --- a/dd-java-agent/agent-debugger/src/main/java/com/datadog/debugger/codeorigin/DefaultCodeOriginRecorder.java +++ b/dd-java-agent/agent-debugger/src/main/java/com/datadog/debugger/codeorigin/DefaultCodeOriginRecorder.java @@ -60,6 +60,10 @@ public DefaultCodeOriginRecorder( @Override public String captureCodeOrigin(boolean entry) { + if (!entry) { + LOG.debug("Not capturing code origin for exit"); + return null; + } StackTraceElement element = findPlaceInStack(); String fingerprint = Fingerprinter.fingerprint(element); CodeOriginProbe probe = probesByFingerprint.get(fingerprint); From 1da7f4a81b71be03759c97b9e59c43804acf74ec Mon Sep 17 00:00:00 2001 From: jean-philippe bempel Date: Mon, 22 Sep 2025 16:04:17 +0200 Subject: [PATCH 2/3] fix test --- .../test/java/com/datadog/debugger/origin/CodeOriginTest.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/dd-java-agent/agent-debugger/src/test/java/com/datadog/debugger/origin/CodeOriginTest.java b/dd-java-agent/agent-debugger/src/test/java/com/datadog/debugger/origin/CodeOriginTest.java index 847cb293de1..61af2573ca9 100644 --- a/dd-java-agent/agent-debugger/src/test/java/com/datadog/debugger/origin/CodeOriginTest.java +++ b/dd-java-agent/agent-debugger/src/test/java/com/datadog/debugger/origin/CodeOriginTest.java @@ -56,6 +56,7 @@ import org.jetbrains.annotations.NotNull; import org.joor.Reflect; import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Disabled; import org.junit.jupiter.api.Test; public class CodeOriginTest extends CapturingTestBase { @@ -212,6 +213,7 @@ public void testCaptureCodeOriginEntry() { } @Test + @Disabled("Exit spans are disabled for now") public void testCaptureCodeOriginExit() { installProbes(); CodeOriginProbe probe = From 80de4c13b6687a442a61785f3aa232e36c6890f2 Mon Sep 17 00:00:00 2001 From: jean-philippe bempel Date: Mon, 22 Sep 2025 17:32:46 +0200 Subject: [PATCH 3/3] fix smoke test --- .../java/datadog/smoketest/debugger/TestApplicationHelper.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dd-smoke-tests/debugger-integration-tests/src/main/java/datadog/smoketest/debugger/TestApplicationHelper.java b/dd-smoke-tests/debugger-integration-tests/src/main/java/datadog/smoketest/debugger/TestApplicationHelper.java index b69e697b704..cf624566947 100644 --- a/dd-smoke-tests/debugger-integration-tests/src/main/java/datadog/smoketest/debugger/TestApplicationHelper.java +++ b/dd-smoke-tests/debugger-integration-tests/src/main/java/datadog/smoketest/debugger/TestApplicationHelper.java @@ -20,7 +20,7 @@ public class TestApplicationHelper { private static final String INSTRUMENTATION_DONE_TASK_THREAD = "[dd-task-scheduler] DEBUG com.datadog.debugger.agent.DebuggerTransformer - Generating bytecode for class: %s"; private static final String RENTRANSFORMATION_CLASS = - "[dd-remote-config] INFO com.datadog.debugger.agent.ConfigurationUpdater - Re-transforming class: %s"; + "[dd-remote-config] DEBUG com.datadog.debugger.agent.ConfigurationUpdater - Re-transforming class: %s"; private static final String RETRANSFORMATION_DONE = "com.datadog.debugger.agent.ConfigurationUpdater - Re-transformation done"; private static final long SLEEP_MS = 100;