diff --git a/dd-java-agent/agent-debugger/debugger-bootstrap/src/main/java/datadog/trace/bootstrap/debugger/DebuggerContext.java b/dd-java-agent/agent-debugger/debugger-bootstrap/src/main/java/datadog/trace/bootstrap/debugger/DebuggerContext.java index c524f065557..e5a6926baab 100644 --- a/dd-java-agent/agent-debugger/debugger-bootstrap/src/main/java/datadog/trace/bootstrap/debugger/DebuggerContext.java +++ b/dd-java-agent/agent-debugger/debugger-bootstrap/src/main/java/datadog/trace/bootstrap/debugger/DebuggerContext.java @@ -116,7 +116,7 @@ public interface ExceptionDebugger { public interface CodeOriginRecorder { String captureCodeOrigin(boolean entry); - String captureCodeOrigin(Method method, boolean entry, boolean instrument); + String captureCodeOrigin(Method method, boolean entry); } private static volatile ProductConfigUpdater productConfigUpdater; @@ -466,32 +466,28 @@ public static void commit( } } - public static String captureCodeOrigin(boolean entry) { + public static void marker() {} + + public static void captureCodeOrigin(boolean entry) { try { CodeOriginRecorder recorder = codeOriginRecorder; if (recorder != null) { - return recorder.captureCodeOrigin(entry); + recorder.captureCodeOrigin(entry); } } catch (Exception ex) { LOGGER.debug("Error in captureCodeOrigin: ", ex); } - return null; - } - - public static String captureCodeOrigin(Method method, boolean entry) { - return captureCodeOrigin(method, entry, true); } - public static String captureCodeOrigin(Method method, boolean entry, boolean instrument) { + public static void captureCodeOrigin(Method method, boolean entry) { try { CodeOriginRecorder recorder = codeOriginRecorder; if (recorder != null) { - return recorder.captureCodeOrigin(method, entry, instrument); + recorder.captureCodeOrigin(method, entry); } } catch (Exception ex) { LOGGER.debug("Error in captureCodeOrigin: ", ex); } - return null; } public static void handleException(Throwable t, AgentSpan span) { diff --git a/dd-java-agent/agent-debugger/debugger-bootstrap/src/main/java/datadog/trace/bootstrap/debugger/spanorigin/CodeOriginInfo.java b/dd-java-agent/agent-debugger/debugger-bootstrap/src/main/java/datadog/trace/bootstrap/debugger/spanorigin/CodeOriginInfo.java deleted file mode 100644 index f3b6b00ae8a..00000000000 --- a/dd-java-agent/agent-debugger/debugger-bootstrap/src/main/java/datadog/trace/bootstrap/debugger/spanorigin/CodeOriginInfo.java +++ /dev/null @@ -1,24 +0,0 @@ -package datadog.trace.bootstrap.debugger.spanorigin; - -import static datadog.trace.bootstrap.debugger.DebuggerContext.captureCodeOrigin; - -import datadog.trace.api.InstrumenterConfig; -import datadog.trace.bootstrap.instrumentation.api.AgentSpan; -import java.lang.reflect.Method; - -public class CodeOriginInfo { - public static void entry(Method method) { - if (InstrumenterConfig.get().isCodeOriginEnabled()) { - captureCodeOrigin(method, true); - } - } - - public static void exit(AgentSpan span) { - if (InstrumenterConfig.get().isCodeOriginEnabled()) { - String probeId = captureCodeOrigin(false); - if (span != null) { - span.getLocalRootSpan().setTag(probeId, span); - } - } - } -} 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 b4395555d56..0da75769f80 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 @@ -45,7 +45,7 @@ public class DefaultCodeOriginRecorder implements CodeOriginRecorder { private final int maxUserFrames; - private AgentTaskScheduler scheduler = AgentTaskScheduler.INSTANCE; + private AgentTaskScheduler scheduler; public DefaultCodeOriginRecorder(Config config, ConfigurationUpdater configurationUpdater) { this(config, configurationUpdater, AgentTaskScheduler.INSTANCE); @@ -70,7 +70,7 @@ public String captureCodeOrigin(boolean entry) { element.getMethodName(), null, String.valueOf(element.getLineNumber())); - probe = createProbe(fingerprint, entry, where, true); + probe = createProbe(fingerprint, entry, where); LOG.debug("Creating probe for location {}", where); } @@ -78,43 +78,36 @@ public String captureCodeOrigin(boolean entry) { } @Override - public String captureCodeOrigin(Method method, boolean entry, boolean instrument) { + public String captureCodeOrigin(Method method, boolean entry) { String fingerprint = method.toString(); CodeOriginProbe probe = probesByFingerprint.get(fingerprint); if (probe == null) { - probe = createProbe(fingerprint, entry, Where.of(method), instrument); + probe = createProbe(fingerprint, entry, Where.of(method)); LOG.debug("Creating probe for method {}", fingerprint); - } else if (!instrument) { - // direct call to fill code origin info without using probe instrumentation - // buildLocation should be called before in order to gather location info - probe.commit( - CapturedContext.EMPTY_CONTEXT, CapturedContext.EMPTY_CONTEXT, Collections.emptyList()); } return probe.getId(); } public void registerLogProbe(CodeOriginProbe probe) { - LogProbe logProbe = - logProbes.computeIfAbsent( - probe.getId(), - key -> - new Builder() - .language(probe.getLanguage()) - .probeId(ProbeId.newId()) - .where(probe.getWhere()) - .evaluateAt(probe.getEvaluateAt()) - .captureSnapshot(true) - .tags("session_id:*") - .snapshotProcessor(new CodeOriginSnapshotConsumer(probe.entrySpanProbe())) - .build()); + logProbes.computeIfAbsent( + probe.getId(), + key -> + new Builder() + .language(probe.getLanguage()) + .probeId(ProbeId.newId()) + .where(probe.getWhere()) + .evaluateAt(probe.getEvaluateAt()) + .captureSnapshot(true) + .tags("session_id:*") + .snapshotProcessor(new CodeOriginSnapshotConsumer(probe.entrySpanProbe())) + .build()); } - private CodeOriginProbe createProbe( - String fingerPrint, boolean entry, Where where, boolean instrument) { + private CodeOriginProbe createProbe(String fingerPrint, boolean entry, Where where) { CodeOriginProbe probe; AgentSpan span = AgentTracer.activeSpan(); - probe = new CodeOriginProbe(ProbeId.newId(), entry, where, instrument); + probe = new CodeOriginProbe(ProbeId.newId(), entry, where); addFingerprint(fingerPrint, probe); CodeOriginProbe installed = probes.putIfAbsent(probe.getId(), probe); diff --git a/dd-java-agent/agent-debugger/src/main/java/com/datadog/debugger/instrumentation/ASMHelper.java b/dd-java-agent/agent-debugger/src/main/java/com/datadog/debugger/instrumentation/ASMHelper.java index 885e0c4dd31..f811ab41710 100644 --- a/dd-java-agent/agent-debugger/src/main/java/com/datadog/debugger/instrumentation/ASMHelper.java +++ b/dd-java-agent/agent-debugger/src/main/java/com/datadog/debugger/instrumentation/ASMHelper.java @@ -1,20 +1,29 @@ package com.datadog.debugger.instrumentation; import static com.datadog.debugger.instrumentation.Types.REFLECTIVE_FIELD_VALUE_RESOLVER_TYPE; +import static java.lang.String.format; import static org.objectweb.asm.Type.getMethodDescriptor; import static org.objectweb.asm.Type.getObjectType; import com.datadog.debugger.agent.Generated; import datadog.trace.util.Strings; +import de.thetaphi.forbiddenapis.SuppressForbidden; +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.PrintWriter; +import java.io.StringWriter; import java.lang.reflect.Field; import java.lang.reflect.Modifier; import java.util.ArrayList; +import java.util.Arrays; import java.util.Collections; import java.util.Comparator; import java.util.List; +import java.util.StringJoiner; import java.util.stream.Collectors; +import org.objectweb.asm.ClassWriter; import org.objectweb.asm.Opcodes; -import org.objectweb.asm.Type; import org.objectweb.asm.signature.SignatureReader; import org.objectweb.asm.signature.SignatureVisitor; import org.objectweb.asm.tree.AbstractInsnNode; @@ -24,10 +33,14 @@ import org.objectweb.asm.tree.InsnList; import org.objectweb.asm.tree.InsnNode; import org.objectweb.asm.tree.LdcInsnNode; +import org.objectweb.asm.tree.LineNumberNode; import org.objectweb.asm.tree.LocalVariableNode; import org.objectweb.asm.tree.MethodInsnNode; import org.objectweb.asm.tree.MethodNode; import org.objectweb.asm.tree.TypeInsnNode; +import org.objectweb.asm.util.Printer; +import org.objectweb.asm.util.Textifier; +import org.objectweb.asm.util.TraceClassVisitor; /** Helper class for bytecode generation */ public class ASMHelper { @@ -36,6 +49,45 @@ public class ASMHelper { public static final Type STRING_TYPE = new Type(Types.STRING_TYPE); public static final Type LONG_TYPE = new Type(org.objectweb.asm.Type.LONG_TYPE); + public static void dumpMethod(ClassNode classNode, String method, String suffix) { + String content = extractMethod(classNode, method); + File output; + int count = 0; + do { + output = new File(format("build/%s-%d-%s.txt", method, count++, suffix)); + } while (output.exists()); + output.getParentFile().mkdirs(); + try (PrintWriter writer = new PrintWriter(output)) { + writer.println(content); + String absolutePath = output.getAbsolutePath(); + absolutePath = absolutePath.substring(0, absolutePath.lastIndexOf('.')); + absolutePath += ".class"; + ClassWriter classWriter = new ClassWriter(0); + classNode.accept(classWriter); + try (FileOutputStream stream = new FileOutputStream(absolutePath)) { + stream.write(classWriter.toByteArray()); + } + } catch (IOException e) { + throw new RuntimeException(e); + } + } + + @SuppressForbidden + static String extractMethod(ClassNode classNode, String method) { + StringJoiner joiner = new StringJoiner("\n"); + joiner.add("Class: " + classNode.name); + StringWriter writer = new StringWriter(); + classNode.accept(new TraceClassVisitor(null, new Textifier(), new PrintWriter(writer))); + List strings = Arrays.asList(writer.toString().split("\n")); + for (int i = 0; i < strings.size(); i++) { + if (strings.get(i).matches(format(".*(private|public).* %s\\(.*", method))) { + while (!strings.get(i).equals("")) + joiner.add(String.format("[%3d] %s", i, strings.get(i++))); + } + } + return joiner.toString(); + } + public static void invokeInterface( InsnList insnList, org.objectweb.asm.Type owner, @@ -322,6 +374,18 @@ public static boolean isStoreCompatibleType( return previousSort == currentSort; } + public static String toString(AbstractInsnNode node) { + String opcode = node.getOpcode() >= 0 ? Printer.OPCODES[node.getOpcode()] : node.toString(); + if (node instanceof LineNumberNode) { + return String.format("LineNumber: %s", ((LineNumberNode) node).line); + } else if (node instanceof MethodInsnNode) { + MethodInsnNode method = (MethodInsnNode) node; + return String.format("%s: [%s] %s", opcode, method.name, method.desc); + } else { + return opcode; + } + } + private static int widenIntType(int sort) { switch (sort) { case org.objectweb.asm.Type.BOOLEAN: diff --git a/dd-java-agent/agent-debugger/src/main/java/com/datadog/debugger/instrumentation/CodeOriginInstrumentor.java b/dd-java-agent/agent-debugger/src/main/java/com/datadog/debugger/instrumentation/CodeOriginInstrumentor.java index 0a4503392e5..4ef2a5a4c63 100644 --- a/dd-java-agent/agent-debugger/src/main/java/com/datadog/debugger/instrumentation/CodeOriginInstrumentor.java +++ b/dd-java-agent/agent-debugger/src/main/java/com/datadog/debugger/instrumentation/CodeOriginInstrumentor.java @@ -5,35 +5,90 @@ import static com.datadog.debugger.instrumentation.Types.DEBUGGER_CONTEXT_TYPE; import static com.datadog.debugger.instrumentation.Types.STRING_TYPE; import static java.lang.Integer.parseInt; +import static java.lang.String.format; import com.datadog.debugger.instrumentation.InstrumentationResult.Status; import com.datadog.debugger.probe.CodeOriginProbe; import com.datadog.debugger.probe.ProbeDefinition; +import datadog.trace.bootstrap.debugger.DebuggerContext; import datadog.trace.bootstrap.debugger.ProbeId; import java.util.List; +import java.util.ListIterator; import org.objectweb.asm.Type; import org.objectweb.asm.tree.AbstractInsnNode; import org.objectweb.asm.tree.InsnList; import org.objectweb.asm.tree.LabelNode; +import org.objectweb.asm.tree.LineNumberNode; +import org.objectweb.asm.tree.MethodInsnNode; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; public class CodeOriginInstrumentor extends Instrumentor { + private static final String CAPTURE; + private static final String MARKER; + private static final Logger LOGGER = LoggerFactory.getLogger(CodeOriginInstrumentor.class); + + static { + String className = DebuggerContext.class.getName().replace('.', '/'); + CAPTURE = format("%s#%s", className, "captureCodeOrigin"); + MARKER = format("%s#%s", className, "marker"); + } + public CodeOriginInstrumentor( - ProbeDefinition definition, - MethodInfo methodInfo, - List diagnostics, - List probeIds) { - super(definition, methodInfo, diagnostics, probeIds); + ProbeDefinition definition, MethodInfo methodInfo, List probeIds) { + super(definition, methodInfo, null, probeIds); } @Override public Status instrument() { - InsnList insnList = new InsnList(); + AbstractInsnNode insertionPoint = stripSetup(); + methodNode.instructions.insert( + insertionPoint != null ? insertionPoint : findInsertionPoint(), codeOriginCall()); + return Status.INSTALLED; + } + + private static String buildDescription(AbstractInsnNode node) { + if (!(node instanceof MethodInsnNode)) return ""; + MethodInsnNode method = (MethodInsnNode) node; + return format("%s#%s", method.owner, method.name); + } + + private InsnList codeOriginCall() { + InsnList insnList = new InsnList(); ldc(insnList, probeIds.get(0).getEncodedId()); invokeStatic(insnList, DEBUGGER_CONTEXT_TYPE, "codeOrigin", Type.VOID_TYPE, STRING_TYPE); - methodNode.instructions.insert(findInsertionPoint(), insnList); + return insnList; + } - return InstrumentationResult.Status.INSTALLED; + private AbstractInsnNode stripSetup() { + try { + ListIterator iterator = methodNode.instructions.iterator(); + AbstractInsnNode insertionPoint = null; + InsnList list = new InsnList(); + while (iterator.hasNext()) { + AbstractInsnNode next = iterator.next(); + if (buildDescription(next).equals(MARKER)) { + insertionPoint = next.getPrevious(); + while (iterator.hasNext() && !buildDescription(next = iterator.next()).equals(CAPTURE)) { + if (next instanceof LineNumberNode || next instanceof LabelNode) { + list.add(next); + } + } + + if (!iterator.hasNext()) { + return null; + } + } else { + list.add(next); + } + } + methodNode.instructions = list; + return insertionPoint; + } catch (Exception e) { + LOGGER.debug("Error in captureCodeOrigin: ", e); + return null; + } } private AbstractInsnNode findInsertionPoint() { diff --git a/dd-java-agent/agent-debugger/src/main/java/com/datadog/debugger/probe/CodeOriginProbe.java b/dd-java-agent/agent-debugger/src/main/java/com/datadog/debugger/probe/CodeOriginProbe.java index 1a5da90893e..633c8748f23 100644 --- a/dd-java-agent/agent-debugger/src/main/java/com/datadog/debugger/probe/CodeOriginProbe.java +++ b/dd-java-agent/agent-debugger/src/main/java/com/datadog/debugger/probe/CodeOriginProbe.java @@ -26,23 +26,18 @@ public class CodeOriginProbe extends ProbeDefinition { private static final Logger LOGGER = LoggerFactory.getLogger(CodeOriginProbe.class); - private final boolean instrument; private final boolean entrySpanProbe; private String signature; - public CodeOriginProbe(ProbeId probeId, boolean entry, Where where, boolean instrument) { + public CodeOriginProbe(ProbeId probeId, boolean entry, Where where) { super(LANGUAGE, probeId, (Tag[]) null, where, MethodLocation.ENTRY); - this.instrument = instrument; this.entrySpanProbe = entry; } @Override public Status instrument( MethodInfo methodInfo, List diagnostics, List probeIds) { - if (instrument) { - return new CodeOriginInstrumentor(this, methodInfo, diagnostics, probeIds).instrument(); - } - return Status.INSTALLED; + return new CodeOriginInstrumentor(this, methodInfo, probeIds).instrument(); } @Override diff --git a/dd-java-agent/agent-debugger/src/test/java/com/datadog/debugger/origin/CodeOrigin.java b/dd-java-agent/agent-debugger/src/test/java/com/datadog/debugger/origin/CodeOrigin.java new file mode 100644 index 00000000000..cc0dc4c8f8d --- /dev/null +++ b/dd-java-agent/agent-debugger/src/test/java/com/datadog/debugger/origin/CodeOrigin.java @@ -0,0 +1,7 @@ +package com.datadog.debugger.origin; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Target; + +@Target(ElementType.METHOD) +public @interface CodeOrigin {} 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 31ac161c0ff..847cb293de1 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 @@ -7,6 +7,9 @@ import static datadog.trace.util.AgentThreadFactory.AgentThread.TASK_SCHEDULER; import static java.lang.String.format; import static java.util.Arrays.asList; +import static net.bytebuddy.matcher.ElementMatchers.isAnnotatedWith; +import static net.bytebuddy.matcher.ElementMatchers.isMethod; +import static net.bytebuddy.matcher.ElementMatchers.nameStartsWith; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertFalse; import static org.junit.jupiter.api.Assertions.assertNotEquals; @@ -44,6 +47,12 @@ import java.util.Set; import java.util.TreeSet; import java.util.stream.Collectors; +import net.bytebuddy.agent.builder.AgentBuilder; +import net.bytebuddy.agent.builder.AgentBuilder.InitializationStrategy; +import net.bytebuddy.agent.builder.AgentBuilder.RedefinitionStrategy; +import net.bytebuddy.agent.builder.AgentBuilder.TypeStrategy; +import net.bytebuddy.asm.Advice; +import net.bytebuddy.matcher.ElementMatcher.Junction.Conjunction; import org.jetbrains.annotations.NotNull; import org.joor.Reflect; import org.junit.jupiter.api.BeforeEach; @@ -92,7 +101,21 @@ public void before() { setFieldInConfig(Config.get(), "debuggerCodeOriginEnabled", true); setFieldInConfig(Config.get(), "distributedDebuggerEnabled", true); + setFieldInConfig(Config.get(), "dynamicInstrumentationClassFileDumpEnabled", true); setFieldInConfig(InstrumenterConfig.get(), "codeOriginEnabled", true); + + new AgentBuilder.Default() + .with(RedefinitionStrategy.RETRANSFORMATION) + .with(InitializationStrategy.NoOp.INSTANCE) + .with(TypeStrategy.Default.REDEFINE) + .type(nameStartsWith("com.datadog.debugger.")) + .transform( + (builder, typeDescription, classLoader, module, protectionDomain) -> + builder.visit( + Advice.to(CodeOriginTestAdvice.class) + .on(new Conjunction<>(isMethod(), isAnnotatedWith(CodeOrigin.class))))) + // .installOn(instr) + ; } @Test @@ -109,8 +132,8 @@ public void withDebug1() throws Exception { final String className = "com.datadog.debugger.CodeOrigin02"; installProbes(); final Class testClass = compileAndLoadClass(className); - codeOriginRecorder.captureCodeOrigin(testClass.getMethod("entry"), true, true); - codeOriginRecorder.captureCodeOrigin(testClass.getMethod("exit"), false, true); + codeOriginRecorder.captureCodeOrigin(testClass.getMethod("entry"), true); + codeOriginRecorder.captureCodeOrigin(testClass.getMethod("exit"), false); checkResults(testClass, "fullTrace", 0); checkResults(testClass, "debug_1", 2); } @@ -121,8 +144,8 @@ public void withLogProbe() throws Exception { installProbes( createProbeBuilder(PROBE_ID, CLASS_NAME, "entry", "()").captureSnapshot(true).build()); final Class testClass = compileAndLoadClass(CLASS_NAME); - codeOriginRecorder.captureCodeOrigin(testClass.getMethod("entry"), true, true); - codeOriginRecorder.captureCodeOrigin(testClass.getMethod("exit"), false, true); + codeOriginRecorder.captureCodeOrigin(testClass.getMethod("entry"), true); + codeOriginRecorder.captureCodeOrigin(testClass.getMethod("exit"), false); checkResults(testClass, "debug_1", 3); } @@ -135,13 +158,12 @@ public void doubleEntry() throws IOException, URISyntaxException { CODE_ORIGIN_ID1, true, Where.of( - className, "entry", "()", "" + getLineForLineProbe(className, CODE_ORIGIN_ID1)), - true), + className, "entry", "()", "" + getLineForLineProbe(className, CODE_ORIGIN_ID1))), new CodeOriginProbe( CODE_ORIGIN_ID2, false, - Where.of(className, "exit", "()", "" + getLineForLineProbe(className, CODE_ORIGIN_ID2)), - true), + Where.of( + className, "exit", "()", "" + getLineForLineProbe(className, CODE_ORIGIN_ID2))), new CodeOriginProbe( CODE_ORIGIN_DOUBLE_ENTRY_ID, true, @@ -149,8 +171,7 @@ public void doubleEntry() throws IOException, URISyntaxException { className, "doubleEntry", "()", - "" + getLineForLineProbe(className, CODE_ORIGIN_DOUBLE_ENTRY_ID)), - true)); + "" + getLineForLineProbe(className, CODE_ORIGIN_DOUBLE_ENTRY_ID)))); final Class testClass = compileAndLoadClass(className); checkResults(testClass, "fullTrace", 0); List trace = traceInterceptor.getTrace(); @@ -163,7 +184,7 @@ public void doubleEntry() throws IOException, URISyntaxException { public void stackDepth() throws IOException, URISyntaxException { final String CLASS_NAME = "com.datadog.debugger.CodeOrigin04"; installProbes( - new CodeOriginProbe(CODE_ORIGIN_ID1, true, Where.of(CLASS_NAME, "exit", "()", "39"), true)); + new CodeOriginProbe(CODE_ORIGIN_ID1, true, Where.of(CLASS_NAME, "exit", "()", "39"))); Class testClass = compileAndLoadClass("com.datadog.debugger.CodeOrigin04"); countFrames(testClass, 10); @@ -207,8 +228,7 @@ public void testCaptureCodeOriginWithExplicitInfo() installProbes(); CodeOriginProbe probe = codeOriginRecorder.getProbe( - codeOriginRecorder.captureCodeOrigin( - testClass.getMethod("main", int.class), true, true)); + codeOriginRecorder.captureCodeOrigin(testClass.getMethod("main", int.class), true)); assertNotNull(probe, "The probe should have been created."); assertTrue(probe.entrySpanProbe(), "Should be an entry probe."); } @@ -220,18 +240,20 @@ public void testDuplicateInstrumentations() final Class testClass = compileAndLoadClass(CLASS_NAME); installProbes(); String probe1 = - codeOriginRecorder.captureCodeOrigin(testClass.getMethod("main", int.class), true, true); + codeOriginRecorder.captureCodeOrigin(testClass.getMethod("main", int.class), true); String probe2 = - codeOriginRecorder.captureCodeOrigin(testClass.getMethod("main", int.class), true, true); + codeOriginRecorder.captureCodeOrigin(testClass.getMethod("main", int.class), true); assertEquals(probe1, probe2); } @NotNull - private CodeOriginProbe[] codeOriginProbes(String type) { + private static CodeOriginProbe[] codeOriginProbes(String type) { CodeOriginProbe entry = - new CodeOriginProbe(CODE_ORIGIN_ID1, true, Where.of(type, "entry", "()", "53"), true); + new CodeOriginProbe(CODE_ORIGIN_ID1, true, Where.of(type, "entry", "()", "53")); + + int line = getLineForLineProbe(type, CODE_ORIGIN_ID2); CodeOriginProbe exit = - new CodeOriginProbe(CODE_ORIGIN_ID2, false, Where.of(type, "exit", "()", "60"), true); + new CodeOriginProbe(CODE_ORIGIN_ID2, false, Where.of(type, "exit", "()", "" + line)); return new CodeOriginProbe[] {entry, exit}; } diff --git a/dd-java-agent/agent-debugger/src/test/java/com/datadog/debugger/origin/CodeOriginTestAdvice.java b/dd-java-agent/agent-debugger/src/test/java/com/datadog/debugger/origin/CodeOriginTestAdvice.java new file mode 100644 index 00000000000..ac130eb66a7 --- /dev/null +++ b/dd-java-agent/agent-debugger/src/test/java/com/datadog/debugger/origin/CodeOriginTestAdvice.java @@ -0,0 +1,17 @@ +package com.datadog.debugger.origin; + +import static datadog.trace.bootstrap.debugger.DebuggerContext.*; +import static datadog.trace.bootstrap.debugger.DebuggerContext.marker; + +import java.lang.reflect.Method; +import net.bytebuddy.asm.Advice; + +public class CodeOriginTestAdvice { + + @Advice.OnMethodEnter + @SuppressWarnings("bytebuddy-exception-suppression") + public static void onEnter(@Advice.Origin final Method method) { + marker(); + captureCodeOrigin(method, true); + } +} diff --git a/dd-java-agent/agent-debugger/src/test/java/utils/InstrumentationTestHelper.java b/dd-java-agent/agent-debugger/src/test/java/utils/InstrumentationTestHelper.java index 0308c60476d..99690c388f9 100644 --- a/dd-java-agent/agent-debugger/src/test/java/utils/InstrumentationTestHelper.java +++ b/dd-java-agent/agent-debugger/src/test/java/utils/InstrumentationTestHelper.java @@ -70,13 +70,11 @@ public static Class loadClassFromJar(String className, String jarFileName) return jarClassLoader.loadClass(className); } - public static int getLineForLineProbe(String className, ProbeId lineProbeId) - throws IOException, URISyntaxException { + public static int getLineForLineProbe(String className, ProbeId lineProbeId) { return getLineForLineProbe(className, ".java", lineProbeId); } - public static int getLineForLineProbe(String className, String ext, ProbeId lineProbeId) - throws IOException, URISyntaxException { + public static int getLineForLineProbe(String className, String ext, ProbeId lineProbeId) { List lines = getFixtureLines("/" + className.replace('.', '/') + ext); for (int i = 0; i < lines.size(); i++) { String line = lines.get(i); diff --git a/dd-java-agent/agent-debugger/src/test/java/utils/TestHelper.java b/dd-java-agent/agent-debugger/src/test/java/utils/TestHelper.java index 18e01f43ee2..364bf4b10c9 100644 --- a/dd-java-agent/agent-debugger/src/test/java/utils/TestHelper.java +++ b/dd-java-agent/agent-debugger/src/test/java/utils/TestHelper.java @@ -17,9 +17,12 @@ public static String getFixtureContent(String fixture) throws IOException, URISy return new String(Files.readAllBytes(Paths.get(TestHelper.class.getResource(fixture).toURI()))); } - public static List getFixtureLines(String fixture) - throws IOException, URISyntaxException { - return Files.readAllLines(Paths.get(TestHelper.class.getResource(fixture).toURI())); + public static List getFixtureLines(String fixture) { + try { + return Files.readAllLines(Paths.get(TestHelper.class.getResource(fixture).toURI())); + } catch (Exception e) { + throw new RuntimeException(e.getMessage(), e); + } } public static void setFieldInConfig(Object target, String fieldName, Object value) { diff --git a/dd-java-agent/agent-debugger/src/test/resources/com/datadog/debugger/CodeOrigin01.java b/dd-java-agent/agent-debugger/src/test/resources/com/datadog/debugger/CodeOrigin01.java index e848e4ba841..da4befebfd2 100644 --- a/dd-java-agent/agent-debugger/src/test/resources/com/datadog/debugger/CodeOrigin01.java +++ b/dd-java-agent/agent-debugger/src/test/resources/com/datadog/debugger/CodeOrigin01.java @@ -1,12 +1,16 @@ package com.datadog.debugger; -import datadog.trace.bootstrap.debugger.spanorigin.CodeOriginInfo; +import com.datadog.debugger.origin.CodeOrigin; +import datadog.trace.bootstrap.debugger.DebuggerContext; import datadog.trace.bootstrap.instrumentation.api.AgentScope; import datadog.trace.bootstrap.instrumentation.api.AgentSpan; import datadog.trace.bootstrap.instrumentation.api.AgentTracer; import datadog.trace.bootstrap.instrumentation.api.AgentTracer.TracerAPI; import datadog.trace.core.DDSpan; +import static datadog.trace.bootstrap.debugger.DebuggerContext.*; +import static datadog.trace.bootstrap.debugger.DebuggerContext.marker; + public class CodeOrigin01 { private int intField = 42; @@ -15,6 +19,8 @@ public class CodeOrigin01 { public static int main(String arg) throws ReflectiveOperationException { AgentSpan span = newSpan("main"); AgentScope scope = tracerAPI.activateManualSpan(span); + marker(); + captureCodeOrigin(CodeOrigin01.class.getDeclaredMethod("main", String.class), true); if (arg.equals("debug_1")) { ((DDSpan) span.getLocalRootSpan()).setTag("_dd.p.debug", "1"); } else if (arg.equals("debug_0")) { @@ -29,7 +35,8 @@ public static int main(String arg) throws ReflectiveOperationException { return 0; } - private static void fullTrace() throws NoSuchMethodException { + @CodeOrigin + public static void fullTrace() throws NoSuchMethodException { AgentSpan span = newSpan("entry"); AgentScope scope = tracerAPI.activateManualSpan(span); entry(); @@ -47,6 +54,7 @@ private static AgentSpan newSpan(String name) { return tracerAPI.buildSpan("code origin tests", name).start(); } + @CodeOrigin public static void entry() throws NoSuchMethodException { // just to fill out the method body boolean dummyCode = true; @@ -55,8 +63,9 @@ public static void entry() throws NoSuchMethodException { } } + @CodeOrigin private static void exit() { - int x = 47 / 3; + int x = 47 / 3; // code origin 2 } } diff --git a/dd-java-agent/agent-debugger/src/test/resources/com/datadog/debugger/CodeOrigin02.java b/dd-java-agent/agent-debugger/src/test/resources/com/datadog/debugger/CodeOrigin02.java index 8e277b02605..0858edd5d34 100644 --- a/dd-java-agent/agent-debugger/src/test/resources/com/datadog/debugger/CodeOrigin02.java +++ b/dd-java-agent/agent-debugger/src/test/resources/com/datadog/debugger/CodeOrigin02.java @@ -1,6 +1,6 @@ package com.datadog.debugger; -import datadog.trace.bootstrap.debugger.spanorigin.CodeOriginInfo; +import datadog.trace.bootstrap.debugger.DebuggerContext; import datadog.trace.bootstrap.instrumentation.api.AgentScope; import datadog.trace.bootstrap.instrumentation.api.AgentSpan; import datadog.trace.bootstrap.instrumentation.api.AgentTracer; @@ -56,7 +56,7 @@ public static void entry() throws NoSuchMethodException { } public static void exit() { - int x = 47 / 3; + int x = 47 / 3; // code origin 2 } } diff --git a/dd-java-agent/agent-debugger/src/test/resources/com/datadog/debugger/CodeOrigin03.java b/dd-java-agent/agent-debugger/src/test/resources/com/datadog/debugger/CodeOrigin03.java index a256bb51050..42d2949694e 100644 --- a/dd-java-agent/agent-debugger/src/test/resources/com/datadog/debugger/CodeOrigin03.java +++ b/dd-java-agent/agent-debugger/src/test/resources/com/datadog/debugger/CodeOrigin03.java @@ -1,12 +1,14 @@ package com.datadog.debugger; -import datadog.trace.bootstrap.debugger.spanorigin.CodeOriginInfo; +import datadog.trace.bootstrap.debugger.DebuggerContext; import datadog.trace.bootstrap.instrumentation.api.AgentScope; import datadog.trace.bootstrap.instrumentation.api.AgentSpan; import datadog.trace.bootstrap.instrumentation.api.AgentTracer; import datadog.trace.bootstrap.instrumentation.api.AgentTracer.TracerAPI; import datadog.trace.core.DDSpan; +import static datadog.trace.bootstrap.debugger.DebuggerContext.marker; + public class CodeOrigin03 { private int intField = 42; @@ -32,6 +34,8 @@ public static int main(String arg) throws ReflectiveOperationException { private static void fullTrace() throws NoSuchMethodException { AgentSpan span = newSpan("entry"); AgentScope scope = tracerAPI.activateManualSpan(span); + marker(); + DebuggerContext.captureCodeOrigin(true); entry(); span.finish(); scope.close(); @@ -56,7 +60,7 @@ public static void entry() throws NoSuchMethodException { } public static void exit() { - int x = 47 / 3; + int x = 47 / 3; // code origin 2 } } diff --git a/dd-java-agent/agent-debugger/src/test/resources/com/datadog/debugger/CodeOrigin04.java b/dd-java-agent/agent-debugger/src/test/resources/com/datadog/debugger/CodeOrigin04.java index 7cabe4231a1..ad67ae8341e 100644 --- a/dd-java-agent/agent-debugger/src/test/resources/com/datadog/debugger/CodeOrigin04.java +++ b/dd-java-agent/agent-debugger/src/test/resources/com/datadog/debugger/CodeOrigin04.java @@ -35,7 +35,7 @@ private static AgentSpan newSpan(String name) { } private static void exit() { - int x = 47 / 3; + int x = 47 / 3; // code origin 2 } } diff --git a/dd-java-agent/agent-debugger/src/test/resources/com/datadog/debugger/CodeOrigin05.java b/dd-java-agent/agent-debugger/src/test/resources/com/datadog/debugger/CodeOrigin05.java index ec3a8062c0b..341d8391736 100644 --- a/dd-java-agent/agent-debugger/src/test/resources/com/datadog/debugger/CodeOrigin05.java +++ b/dd-java-agent/agent-debugger/src/test/resources/com/datadog/debugger/CodeOrigin05.java @@ -1,6 +1,5 @@ package com.datadog.debugger; -import datadog.trace.bootstrap.debugger.spanorigin.CodeOriginInfo; import datadog.trace.bootstrap.instrumentation.api.AgentScope; import datadog.trace.bootstrap.instrumentation.api.AgentSpan; import datadog.trace.bootstrap.instrumentation.api.AgentTracer; diff --git a/dd-java-agent/agent-debugger/src/test/resources/com/datadog/debugger/TriggerProbe01.java b/dd-java-agent/agent-debugger/src/test/resources/com/datadog/debugger/TriggerProbe01.java index 8181142c581..73cc5f843b0 100644 --- a/dd-java-agent/agent-debugger/src/test/resources/com/datadog/debugger/TriggerProbe01.java +++ b/dd-java-agent/agent-debugger/src/test/resources/com/datadog/debugger/TriggerProbe01.java @@ -1,11 +1,9 @@ package com.datadog.debugger; -import datadog.trace.bootstrap.debugger.spanorigin.CodeOriginInfo; import datadog.trace.bootstrap.instrumentation.api.AgentScope; import datadog.trace.bootstrap.instrumentation.api.AgentSpan; import datadog.trace.bootstrap.instrumentation.api.AgentTracer; import datadog.trace.bootstrap.instrumentation.api.AgentTracer.TracerAPI; -import datadog.trace.core.DDSpan; public class TriggerProbe01 { private int intField = 42; diff --git a/dd-java-agent/agent-debugger/src/test/resources/com/datadog/debugger/TriggerProbe02.java b/dd-java-agent/agent-debugger/src/test/resources/com/datadog/debugger/TriggerProbe02.java index f3323b89872..2e200c10727 100644 --- a/dd-java-agent/agent-debugger/src/test/resources/com/datadog/debugger/TriggerProbe02.java +++ b/dd-java-agent/agent-debugger/src/test/resources/com/datadog/debugger/TriggerProbe02.java @@ -1,11 +1,9 @@ package com.datadog.debugger; -import datadog.trace.bootstrap.debugger.spanorigin.CodeOriginInfo; import datadog.trace.bootstrap.instrumentation.api.AgentScope; import datadog.trace.bootstrap.instrumentation.api.AgentSpan; import datadog.trace.bootstrap.instrumentation.api.AgentTracer; import datadog.trace.bootstrap.instrumentation.api.AgentTracer.TracerAPI; -import datadog.trace.core.DDSpan; public class TriggerProbe02 { private int intField = 42; diff --git a/dd-java-agent/instrumentation/grpc-1.5/src/main/java/datadog/trace/instrumentation/grpc/server/MethodHandlersInstrumentation.java b/dd-java-agent/instrumentation/grpc-1.5/src/main/java/datadog/trace/instrumentation/grpc/server/MethodHandlersInstrumentation.java index 14c08edc9ed..d41f56b7a9f 100644 --- a/dd-java-agent/instrumentation/grpc-1.5/src/main/java/datadog/trace/instrumentation/grpc/server/MethodHandlersInstrumentation.java +++ b/dd-java-agent/instrumentation/grpc-1.5/src/main/java/datadog/trace/instrumentation/grpc/server/MethodHandlersInstrumentation.java @@ -1,7 +1,8 @@ package datadog.trace.instrumentation.grpc.server; import static datadog.trace.agent.tooling.bytebuddy.matcher.NameMatchers.nameEndsWith; -import static datadog.trace.bootstrap.debugger.spanorigin.CodeOriginInfo.entry; +import static datadog.trace.bootstrap.debugger.DebuggerContext.captureCodeOrigin; +import static datadog.trace.bootstrap.debugger.DebuggerContext.marker; import static net.bytebuddy.matcher.ElementMatchers.isConstructor; import static net.bytebuddy.matcher.ElementMatchers.takesArguments; @@ -68,7 +69,10 @@ public static void onEnter(@Advice.Argument(0) Object serviceImpl) { } for (Method method : superClass.getDeclaredMethods()) { try { - entry(serviceClass.getDeclaredMethod(method.getName(), method.getParameterTypes())); + marker(); + captureCodeOrigin( + serviceClass.getDeclaredMethod(method.getName(), method.getParameterTypes()), + true); } catch (Throwable e) { // service method not overridden on the impl. skipping instrumentation. } diff --git a/dd-java-agent/instrumentation/micronaut/http-server-netty-4.0/src/test/groovy/MicronautTest.groovy b/dd-java-agent/instrumentation/micronaut/http-server-netty-4.0/src/test/groovy/MicronautTest.groovy index aa214a39f3e..ddae4eccf59 100644 --- a/dd-java-agent/instrumentation/micronaut/http-server-netty-4.0/src/test/groovy/MicronautTest.groovy +++ b/dd-java-agent/instrumentation/micronaut/http-server-netty-4.0/src/test/groovy/MicronautTest.groovy @@ -35,7 +35,7 @@ class MicronautTest extends HttpServerTest { } @Override - String captureCodeOrigin(Method method, boolean entry, boolean instrument) { + String captureCodeOrigin(Method method, boolean entry) { invoked = true return "done" } diff --git a/dd-java-agent/instrumentation/span-origin/src/main/java/datadog/trace/instrumentation/codeorigin/EntrySpanOriginAdvice.java b/dd-java-agent/instrumentation/span-origin/src/main/java/datadog/trace/instrumentation/codeorigin/EntrySpanOriginAdvice.java index fcf7385a3b3..bbc94cb5c5f 100644 --- a/dd-java-agent/instrumentation/span-origin/src/main/java/datadog/trace/instrumentation/codeorigin/EntrySpanOriginAdvice.java +++ b/dd-java-agent/instrumentation/span-origin/src/main/java/datadog/trace/instrumentation/codeorigin/EntrySpanOriginAdvice.java @@ -1,6 +1,8 @@ package datadog.trace.instrumentation.codeorigin; -import datadog.trace.bootstrap.debugger.spanorigin.CodeOriginInfo; +import static datadog.trace.bootstrap.debugger.DebuggerContext.*; +import static datadog.trace.bootstrap.debugger.DebuggerContext.marker; + import java.lang.reflect.Method; import net.bytebuddy.asm.Advice; @@ -9,6 +11,7 @@ public class EntrySpanOriginAdvice { @Advice.OnMethodEnter @SuppressWarnings("bytebuddy-exception-suppression") public static void onEnter(@Advice.Origin final Method method) { - CodeOriginInfo.entry(method); + marker(); + captureCodeOrigin(method, true); } } diff --git a/dd-java-agent/instrumentation/spring-data-1.8/src/main/java/datadog/trace/instrumentation/springdata/SpringDataDecorator.java b/dd-java-agent/instrumentation/spring-data-1.8/src/main/java/datadog/trace/instrumentation/springdata/SpringDataDecorator.java index 5b9a8fabf40..dd52c9f4d43 100644 --- a/dd-java-agent/instrumentation/spring-data-1.8/src/main/java/datadog/trace/instrumentation/springdata/SpringDataDecorator.java +++ b/dd-java-agent/instrumentation/spring-data-1.8/src/main/java/datadog/trace/instrumentation/springdata/SpringDataDecorator.java @@ -2,8 +2,10 @@ package datadog.trace.instrumentation.springdata; +import static datadog.trace.bootstrap.debugger.DebuggerContext.captureCodeOrigin; +import static datadog.trace.bootstrap.debugger.DebuggerContext.marker; + import datadog.trace.api.Config; -import datadog.trace.bootstrap.debugger.spanorigin.CodeOriginInfo; import datadog.trace.bootstrap.instrumentation.api.AgentSpan; import datadog.trace.bootstrap.instrumentation.api.UTF8BytesString; import datadog.trace.bootstrap.instrumentation.decorator.ClientDecorator; @@ -46,6 +48,7 @@ public void onOperation( span.setResourceName(spanNameForMethod(method)); } - CodeOriginInfo.exit(span); + marker(); + captureCodeOrigin(false); } } diff --git a/dd-java-agent/instrumentation/trace-annotation/src/main/java/datadog/trace/instrumentation/trace_annotation/TraceAdvice.java b/dd-java-agent/instrumentation/trace-annotation/src/main/java/datadog/trace/instrumentation/trace_annotation/TraceAdvice.java index c90a7ef1d5e..fdb48f04dd7 100644 --- a/dd-java-agent/instrumentation/trace-annotation/src/main/java/datadog/trace/instrumentation/trace_annotation/TraceAdvice.java +++ b/dd-java-agent/instrumentation/trace-annotation/src/main/java/datadog/trace/instrumentation/trace_annotation/TraceAdvice.java @@ -1,9 +1,10 @@ package datadog.trace.instrumentation.trace_annotation; +import static datadog.trace.bootstrap.debugger.DebuggerContext.*; +import static datadog.trace.bootstrap.debugger.DebuggerContext.marker; import static datadog.trace.bootstrap.instrumentation.api.AgentTracer.activateSpan; import static datadog.trace.instrumentation.trace_annotation.TraceDecorator.DECORATE; -import datadog.trace.bootstrap.debugger.DebuggerContext; import datadog.trace.bootstrap.instrumentation.api.AgentScope; import java.lang.invoke.MethodType; import java.lang.reflect.Method; @@ -15,7 +16,8 @@ public class TraceAdvice { @Advice.OnMethodEnter(suppress = Throwable.class) public static AgentScope onEnter(@Advice.Origin final Method method) { AgentScope agentScope = activateSpan(DECORATE.startMethodSpan(method)); - DebuggerContext.captureCodeOrigin(method, true, false); + marker(); + captureCodeOrigin(method, true); return agentScope; } 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 2fa43f07e5a..1964fcaa7ce 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 @@ -1,7 +1,5 @@ package datadog.smoketest; -import static datadog.smoketest.debugger.TestApplicationHelper.waitForSpecificLine; - import com.datadog.debugger.probe.LogProbe; import java.io.IOException; import java.nio.file.Path;