Skip to content

Commit

Permalink
Introduce id-based line probe source matching (#8275)
Browse files Browse the repository at this point in the history
line probe in unit tests are created by searching probe id (UUID)
inside the targeted source file.
uuid are added as comment on the line we want to put a line probe.
Add helper method to search a uuid inside the targeted source file
and returns the line number used to create the line probe
  • Loading branch information
jpbempel authored Jan 24, 2025
1 parent 71309b3 commit 710964d
Show file tree
Hide file tree
Showing 25 changed files with 382 additions and 267 deletions.

Large diffs are not rendered by default.

Large diffs are not rendered by default.

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import static utils.InstrumentationTestHelper.compileAndLoadClass;
import static utils.InstrumentationTestHelper.getLineForLineProbe;

import com.datadog.debugger.el.DSL;
import com.datadog.debugger.el.ProbeCondition;
Expand Down Expand Up @@ -60,6 +61,8 @@ public class SpanDecorationProbeInstrumentationTest extends ProbeInstrumentation
private static final ProbeId PROBE_ID2 = new ProbeId("beae1807-f3b0-4ea8-a74f-826790c5e6f7", 0);
private static final ProbeId PROBE_ID3 = new ProbeId("beae1807-f3b0-4ea8-a74f-826790c5e6f8", 0);
private static final ProbeId PROBE_ID4 = new ProbeId("beae1807-f3b0-4ea8-a74f-826790c5e6f9", 0);
private static final ProbeId LINE_PROBE_ID1 =
new ProbeId("beae1817-f3b0-4ea8-a74f-000000000001", 0);

private TestTraceInterceptor traceInterceptor = new TestTraceInterceptor();

Expand Down Expand Up @@ -259,14 +262,16 @@ public void methodActiveSpanSynthException() throws IOException, URISyntaxExcept
public void lineActiveSpanSimpleTag() throws IOException, URISyntaxException {
final String CLASS_NAME = "com.datadog.debugger.CapturedSnapshot20";
SpanDecorationProbe.Decoration decoration = createDecoration("tag1", "{arg}");
installSingleSpanDecoration(CLASS_NAME, ACTIVE, decoration, "CapturedSnapshot20.java", 47);
int line = getLineForLineProbe(CLASS_NAME, LINE_PROBE_ID1);
installSingleSpanDecoration(
LINE_PROBE_ID1, CLASS_NAME, ACTIVE, decoration, "CapturedSnapshot20.java", line);
Class<?> testClass = compileAndLoadClass(CLASS_NAME);
int result = Reflect.on(testClass).call("main", "1").get();
assertEquals(84, result);
MutableSpan span = traceInterceptor.getFirstSpan();
assertEquals("1", span.getTags().get("tag1"));
assertEquals(PROBE_ID.getId(), span.getTags().get("_dd.di.tag1.probe_id"));
verify(probeStatusSink).addEmitting(ArgumentMatchers.eq(PROBE_ID));
assertEquals(LINE_PROBE_ID1.getId(), span.getTags().get("_dd.di.tag1.probe_id"));
verify(probeStatusSink).addEmitting(ArgumentMatchers.eq(LINE_PROBE_ID1));
}

@Test
Expand All @@ -275,8 +280,14 @@ public void lineRootSpanTagList() throws IOException, URISyntaxException {
SpanDecorationProbe.Decoration deco1 = createDecoration("tag1", "{arg}");
SpanDecorationProbe.Decoration deco2 = createDecoration("tag2", "{this.intField}");
SpanDecorationProbe.Decoration deco3 = createDecoration("tag3", "{strField}");
int line = getLineForLineProbe(CLASS_NAME, LINE_PROBE_ID1);
installSingleSpanDecoration(
CLASS_NAME, ROOT, asList(deco1, deco2, deco3), "CapturedSnapshot21.java", 67);
LINE_PROBE_ID1,
CLASS_NAME,
ROOT,
asList(deco1, deco2, deco3),
"CapturedSnapshot21.java",
line);
Class<?> testClass = compileAndLoadClass(CLASS_NAME);
int result = Reflect.on(testClass).call("main", "1").get();
assertEquals(45, result);
Expand All @@ -292,7 +303,9 @@ public void lineActiveSpanCondition() throws IOException, URISyntaxException {
final String CLASS_NAME = "com.datadog.debugger.CapturedSnapshot20";
SpanDecorationProbe.Decoration decoration =
createDecoration(eq(ref("arg"), value("5")), "arg == '5'", "tag1", "{arg}");
installSingleSpanDecoration(CLASS_NAME, ACTIVE, decoration, "CapturedSnapshot20.java", 47);
int line = getLineForLineProbe(CLASS_NAME, LINE_PROBE_ID1);
installSingleSpanDecoration(
LINE_PROBE_ID1, CLASS_NAME, ACTIVE, decoration, "CapturedSnapshot20.java", line);
Class<?> testClass = compileAndLoadClass(CLASS_NAME);
for (int i = 0; i < 10; i++) {
int result = Reflect.on(testClass).call("main", String.valueOf(i)).get();
Expand All @@ -308,7 +321,9 @@ public void lineActiveSpanInvalidCondition() throws IOException, URISyntaxExcept
final String CLASS_NAME = "com.datadog.debugger.CapturedSnapshot20";
SpanDecorationProbe.Decoration decoration =
createDecoration(eq(ref("noarg"), value("5")), "arg == '5'", "tag1", "{arg}");
installSingleSpanDecoration(CLASS_NAME, ACTIVE, decoration, "CapturedSnapshot20.java", 47);
int line = getLineForLineProbe(CLASS_NAME, LINE_PROBE_ID1);
installSingleSpanDecoration(
LINE_PROBE_ID1, CLASS_NAME, ACTIVE, decoration, "CapturedSnapshot20.java", line);
Class<?> testClass = compileAndLoadClass(CLASS_NAME);
int result = Reflect.on(testClass).call("main", "5").get();
assertEquals(84, result);
Expand Down Expand Up @@ -338,24 +353,12 @@ public void mixedWithLogProbes() throws IOException, URISyntaxException {
SpanDecorationProbe.Decoration decoration2 = createDecoration("tag2", "{arg}");
SpanDecorationProbe spanDecoProbe1 =
createProbeBuilder(
PROBE_ID1,
ACTIVE,
singletonList(decoration1),
CLASS_NAME,
"process",
null,
(String[]) null)
PROBE_ID1, ACTIVE, singletonList(decoration1), CLASS_NAME, "process", null)
.evaluateAt(MethodLocation.EXIT)
.build();
SpanDecorationProbe spanDecoProbe2 =
createProbeBuilder(
PROBE_ID2,
ACTIVE,
singletonList(decoration2),
CLASS_NAME,
"process",
null,
(String[]) null)
PROBE_ID2, ACTIVE, singletonList(decoration2), CLASS_NAME, "process", null)
.evaluateAt(MethodLocation.ENTRY)
.build();
LogProbe logProbe1 =
Expand Down Expand Up @@ -403,24 +406,12 @@ public void mixedEntryExit() throws IOException, URISyntaxException {
SpanDecorationProbe.Decoration decoration2 = createDecoration("tag2", "{arg}");
SpanDecorationProbe spanDecoProbe1 =
createProbeBuilder(
PROBE_ID1,
ACTIVE,
singletonList(decoration1),
CLASS_NAME,
"process",
null,
(String[]) null)
PROBE_ID1, ACTIVE, singletonList(decoration1), CLASS_NAME, "process", null)
.evaluateAt(MethodLocation.EXIT)
.build();
SpanDecorationProbe spanDecoProbe2 =
createProbeBuilder(
PROBE_ID2,
ACTIVE,
singletonList(decoration2),
CLASS_NAME,
"process",
null,
(String[]) null)
PROBE_ID2, ACTIVE, singletonList(decoration2), CLASS_NAME, "process", null)
.evaluateAt(MethodLocation.ENTRY)
.build();
Configuration configuration =
Expand Down Expand Up @@ -624,12 +615,14 @@ private void installSingleSpanDecoration(
}

private void installSingleSpanDecoration(
ProbeId probeId,
String typeName,
SpanDecorationProbe.TargetSpan targetSpan,
SpanDecorationProbe.Decoration decoration,
String sourceFile,
int line) {
installSingleSpanDecoration(typeName, targetSpan, asList(decoration), sourceFile, line);
installSingleSpanDecoration(
probeId, typeName, targetSpan, asList(decoration), sourceFile, line);
}

private void installSingleSpanDecoration(
Expand All @@ -645,12 +638,13 @@ private void installSingleSpanDecoration(
}

private void installSingleSpanDecoration(
ProbeId probeId,
String typeName,
SpanDecorationProbe.TargetSpan targetSpan,
List<SpanDecorationProbe.Decoration> decorations,
String sourceFile,
int line) {
SpanDecorationProbe probe = createProbe(PROBE_ID, targetSpan, decorations, sourceFile, line);
SpanDecorationProbe probe = createProbe(probeId, targetSpan, decorations, sourceFile, line);
installSpanDecorationProbes(
typeName, Configuration.builder().setService(SERVICE_NAME).add(probe).build());
}
Expand All @@ -661,10 +655,8 @@ private static SpanDecorationProbe createProbe(
List<SpanDecorationProbe.Decoration> decorationList,
String typeName,
String methodName,
String signature,
String... lines) {
return createProbeBuilder(
id, targetSpan, decorationList, typeName, methodName, signature, lines)
String signature) {
return createProbeBuilder(id, targetSpan, decorationList, typeName, methodName, signature)
.evaluateAt(MethodLocation.EXIT)
.build();
}
Expand All @@ -684,12 +676,11 @@ private static SpanDecorationProbe.Builder createProbeBuilder(
List<SpanDecorationProbe.Decoration> decorationList,
String typeName,
String methodName,
String signature,
String... lines) {
String signature) {
return SpanDecorationProbe.builder()
.language(LANGUAGE)
.probeId(id)
.where(typeName, methodName, signature, lines)
.where(typeName, methodName, signature)
.evaluateAt(MethodLocation.EXIT)
.targetSpan(targetSpan)
.decorate(decorationList);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -173,9 +173,8 @@ public static TriggerProbe createTriggerProbe(
String methodName,
String signature,
ProbeCondition probeCondition,
Sampling sampling,
String... lines) {
return new TriggerProbe(id, Where.of(typeName, methodName, signature, lines))
Sampling sampling) {
return new TriggerProbe(id, Where.of(typeName, methodName, signature))
.setSessionId(sessionId)
.setProbeCondition(probeCondition)
.setSampling(sampling);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
package utils;

import static utils.TestHelper.getFixtureContent;
import static utils.TestHelper.getFixtureLines;

import com.datadog.debugger.agent.CapturedSnapshotTest;
import datadog.trace.bootstrap.debugger.ProbeId;
import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URISyntaxException;
Expand All @@ -11,6 +13,7 @@
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class InstrumentationTestHelper {
Expand Down Expand Up @@ -66,4 +69,21 @@ public static Class<?> loadClassFromJar(String className, String jarFileName)
new URLClassLoader(new URL[] {new URL("file://" + jarFileName)});
return jarClassLoader.loadClass(className);
}

public static int getLineForLineProbe(String className, ProbeId lineProbeId)
throws IOException, URISyntaxException {
return getLineForLineProbe(className, ".java", lineProbeId);
}

public static int getLineForLineProbe(String className, String ext, ProbeId lineProbeId)
throws IOException, URISyntaxException {
List<String> lines = getFixtureLines("/" + className.replace('.', '/') + ext);
for (int i = 0; i < lines.size(); i++) {
String line = lines.get(i);
if (line.contains("//") && line.contains(lineProbeId.getId())) {
return i + 1;
}
}
return -1;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,15 @@
import java.net.URISyntaxException;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.List;

public class TestHelper {
public static String getFixtureContent(String fixture) throws IOException, URISyntaxException {
return new String(Files.readAllBytes(Paths.get(TestHelper.class.getResource(fixture).toURI())));
}

public static List<String> getFixtureLines(String fixture)
throws IOException, URISyntaxException {
return Files.readAllLines(Paths.get(TestHelper.class.getResource(fixture).toURI()));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ public static int main(String arg) {
var1 = 2;
return var1;
}
var1 = 3;
return var1;
var1 = 3; // beae1817-f3b0-4ea8-a74f-000000000001
return var1; // beae1817-f3b0-4ea8-a74f-000000000002
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ void f() {
int synchronizedBlock(int input) {
int count = input;
synchronized (this) {
for (int i = 0; i < 10; i++) {
for (int i = 0; i < 10; i++) { // beae1817-f3b0-4ea8-a74f-000000000001
count += i;
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
public class CapturedSnapshot03 {

int f1(int value) {
return value;
return value; // beae1817-f3b0-4ea8-a74f-000000000001
}

int f2(int value) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,8 @@ public static int main(String arg) {
CapturedSnapshot04 cs4 = new CapturedSnapshot04();
SimpleData sdata = cs4.createSimpleData();
CompositeData cdata = cs4.createCompositeData();
SimpleData nullObject = null;
return sdata.intValue + cdata.s1.intValue;
SimpleData nullObject = null; // beae1817-f3b0-4ea8-a74f-000000000003, beae1817-f3b0-4ea8-a74f-000000000004
return sdata.intValue + cdata.s1.intValue; // beae1817-f3b0-4ea8-a74f-000000000001, beae1817-f3b0-4ea8-a74f-000000000002
}

public static class SimpleData {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,13 +23,13 @@ int triggerSwallowedException(int arg) {
if (arg == 1)
throw new IllegalArgumentException("nope!");
throw new FileNotFoundException("not there");
} catch (IllegalStateException ex) {
} catch (IllegalStateException ex) { // beae1817-f3b0-4ea8-a74f-000000000001
// swallowed with empty catch block
} catch (IllegalArgumentException ex) {
ex.printStackTrace();
ex.printStackTrace(); // beae1817-f3b0-4ea8-a74f-000000000002
return 0;
} catch (Throwable ex) {
return -1;
return -1; // beae1817-f3b0-4ea8-a74f-000000000003
}
return 42;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ int f() {
strValue = "done";
strList.add(strValue);
strMap.put("foo", "bar");
return 42;
return 42; // beae1817-f3b0-4ea8-a74f-000000000001
}

public static int main(String arg) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ public static int main(String mode, String arg) {
private int staticLambda(String arg) {
Function<String, String> func = s -> {
int idx = s.indexOf('@');
if (idx >= 0) {
if (idx >= 0) { // beae1817-f3b0-4ea8-a74f-000000000001
return s.substring(idx);
}
return s.substring(0);
Expand All @@ -45,7 +45,7 @@ private int staticLambda(String arg) {
private int capturingLambda(String arg) {
Function<String, String> func = s -> {
int idx = strValue.indexOf('@');
if (idx >= 0) {
if (idx >= 0) { // beae1817-f3b0-4ea8-a74f-000000000002
return strValue.substring(idx);
}
return strValue.substring(0);
Expand All @@ -55,7 +55,7 @@ private int capturingLambda(String arg) {

private int multiLambda(String arg) {
return (int)Arrays.stream(arg.split(","))
.map(s -> s.toUpperCase()).filter(s -> s.startsWith("FOO"))
.map(s -> s.toUpperCase()).filter(s -> s.startsWith("FOO")) // beae1817-f3b0-4ea8-a74f-000000000003
.count();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,13 @@ public static int main(String arg) {
return INSTANCE.doit(arg);
}

private int doit(String arg) {
int var1 = 1;
private int doit(String arg) { // beae1817-f3b0-4ea8-a74f-000000000002
int var1 = 1; // beae1817-f3b0-4ea8-a74f-000000000001
if (Integer.parseInt(arg) == 2) {
var1 = 2;
return var1;
}
var1 = 3;
var1 = 3; // beae1817-f3b0-4ea8-a74f-000000000003, beae1817-f3b0-4ea8-a74f-000000000004
return var1;
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
class CapturedSnapshot101 {
def f1(value: Int) = {
value
value // beae1817-f3b0-4ea8-a74f-000000000001
}
def f2(value: Int) = {
value
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
class CapturedSnapshot201 {

def f1(int value) {
value
value // beae1817-f3b0-4ea8-a74f-000000000001
}

def f2(int value) {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
class CapturedSnapshot301 {

fun f1(value: Int): Int {
return value
return value // beae1817-f3b0-4ea8-a74f-000000000001
}

fun f2(value: Int): Int {
Expand Down
Loading

0 comments on commit 710964d

Please sign in to comment.