Skip to content

Commit be03ce5

Browse files
authored
Don't instrument trigger probes if the distributed debugger is disabled (#8458)
1 parent ba51027 commit be03ce5

File tree

5 files changed

+147
-48
lines changed

5 files changed

+147
-48
lines changed

dd-java-agent/agent-debugger/debugger-el/build.gradle

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,8 @@ excludedClassesCoverage += [
1212
'com.datadog.debugger.el.Script*',
1313
'com.datadog.debugger.el.ValueScript*',
1414
'com.datadog.debugger.el.values.CollectionValue*',
15-
'com.datadog.debugger.el.InvalidValueException'
15+
'com.datadog.debugger.el.InvalidValueException',
16+
'com.datadog.debugger.el.EvaluationException'
1617
]
1718

1819
dependencies {

dd-java-agent/agent-debugger/debugger-el/src/main/java/com/datadog/debugger/el/EvaluationException.java

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
package com.datadog.debugger.el;
22

3+
import java.util.Objects;
4+
35
public class EvaluationException extends RuntimeException {
46
private final String expr;
57

@@ -16,4 +18,22 @@ public EvaluationException(String message, String expr, Throwable cause) {
1618
public String getExpr() {
1719
return expr;
1820
}
21+
22+
@Override
23+
public final boolean equals(Object o) {
24+
if (!(o instanceof EvaluationException)) {
25+
return false;
26+
}
27+
28+
EvaluationException that = (EvaluationException) o;
29+
return Objects.equals(getExpr(), that.getExpr())
30+
&& Objects.equals(getMessage(), that.getMessage());
31+
}
32+
33+
@Override
34+
public int hashCode() {
35+
int result = Objects.hashCode(getExpr());
36+
result = 31 * result + Objects.hashCode(getMessage());
37+
return result;
38+
}
1939
}

dd-java-agent/agent-debugger/src/main/java/com/datadog/debugger/agent/DebuggerTransformer.java

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -634,7 +634,10 @@ private List<ToInstrumentInfo> filterAndSortDefinitions(
634634
// Log and span decoration probe shared the same instrumentor: CaptureContextInstrumentor
635635
// and therefore need to be instrumented once
636636
// note: exception probes are log probes and are handled the same way
637-
if (isCapturedContextProbe(definition)) {
637+
if (!Config.get().isDistributedDebuggerEnabled() && definition instanceof TriggerProbe) {
638+
log.debug(
639+
"The distributed debugger feature is disabled. Trigger probes will not be installed.");
640+
} else if (isCapturedContextProbe(definition)) {
638641
if (definition.isLineProbe()) {
639642
capturedContextLineProbes
640643
.computeIfAbsent(definition.getWhere(), key -> new ArrayList<>())

dd-java-agent/agent-debugger/src/main/java/com/datadog/debugger/probe/TriggerProbe.java

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -59,10 +59,6 @@ public InstrumentationResult.Status instrument(
5959
.instrument();
6060
}
6161

62-
public String getSessionId() {
63-
return sessionId;
64-
}
65-
6662
public TriggerProbe setSessionId(String sessionId) {
6763
this.sessionId = sessionId;
6864
return this;
@@ -86,6 +82,7 @@ public TriggerProbe setProbeCondition(ProbeCondition probeCondition) {
8682
public void evaluate(
8783
CapturedContext context, CapturedContext.Status status, MethodLocation location) {
8884

85+
Sampling sampling = getSampling();
8986
if (sampling == null || !sampling.inCoolDown()) {
9087
boolean sample = true;
9188
if (!hasCondition()) {

dd-java-agent/agent-debugger/src/test/java/com/datadog/debugger/trigger/TriggerProbeTest.java

Lines changed: 120 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -5,11 +5,14 @@
55
import static java.lang.String.format;
66
import static org.junit.jupiter.api.Assertions.assertEquals;
77
import static org.junit.jupiter.api.Assertions.assertTrue;
8+
import static org.mockito.ArgumentMatchers.eq;
9+
import static org.mockito.Mockito.verify;
810
import static utils.InstrumentationTestHelper.compileAndLoadClass;
911

1012
import com.datadog.debugger.agent.CapturingTestBase;
1113
import com.datadog.debugger.agent.Configuration;
1214
import com.datadog.debugger.agent.MockSampler;
15+
import com.datadog.debugger.el.EvaluationException;
1316
import com.datadog.debugger.el.ProbeCondition;
1417
import com.datadog.debugger.probe.Sampling;
1518
import com.datadog.debugger.probe.TriggerProbe;
@@ -50,6 +53,53 @@ public void before() {
5053

5154
setFieldInConfig(Config.get(), "debuggerCodeOriginEnabled", true);
5255
setFieldInConfig(InstrumenterConfig.get(), "codeOriginEnabled", true);
56+
setFieldInConfig(Config.get(), "distributedDebuggerEnabled", true);
57+
}
58+
59+
@Test
60+
public void conditions() throws IOException, URISyntaxException {
61+
final String className = "com.datadog.debugger.TriggerProbe02";
62+
TriggerProbe probe1 =
63+
createTriggerProbe(
64+
TRIGGER_PROBE_ID1,
65+
TRIGGER_PROBE_SESSION_ID,
66+
className,
67+
"entry",
68+
"(int)",
69+
new ProbeCondition(when(lt(ref("value"), value(25))), "value < 25"),
70+
new Sampling(10.0));
71+
installProbes(Configuration.builder().setService(SERVICE_NAME).add(probe1).build());
72+
Class<?> testClass = compileAndLoadClass(className);
73+
for (int i = 0; i < 100; i++) {
74+
Reflect.onClass(testClass).call("main", i).get();
75+
}
76+
List<List<? extends MutableSpan>> allTraces = traceInterceptor.getAllTraces();
77+
long count =
78+
allTraces.stream()
79+
.map(span -> span.get(0))
80+
.filter(
81+
span -> {
82+
DDSpan ddSpan = (DDSpan) span;
83+
PropagationTags tags = ddSpan.context().getPropagationTags();
84+
return (TRIGGER_PROBE_SESSION_ID + ":1").equals(tags.getDebugPropagation());
85+
})
86+
.count();
87+
assertEquals(100, allTraces.size(), "actual traces: " + allTraces.size());
88+
assertTrue(count <= 25, "Should have at most 25 debug sessions. found: " + count);
89+
}
90+
91+
private static TriggerProbe createTriggerProbe(
92+
ProbeId id,
93+
String sessionId,
94+
String typeName,
95+
String methodName,
96+
String signature,
97+
ProbeCondition probeCondition,
98+
Sampling sampling) {
99+
return new TriggerProbe(id, Where.of(typeName, methodName, signature))
100+
.setSessionId(sessionId)
101+
.setProbeCondition(probeCondition)
102+
.setSampling(sampling);
53103
}
54104

55105
@Test
@@ -104,6 +154,58 @@ public void cooldown() throws IOException, URISyntaxException {
104154
}
105155
}
106156

157+
@Test
158+
public void badCondition() throws IOException, URISyntaxException {
159+
String className = "com.datadog.debugger.TriggerProbe02";
160+
TriggerProbe probe1 =
161+
createTriggerProbe(
162+
TRIGGER_PROBE_ID1,
163+
TRIGGER_PROBE_SESSION_ID,
164+
className,
165+
"entry",
166+
"(int)",
167+
new ProbeCondition(when(lt(ref("limit"), value(25))), "limit < 25"),
168+
new Sampling(10.0));
169+
170+
installProbes(Configuration.builder().setService(SERVICE_NAME).add(probe1).build());
171+
Class<?> testClass = compileAndLoadClass(className);
172+
Reflect.onClass(testClass).call("main", 0).get();
173+
verify(probeStatusSink)
174+
.addError(
175+
eq(TRIGGER_PROBE_ID1),
176+
eq(new EvaluationException("Cannot find symbol: limit", "limit")));
177+
}
178+
179+
@Test
180+
public void debuggerDisabled() throws IOException, URISyntaxException {
181+
boolean original = Config.get().isDistributedDebuggerEnabled();
182+
try {
183+
setFieldInConfig(Config.get(), "distributedDebuggerEnabled", false);
184+
185+
MockSampler sampler = new MockSampler();
186+
ProbeRateLimiter.setSamplerSupplier(value -> sampler);
187+
188+
final String className = "com.datadog.debugger.TriggerProbe02";
189+
TriggerProbe probe1 =
190+
createTriggerProbe(
191+
TRIGGER_PROBE_ID1,
192+
TRIGGER_PROBE_SESSION_ID,
193+
className,
194+
"entry",
195+
"(int)",
196+
new ProbeCondition(when(lt(ref("value"), value(25))), "value < 25"),
197+
new Sampling(10.0));
198+
installProbes(Configuration.builder().setService(SERVICE_NAME).add(probe1).build());
199+
Class<?> testClass = compileAndLoadClass(className);
200+
Reflect.onClass(testClass).call("main", 0).get();
201+
202+
assertEquals(0, sampler.getCallCount());
203+
} finally {
204+
setFieldInConfig(Config.get(), "distributedDebuggerEnabled", original);
205+
ProbeRateLimiter.setSamplerSupplier(null);
206+
}
207+
}
208+
107209
@Test
108210
public void sampling() throws IOException, URISyntaxException {
109211
try {
@@ -134,49 +236,25 @@ public void sampling() throws IOException, URISyntaxException {
134236
}
135237

136238
@Test
137-
public void conditions() throws IOException, URISyntaxException {
239+
public void noSampling() throws IOException, URISyntaxException {
240+
try {
241+
MockSampler sampler = new MockSampler();
242+
ProbeRateLimiter.setSamplerSupplier(value -> sampler);
138243

139-
final String className = "com.datadog.debugger.TriggerProbe02";
140-
TriggerProbe probe1 =
141-
createTriggerProbe(
142-
TRIGGER_PROBE_ID1,
143-
TRIGGER_PROBE_SESSION_ID,
144-
className,
145-
"entry",
146-
"(int)",
147-
new ProbeCondition(when(lt(ref("value"), value(25))), "value < 25"),
148-
new Sampling(10.0));
149-
installProbes(Configuration.builder().setService(SERVICE_NAME).add(probe1).build());
150-
Class<?> testClass = compileAndLoadClass(className);
151-
for (int i = 0; i < 100; i++) {
152-
Reflect.onClass(testClass).call("main", i).get();
153-
}
154-
List<List<? extends MutableSpan>> allTraces = traceInterceptor.getAllTraces();
155-
long count =
156-
allTraces.stream()
157-
.map(span -> span.get(0))
158-
.filter(
159-
span -> {
160-
DDSpan ddSpan = (DDSpan) span;
161-
PropagationTags tags = ddSpan.context().getPropagationTags();
162-
return (TRIGGER_PROBE_SESSION_ID + ":1").equals(tags.getDebugPropagation());
163-
})
164-
.count();
165-
assertEquals(100, allTraces.size(), "actual traces: " + allTraces.size());
166-
assertTrue(count <= 25, "Should have at most 25 debug sessions. found: " + count);
167-
}
244+
final String className = "com.datadog.debugger.TriggerProbe01";
245+
TriggerProbe probe1 =
246+
createTriggerProbe(
247+
TRIGGER_PROBE_ID1, TRIGGER_PROBE_SESSION_ID, className, "entry", "()", null, null);
248+
Configuration config = Configuration.builder().setService(SERVICE_NAME).add(probe1).build();
249+
installProbes(config);
250+
Class<?> testClass = compileAndLoadClass(className);
251+
for (int i = 0; i < 100; i++) {
252+
Reflect.onClass(testClass).call("main", "").get();
253+
}
168254

169-
public static TriggerProbe createTriggerProbe(
170-
ProbeId id,
171-
String sessionId,
172-
String typeName,
173-
String methodName,
174-
String signature,
175-
ProbeCondition probeCondition,
176-
Sampling sampling) {
177-
return new TriggerProbe(id, Where.of(typeName, methodName, signature))
178-
.setSessionId(sessionId)
179-
.setProbeCondition(probeCondition)
180-
.setSampling(sampling);
255+
assertTrue(sampler.getCallCount() != 0);
256+
} finally {
257+
ProbeRateLimiter.setSamplerSupplier(null);
258+
}
181259
}
182260
}

0 commit comments

Comments
 (0)