Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions dd-java-agent/agent-debugger/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,8 @@ dependencies {
testImplementation project(':dd-java-agent:agent-debugger:debugger-test-scala')
testImplementation project(':dd-trace-core')
testImplementation project(':dd-java-agent:agent-installer')
testImplementation project(':dd-java-agent:instrumentation:rs:jax-rs:jax-rs-annotations:jax-rs-annotations-2.0')
testImplementation group: 'javax.ws.rs', name: 'javax.ws.rs-api', version: '2.1.1'
testImplementation project(':remote-config:remote-config-core')
testImplementation project(':utils:test-utils')

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
import static utils.InstrumentationTestHelper.compile;
import static utils.InstrumentationTestHelper.compileAndLoadClass;
import static utils.InstrumentationTestHelper.getLineForLineProbe;
import static utils.InstrumentationTestHelper.installTracerInstrumentation;
import static utils.InstrumentationTestHelper.loadClass;
import static utils.TestClassFileHelper.getClassFileBytes;
import static utils.TestHelper.getFixtureContent;
Expand Down Expand Up @@ -72,6 +73,7 @@
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.lang.instrument.ClassFileTransformer;
import java.lang.instrument.Instrumentation;
import java.net.URISyntaxException;
import java.net.URL;
Expand Down Expand Up @@ -1838,26 +1840,33 @@ public void multiLambdas() throws IOException, URISyntaxException {
public void tracerInstrumentedClass() throws Exception {
DebuggerContext.initClassFilter(new DenyListHelper(null));
final String CLASS_NAME = "com.datadog.debugger.jaxrs.MyResource";
TestSnapshotListener listener = installMethodProbe(CLASS_NAME, "createResource", null);
// load a class file that was previously instrumented by the DD tracer as JAX-RS resource
Class<?> testClass =
loadClass(CLASS_NAME, getClass().getResource("/MyResource.class").getFile());
Object result =
Reflect.onClass(testClass)
.create()
.call("createResource", (Object) null, (Object) null, 1)
.get();
Snapshot snapshot = assertOneSnapshot(listener);
Map<String, CapturedContext.CapturedValue> arguments =
snapshot.getCaptures().getEntry().getArguments();
// it's important there is no null key in this map, as Jackson is not happy about it
// it's means here that argument names are not resolved correctly
Assertions.assertFalse(arguments.containsKey(null));
assertEquals(4, arguments.size());
assertTrue(arguments.containsKey("this"));
assertTrue(arguments.containsKey("apiKey"));
assertTrue(arguments.containsKey("uriInfo"));
assertTrue(arguments.containsKey("value"));
// compile the JAX-RS resource fixture and weave it with the real tracer JAX-RS
// instrumentation, so this test exercises argument-name resolution against the same
// bytecode shape the tracer actually produces
ClassFileTransformer jaxRsTransformer = installTracerInstrumentation(instr);
Comment thread
jpbempel marked this conversation as resolved.
Class<?> testClass;
try {
TestSnapshotListener listener = installMethodProbe(CLASS_NAME, "createResource", null);
testClass = compileAndLoadClass(CLASS_NAME);
Object result =
Reflect.onClass(testClass)
.create()
.call("createResource", (Object) null, (Object) null, 1)
.get();
Snapshot snapshot = assertOneSnapshot(listener);
Map<String, CapturedContext.CapturedValue> arguments =
snapshot.getCaptures().getEntry().getArguments();
// it's important there is no null key in this map, as Jackson is not happy about it
// it's means here that argument names are not resolved correctly
Assertions.assertFalse(arguments.containsKey(null));
assertEquals(4, arguments.size());
assertTrue(arguments.containsKey("this"));
assertTrue(arguments.containsKey("apiKey"));
assertTrue(arguments.containsKey("uriInfo"));
assertTrue(arguments.containsKey("value"));
} finally {
instr.removeTransformer(jaxRsTransformer);
}
}

@Test
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@
import static org.mockito.Mockito.when;
import static utils.InstrumentationTestHelper.compileAndLoadClass;
import static utils.InstrumentationTestHelper.getLineForLineProbe;
import static utils.InstrumentationTestHelper.loadClass;
import static utils.InstrumentationTestHelper.installTracerInstrumentation;

import com.datadog.debugger.el.DSL;
import com.datadog.debugger.el.ValueScript;
Expand Down Expand Up @@ -1291,21 +1291,28 @@ public void primitivesFunction() throws IOException, URISyntaxException {
public void localVarNotInScope() throws IOException, URISyntaxException {
final String METRIC_NAME = "lenstr";
final String CLASS_NAME = "com.datadog.debugger.jaxrs.MyResource";
MetricProbe metricProbe =
createMetricBuilder(METRIC_ID, METRIC_NAME, GAUGE)
.where(CLASS_NAME, "createResource", null)
.valueScript(new ValueScript(DSL.len(DSL.ref("varStr")), "len(varStr)"))
.build();
MetricForwarderListener listener = installMetricProbes(metricProbe);
Class<?> testClass =
loadClass(CLASS_NAME, getClass().getResource("/MyResource.class").getFile());
Object result =
Reflect.onClass(testClass)
.create()
.call("createResource", (Object) null, (Object) null, 1)
.get();
assertNotNull(result);
assertFalse(listener.gauges.containsKey(METRIC_NAME));
// compile the JAX-RS resource fixture and weave it with the real tracer JAX-RS
// instrumentation, so this test exercises the same bytecode shape the tracer produces
ClassFileTransformer jaxRsTransformer = installTracerInstrumentation(instr);
Class<?> testClass;
try {
MetricProbe metricProbe =
createMetricBuilder(METRIC_ID, METRIC_NAME, GAUGE)
.where(CLASS_NAME, "createResource", null)
.valueScript(new ValueScript(DSL.len(DSL.ref("varStr")), "len(varStr)"))
.build();
MetricForwarderListener listener = installMetricProbes(metricProbe);
testClass = compileAndLoadClass(CLASS_NAME);
Object result =
Reflect.onClass(testClass)
.create()
.call("createResource", (Object) null, (Object) null, 1)
.get();
assertNotNull(result);
assertFalse(listener.gauges.containsKey(METRIC_NAME));
} finally {
instr.removeTransformer(jaxRsTransformer);
}
}

private MetricForwarderListener installMethodMetric(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -179,6 +179,12 @@ public void roundTripCaughtException() throws IOException {
new CapturedStackFrame("f2", 23),
new CapturedStackFrame("f3", 34)),
null));
captures.addCaughtException(
Comment thread
jpbempel marked this conversation as resolved.
new CapturedContext.CapturedThrowable(
NullPointerException.class.getTypeName(),
"illegal argument",
Collections.emptyList(),
null));
String buffer = adapter.toJson(snapshot);
System.out.println("roundTripCaughtException: " + buffer);
Snapshot deserializedSnapshot = adapter.fromJson(buffer);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,21 @@
import static utils.TestHelper.getFixtureLines;

import com.datadog.debugger.agent.CapturedSnapshotTest;
import datadog.instrument.classinject.ClassInjector;
import datadog.trace.agent.tooling.AgentInstaller;
import datadog.trace.agent.tooling.InstrumenterModule;
import datadog.trace.bootstrap.debugger.ProbeId;
import java.io.IOException;
import java.lang.instrument.ClassFileTransformer;
import java.lang.instrument.Instrumentation;
import java.net.MalformedURLException;
import java.net.URISyntaxException;
import java.net.URL;
import java.net.URLClassLoader;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.Collections;
import java.util.EnumSet;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
Expand Down Expand Up @@ -84,6 +90,19 @@ public static int getLineForLineProbe(String className, ProbeId lineProbeId) {
return getLineForLineProbe(className, ".java", lineProbeId);
}

/**
* Installs the real tracer instrumentation modules (e.g. jax-rs-annotations) on top of the given
* {@link Instrumentation}, so that classes defined afterwards (typically via {@link
* #compileAndLoadClass}) are woven with actual tracer advice, the same way they would be by the
* production agent. Callers must remove the returned transformer once done, e.g. via {@link
* Instrumentation#removeTransformer(ClassFileTransformer)}.
*/
public static ClassFileTransformer installTracerInstrumentation(Instrumentation instr) {
ClassInjector.enableClassInjection(instr);
return AgentInstaller.installBytebuddyAgent(
instr, false, EnumSet.of(InstrumenterModule.TargetSystem.TRACING));
}

public static int getLineForLineProbe(String className, String ext, ProbeId lineProbeId) {
List<String> lines = getFixtureLines("/" + className.replace('.', '/') + ext);
for (int i = 0; i < lines.size(); i++) {
Expand Down
Binary file not shown.
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package com.datadog.debugger.jaxrs;

import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.QueryParam;
import javax.ws.rs.core.Context;

@Path("myresource")
public class MyResource {

@GET
public Object createResource(
String apiKey, @Context String uriInfo, @QueryParam("value") int value) {
String varStr = "foo";
Object response = new Object();
return response;
}
}
Loading