Skip to content
Closed
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
3 changes: 2 additions & 1 deletion dd-java-agent/agent-debugger/debugger-el/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,8 @@ excludedClassesCoverage += [
'com.datadog.debugger.el.Script*',
'com.datadog.debugger.el.ValueScript*',
'com.datadog.debugger.el.values.CollectionValue*',
'com.datadog.debugger.el.InvalidValueException'
'com.datadog.debugger.el.InvalidValueException',
'com.datadog.debugger.el.EvaluationException'
]

dependencies {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
package com.datadog.debugger.el;

import java.util.Objects;

public class EvaluationException extends RuntimeException {
private final String expr;

Expand All @@ -16,4 +18,22 @@ public EvaluationException(String message, String expr, Throwable cause) {
public String getExpr() {
return expr;
}

@Override
public final boolean equals(Object o) {
if (!(o instanceof EvaluationException)) {
return false;
}

EvaluationException that = (EvaluationException) o;
return Objects.equals(getExpr(), that.getExpr())
&& Objects.equals(getMessage(), that.getMessage());
}

@Override
public int hashCode() {
int result = Objects.hashCode(getExpr());
result = 31 * result + Objects.hashCode(getMessage());
return result;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -634,7 +634,10 @@ private List<ToInstrumentInfo> filterAndSortDefinitions(
// Log and span decoration probe shared the same instrumentor: CaptureContextInstrumentor
// and therefore need to be instrumented once
// note: exception probes are log probes and are handled the same way
if (isCapturedContextProbe(definition)) {
if (!Config.get().isDistributedDebuggerEnabled() && definition instanceof TriggerProbe) {
log.debug(
"The distributed debugger feature is disabled. Trigger probes will not be installed.");
} else if (isCapturedContextProbe(definition)) {
if (definition.isLineProbe()) {
capturedContextLineProbes
.computeIfAbsent(definition.getWhere(), key -> new ArrayList<>())
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -59,10 +59,6 @@ public InstrumentationResult.Status instrument(
.instrument();
}

public String getSessionId() {
return sessionId;
}

public TriggerProbe setSessionId(String sessionId) {
this.sessionId = sessionId;
return this;
Expand All @@ -86,6 +82,7 @@ public TriggerProbe setProbeCondition(ProbeCondition probeCondition) {
public void evaluate(
CapturedContext context, CapturedContext.Status status, MethodLocation location) {

Sampling sampling = getSampling();
if (sampling == null || !sampling.inCoolDown()) {
boolean sample = true;
if (!hasCondition()) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,14 @@
import static java.lang.String.format;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertTrue;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.verify;
import static utils.InstrumentationTestHelper.compileAndLoadClass;

import com.datadog.debugger.agent.CapturingTestBase;
import com.datadog.debugger.agent.Configuration;
import com.datadog.debugger.agent.MockSampler;
import com.datadog.debugger.el.EvaluationException;
import com.datadog.debugger.el.ProbeCondition;
import com.datadog.debugger.probe.Sampling;
import com.datadog.debugger.probe.TriggerProbe;
Expand Down Expand Up @@ -50,6 +53,53 @@ public void before() {

setFieldInConfig(Config.get(), "debuggerCodeOriginEnabled", true);
setFieldInConfig(InstrumenterConfig.get(), "codeOriginEnabled", true);
setFieldInConfig(Config.get(), "distributedDebuggerEnabled", true);
}

@Test
public void conditions() throws IOException, URISyntaxException {
final String className = "com.datadog.debugger.TriggerProbe02";
TriggerProbe probe1 =
createTriggerProbe(
TRIGGER_PROBE_ID1,
TRIGGER_PROBE_SESSION_ID,
className,
"entry",
"(int)",
new ProbeCondition(when(lt(ref("value"), value(25))), "value < 25"),
new Sampling(10.0));
installProbes(Configuration.builder().setService(SERVICE_NAME).add(probe1).build());
Class<?> testClass = compileAndLoadClass(className);
for (int i = 0; i < 100; i++) {
Reflect.onClass(testClass).call("main", i).get();
}
List<List<? extends MutableSpan>> allTraces = traceInterceptor.getAllTraces();
long count =
allTraces.stream()
.map(span -> span.get(0))
.filter(
span -> {
DDSpan ddSpan = (DDSpan) span;
PropagationTags tags = ddSpan.context().getPropagationTags();
return (TRIGGER_PROBE_SESSION_ID + ":1").equals(tags.getDebugPropagation());
})
.count();
assertEquals(100, allTraces.size(), "actual traces: " + allTraces.size());
assertTrue(count <= 25, "Should have at most 25 debug sessions. found: " + count);
}

private static TriggerProbe createTriggerProbe(
ProbeId id,
String sessionId,
String typeName,
String methodName,
String signature,
ProbeCondition probeCondition,
Sampling sampling) {
return new TriggerProbe(id, Where.of(typeName, methodName, signature))
.setSessionId(sessionId)
.setProbeCondition(probeCondition)
.setSampling(sampling);
}

@Test
Expand Down Expand Up @@ -104,6 +154,58 @@ public void cooldown() throws IOException, URISyntaxException {
}
}

@Test
public void badCondition() throws IOException, URISyntaxException {
String className = "com.datadog.debugger.TriggerProbe02";
TriggerProbe probe1 =
createTriggerProbe(
TRIGGER_PROBE_ID1,
TRIGGER_PROBE_SESSION_ID,
className,
"entry",
"(int)",
new ProbeCondition(when(lt(ref("limit"), value(25))), "limit < 25"),
new Sampling(10.0));

installProbes(Configuration.builder().setService(SERVICE_NAME).add(probe1).build());
Class<?> testClass = compileAndLoadClass(className);
Reflect.onClass(testClass).call("main", 0).get();
verify(probeStatusSink)
.addError(
eq(TRIGGER_PROBE_ID1),
eq(new EvaluationException("Cannot find symbol: limit", "limit")));
}

@Test
public void debuggerDisabled() throws IOException, URISyntaxException {
boolean original = Config.get().isDistributedDebuggerEnabled();
try {
setFieldInConfig(Config.get(), "distributedDebuggerEnabled", false);

MockSampler sampler = new MockSampler();
ProbeRateLimiter.setSamplerSupplier(value -> sampler);

final String className = "com.datadog.debugger.TriggerProbe02";
TriggerProbe probe1 =
createTriggerProbe(
TRIGGER_PROBE_ID1,
TRIGGER_PROBE_SESSION_ID,
className,
"entry",
"(int)",
new ProbeCondition(when(lt(ref("value"), value(25))), "value < 25"),
new Sampling(10.0));
installProbes(Configuration.builder().setService(SERVICE_NAME).add(probe1).build());
Class<?> testClass = compileAndLoadClass(className);
Reflect.onClass(testClass).call("main", 0).get();

assertEquals(0, sampler.getCallCount());
} finally {
setFieldInConfig(Config.get(), "distributedDebuggerEnabled", original);
ProbeRateLimiter.setSamplerSupplier(null);
}
}

@Test
public void sampling() throws IOException, URISyntaxException {
try {
Expand Down Expand Up @@ -134,49 +236,25 @@ public void sampling() throws IOException, URISyntaxException {
}

@Test
public void conditions() throws IOException, URISyntaxException {
public void noSampling() throws IOException, URISyntaxException {
try {
MockSampler sampler = new MockSampler();
ProbeRateLimiter.setSamplerSupplier(value -> sampler);

final String className = "com.datadog.debugger.TriggerProbe02";
TriggerProbe probe1 =
createTriggerProbe(
TRIGGER_PROBE_ID1,
TRIGGER_PROBE_SESSION_ID,
className,
"entry",
"(int)",
new ProbeCondition(when(lt(ref("value"), value(25))), "value < 25"),
new Sampling(10.0));
installProbes(Configuration.builder().setService(SERVICE_NAME).add(probe1).build());
Class<?> testClass = compileAndLoadClass(className);
for (int i = 0; i < 100; i++) {
Reflect.onClass(testClass).call("main", i).get();
}
List<List<? extends MutableSpan>> allTraces = traceInterceptor.getAllTraces();
long count =
allTraces.stream()
.map(span -> span.get(0))
.filter(
span -> {
DDSpan ddSpan = (DDSpan) span;
PropagationTags tags = ddSpan.context().getPropagationTags();
return (TRIGGER_PROBE_SESSION_ID + ":1").equals(tags.getDebugPropagation());
})
.count();
assertEquals(100, allTraces.size(), "actual traces: " + allTraces.size());
assertTrue(count <= 25, "Should have at most 25 debug sessions. found: " + count);
}
final String className = "com.datadog.debugger.TriggerProbe01";
TriggerProbe probe1 =
createTriggerProbe(
TRIGGER_PROBE_ID1, TRIGGER_PROBE_SESSION_ID, className, "entry", "()", null, null);
Configuration config = Configuration.builder().setService(SERVICE_NAME).add(probe1).build();
installProbes(config);
Class<?> testClass = compileAndLoadClass(className);
for (int i = 0; i < 100; i++) {
Reflect.onClass(testClass).call("main", "").get();
}

public static TriggerProbe createTriggerProbe(
ProbeId id,
String sessionId,
String typeName,
String methodName,
String signature,
ProbeCondition probeCondition,
Sampling sampling) {
return new TriggerProbe(id, Where.of(typeName, methodName, signature))
.setSessionId(sessionId)
.setProbeCondition(probeCondition)
.setSampling(sampling);
assertTrue(sampler.getCallCount() != 0);
} finally {
ProbeRateLimiter.setSamplerSupplier(null);
}
}
}
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
package datadog.trace.instrumentation.couchbase.client;

import static datadog.trace.agent.tooling.bytebuddy.matcher.NameMatchers.named;
import static datadog.trace.bootstrap.instrumentation.api.AgentTracer.activeScope;
import static datadog.trace.bootstrap.instrumentation.api.AgentTracer.activeSpan;
import static java.util.Collections.singletonMap;
import static net.bytebuddy.matcher.ElementMatchers.isMethod;
import static net.bytebuddy.matcher.ElementMatchers.isPublic;
Expand All @@ -13,7 +13,6 @@
import datadog.trace.agent.tooling.InstrumenterModule;
import datadog.trace.bootstrap.ContextStore;
import datadog.trace.bootstrap.InstrumentationContext;
import datadog.trace.bootstrap.instrumentation.api.AgentScope;
import datadog.trace.bootstrap.instrumentation.api.AgentSpan;
import java.util.Map;
import net.bytebuddy.asm.Advice;
Expand Down Expand Up @@ -52,18 +51,15 @@ public static class CouchbaseCoreAdvice {
@Advice.OnMethodExit(suppress = Throwable.class)
public static void addOperationIdToSpan(@Advice.Argument(0) final CouchbaseRequest request) {

final AgentScope scope = activeScope();
if (scope != null) {
// The scope from the initial rxJava subscribe is not available to the networking layer
final AgentSpan span = activeSpan();
if (span != null) {
// The context from the initial rxJava subscribe is not available to the networking layer
// To transfer the span, the span is added to the context store

final ContextStore<CouchbaseRequest, AgentSpan> contextStore =
InstrumentationContext.get(CouchbaseRequest.class, AgentSpan.class);

AgentSpan span = contextStore.get(request);

if (span == null) {
span = scope.span();
if (contextStore.get(request) == null) {
contextStore.put(request, span);

if (request.operationId() != null) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
import com.google.auto.service.AutoService;
import datadog.trace.agent.tooling.Instrumenter;
import datadog.trace.agent.tooling.InstrumenterModule;
import datadog.trace.bootstrap.instrumentation.api.AgentScope;
import io.cucumber.core.backend.StepDefinition;
import net.bytebuddy.asm.Advice;
import net.bytebuddy.description.type.TypeDescription;
Expand Down Expand Up @@ -46,14 +47,14 @@ public void methodAdvice(MethodTransformer transformer) {

public static class CucumberAdvice {
@Advice.OnMethodEnter
public static void onCucumberStepStart(
public static AgentScope onCucumberStepStart(
@Advice.This StepDefinition step, @Advice.Argument(0) Object[] arguments) {
CucumberStepDecorator.DECORATE.onStepStart(step, arguments);
return CucumberStepDecorator.DECORATE.onStepStart(step, arguments);
}

@Advice.OnMethodExit
public static void onCucumberStepFinish(@Advice.This StepDefinition step) {
CucumberStepDecorator.DECORATE.onStepFinish(step);
public static void onCucumberStepFinish(@Advice.Enter AgentScope scope) {
CucumberStepDecorator.DECORATE.onStepFinish(scope);
}

// Cucumber 5.0.0 and above
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,9 +26,8 @@ protected CharSequence component() {
return "cucumber";
}

public void onStepStart(StepDefinition step, Object[] arguments) {
public AgentScope onStepStart(StepDefinition step, Object[] arguments) {
AgentSpan span = AgentTracer.startSpan("cucumber", "cucumber.step");
AgentScope scope = AgentTracer.activateSpan(span);
afterStart(span);

span.setResourceName(step.getPattern());
Expand All @@ -38,20 +37,14 @@ public void onStepStart(StepDefinition step, Object[] arguments) {
if (arguments != null && arguments.length > 0) {
span.setTag("step.arguments", Arrays.toString(arguments));
}
}

public void onStepFinish(StepDefinition step) {
AgentSpan span = AgentTracer.activeSpan();
if (span == null) {
return;
}

AgentScope scope = AgentTracer.activeScope();
if (scope != null) {
scope.close();
}
return AgentTracer.activateSpan(span);
}

public void onStepFinish(AgentScope scope) {
AgentSpan span = scope.span();
beforeFinish(span);
span.finish();
scope.close();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
import datadog.trace.agent.tooling.InstrumenterModule;
import datadog.trace.api.InstrumenterConfig;
import datadog.trace.bootstrap.config.provider.ConfigProvider;
import datadog.trace.bootstrap.instrumentation.api.AgentScope;
import datadog.trace.bootstrap.instrumentation.api.AgentSpan;
import datadog.trace.bootstrap.instrumentation.api.AgentTracer;
import java.util.Arrays;
import net.bytebuddy.asm.Advice;
Expand Down Expand Up @@ -86,8 +86,8 @@ public static final class EnableWallclockSampling {

@Advice.OnMethodEnter(suppress = Throwable.class)
public static boolean before() {
AgentScope active = AgentTracer.activeScope();
if (active == null) {
AgentSpan span = AgentTracer.activeSpan();
if (span == null) {
AgentTracer.get().getProfilingContext().onAttach();
return true;
}
Expand Down
Loading
Loading