Skip to content

Commit

Permalink
Implement the DebuggerProbe (#7588)
Browse files Browse the repository at this point in the history
Implement the DebuggerProbe. [DEBUG-2719]
Update code origin tags  [DEBUG-2722]
  • Loading branch information
evanchooly authored Sep 11, 2024
1 parent efc6f52 commit 4abf841
Show file tree
Hide file tree
Showing 45 changed files with 1,287 additions and 758 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -67,8 +67,8 @@ public interface ExceptionDebugger {
void handleException(Throwable t, AgentSpan span);
}

public interface SpanDebugger {
String captureSnapshot(String signature);
public interface CodeOriginRecorder {
String captureCodeOrigin(String signature);
}

private static volatile ProbeResolver probeResolver;
Expand All @@ -77,7 +77,7 @@ public interface SpanDebugger {
private static volatile Tracer tracer;
private static volatile ValueSerializer valueSerializer;
private static volatile ExceptionDebugger exceptionDebugger;
private static volatile SpanDebugger spanDebugger;
private static volatile CodeOriginRecorder codeOriginRecorder;

public static void initProbeResolver(ProbeResolver probeResolver) {
DebuggerContext.probeResolver = probeResolver;
Expand All @@ -103,8 +103,8 @@ public static void initExceptionDebugger(ExceptionDebugger exceptionDebugger) {
DebuggerContext.exceptionDebugger = exceptionDebugger;
}

public static void initSpanDebugger(SpanDebugger spanDebugger) {
DebuggerContext.spanDebugger = spanDebugger;
public static void initCodeOrigin(CodeOriginRecorder codeOriginRecorder) {
DebuggerContext.codeOriginRecorder = codeOriginRecorder;
}

/**
Expand Down Expand Up @@ -342,14 +342,14 @@ public static void commit(
}
}

public static String captureSnapshot(String signature) {
public static String captureCodeOrigin(String signature) {
try {
SpanDebugger debugger = spanDebugger;
if (debugger != null) {
return debugger.captureSnapshot(signature);
CodeOriginRecorder recorder = codeOriginRecorder;
if (recorder != null) {
return recorder.captureCodeOrigin(signature);
}
} catch (Exception ex) {
LOGGER.debug("Error in addSnapshot: ", ex);
LOGGER.debug("Error in captureCodeOrigin: ", ex);
}
return null;
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,27 +1,30 @@
package datadog.trace.bootstrap.debugger.spanorigin;

import static datadog.trace.bootstrap.debugger.DebuggerContext.captureSnapshot;
import static datadog.trace.bootstrap.debugger.DebuggerContext.captureCodeOrigin;
import static java.util.Arrays.stream;

import datadog.trace.api.InstrumenterConfig;
import datadog.trace.bootstrap.instrumentation.api.AgentSpan;
import java.lang.reflect.Method;
import java.util.stream.Collectors;

public class SpanOriginInfo {
public static void entry(AgentSpan span, Method method) {
if (InstrumenterConfig.get().isSpanOriginEnabled()) {
public class CodeOriginInfo {
public static void entry(Method method) {
if (InstrumenterConfig.get().isCodeOriginEnabled()) {
String signature =
stream(method.getParameterTypes())
.map(Class::getName)
.collect(Collectors.joining(",", "(", ")"));
captureSnapshot(signature);
captureCodeOrigin(signature);
}
}

public static void exit(AgentSpan span) {
if (InstrumenterConfig.get().isSpanOriginEnabled()) {
span.getLocalRootSpan().setMetaStruct(captureSnapshot(null), span);
if (InstrumenterConfig.get().isCodeOriginEnabled()) {
String probeId = captureCodeOrigin(null);
if (span != null) {
span.getLocalRootSpan().setTag(probeId, span);
}
}
}
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package com.datadog.debugger.agent;

import com.datadog.debugger.probe.DebuggerProbe;
import com.datadog.debugger.probe.ExceptionProbe;
import com.datadog.debugger.probe.LogProbe;
import com.datadog.debugger.probe.MetricProbe;
Expand Down Expand Up @@ -65,6 +66,7 @@ public int hashCode() {
private final Collection<MetricProbe> metricProbes;
private final Collection<LogProbe> logProbes;
private final Collection<SpanProbe> spanProbes;
private final Collection<DebuggerProbe> debuggerProbes;
private final Collection<SpanDecorationProbe> spanDecorationProbes;
private final FilterList allowList;
private final FilterList denyList;
Expand All @@ -79,14 +81,15 @@ public Configuration(
Collection<MetricProbe> metricProbes,
Collection<LogProbe> logProbes,
Collection<SpanProbe> spanProbes) {
this(serviceName, metricProbes, logProbes, spanProbes, null, null, null, null);
this(serviceName, metricProbes, logProbes, spanProbes, null, null, null, null, null);
}

public Configuration(
String serviceName,
Collection<MetricProbe> metricProbes,
Collection<LogProbe> logProbes,
Collection<SpanProbe> spanProbes,
Collection<DebuggerProbe> debuggerProbes,
Collection<SpanDecorationProbe> spanDecorationProbes,
FilterList allowList,
FilterList denyList,
Expand All @@ -95,6 +98,7 @@ public Configuration(
this.metricProbes = metricProbes;
this.logProbes = logProbes;
this.spanProbes = spanProbes;
this.debuggerProbes = debuggerProbes;
this.spanDecorationProbes = spanDecorationProbes;
this.allowList = allowList;
this.denyList = denyList;
Expand All @@ -117,6 +121,10 @@ public Collection<SpanProbe> getSpanProbes() {
return spanProbes;
}

public Collection<DebuggerProbe> getDebuggerProbes() {
return debuggerProbes;
}

public Collection<SpanDecorationProbe> getSpanDecorationProbes() {
return spanDecorationProbes;
}
Expand All @@ -135,6 +143,9 @@ public LogProbe.Sampling getSampling() {

public Collection<ProbeDefinition> getDefinitions() {
Collection<ProbeDefinition> result = new ArrayList<>();
if (debuggerProbes != null) {
result.addAll(debuggerProbes);
}
if (metricProbes != null) {
result.addAll(metricProbes);
}
Expand Down Expand Up @@ -198,6 +209,7 @@ public static class Builder {
private List<MetricProbe> metricProbes = null;
private List<LogProbe> logProbes = null;
private List<SpanProbe> spanProbes = null;
private List<DebuggerProbe> debuggerProbes = null;
private List<SpanDecorationProbe> spanDecorationProbes = null;
private FilterList allowList = null;
private FilterList denyList = null;
Expand All @@ -214,6 +226,7 @@ public Configuration.Builder add(Collection<? extends ProbeDefinition> definitio
}
for (ProbeDefinition definition : definitions) {
if (definition instanceof MetricProbe) add((MetricProbe) definition);
if (definition instanceof DebuggerProbe) add((DebuggerProbe) definition);
if (definition instanceof LogProbe) add((LogProbe) definition);
if (definition instanceof SpanProbe) add((SpanProbe) definition);
if (definition instanceof SpanDecorationProbe) add((SpanDecorationProbe) definition);
Expand Down Expand Up @@ -245,6 +258,14 @@ public Configuration.Builder add(SpanProbe probe) {
return this;
}

public Configuration.Builder add(DebuggerProbe probe) {
if (debuggerProbes == null) {
debuggerProbes = new ArrayList<>();
}
debuggerProbes.add(probe);
return this;
}

public Configuration.Builder add(SpanDecorationProbe probe) {
if (spanDecorationProbes == null) {
spanDecorationProbes = new ArrayList<>();
Expand Down Expand Up @@ -300,6 +321,16 @@ public Configuration.Builder addSpanProbes(Collection<SpanProbe> probes) {
return this;
}

public Configuration.Builder addDebuggerProbes(Collection<DebuggerProbe> probes) {
if (probes == null) {
return this;
}
for (DebuggerProbe probe : probes) {
add(probe);
}
return this;
}

public Configuration.Builder addSpanDecorationProbes(Collection<SpanDecorationProbe> probes) {
if (probes == null) {
return this;
Expand Down Expand Up @@ -346,6 +377,7 @@ public Configuration.Builder add(Configuration other) {
addMetricProbes(other.getMetricProbes());
addLogProbes(other.getLogProbes());
addSpanProbes(other.getSpanProbes());
addDebuggerProbes(other.getDebuggerProbes());
addSpanDecorationProbes(other.getSpanDecorationProbes());
addAllowList(other.getAllowList());
addDenyList(other.getDenyList());
Expand All @@ -359,6 +391,7 @@ public Configuration build() {
metricProbes,
logProbes,
spanProbes,
debuggerProbes,
spanDecorationProbes,
allowList,
denyList,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
public interface ConfigurationAcceptor {
enum Source {
REMOTE_CONFIG,
SPAN_DEBUG,
CODE_ORIGIN,
EXCEPTION
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,14 @@
import static com.datadog.debugger.agent.ConfigurationAcceptor.Source.REMOTE_CONFIG;
import static datadog.trace.util.AgentThreadFactory.AGENT_THREAD_GROUP;

import com.datadog.debugger.codeorigin.CodeOriginProbeManager;
import com.datadog.debugger.codeorigin.DefaultCodeOriginRecorder;
import com.datadog.debugger.exception.DefaultExceptionDebugger;
import com.datadog.debugger.exception.ExceptionProbeManager;
import com.datadog.debugger.sink.DebuggerSink;
import com.datadog.debugger.sink.ProbeStatusSink;
import com.datadog.debugger.sink.SnapshotSink;
import com.datadog.debugger.sink.SymbolSink;
import com.datadog.debugger.snapshot.DefaultSpanDebugger;
import com.datadog.debugger.symbol.SymDBEnablement;
import com.datadog.debugger.symbol.SymbolAggregator;
import com.datadog.debugger.uploader.BatchUploader;
Expand Down Expand Up @@ -102,9 +103,10 @@ public static synchronized void run(
config.getDebuggerMaxExceptionPerSecond());
DebuggerContext.initExceptionDebugger(defaultExceptionDebugger);
}
if (config.isDebuggerSpanDebugEnabled()) {
DebuggerContext.initSpanDebugger(
new DefaultSpanDebugger(configurationUpdater, classNameFiltering));
if (config.isDebuggerCodeOriginEnabled()) {
DebuggerContext.initCodeOrigin(
new DefaultCodeOriginRecorder(
new CodeOriginProbeManager(configurationUpdater, classNameFiltering)));
}
if (config.isDebuggerInstrumentTheWorld()) {
setupInstrumentTheWorldTransformer(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import static com.datadog.debugger.agent.ConfigurationAcceptor.Source.REMOTE_CONFIG;

import com.datadog.debugger.probe.DebuggerProbe;
import com.datadog.debugger.probe.LogProbe;
import com.datadog.debugger.probe.MetricProbe;
import com.datadog.debugger.probe.ProbeDefinition;
Expand All @@ -28,13 +29,15 @@
import org.slf4j.LoggerFactory;

public class DebuggerProductChangesListener implements ProductListener {
public static final int MAX_ALLOWED_DEBUGGER_PROBES = 100;
public static final int MAX_ALLOWED_METRIC_PROBES = 100;
public static final int MAX_ALLOWED_LOG_PROBES = 100;
public static final int MAX_ALLOWED_SPAN_PROBES = 100;
public static final int MAX_ALLOWED_SPAN_DECORATION_PROBES = 100;
public static final String LOG_PROBE_PREFIX = "logProbe_";
public static final String METRIC_PROBE_PREFIX = "metricProbe_";
public static final String SPAN_PROBE_PREFIX = "spanProbe_";
public static final String DEBUGGER_PROBE_PREFIX = "debuggerProbe_";
public static final String SPAN_DECORATION_PROBE_PREFIX = "spanDecorationProbe_";
private static final Logger LOGGER =
LoggerFactory.getLogger(DebuggerProductChangesListener.class);
Expand All @@ -52,6 +55,9 @@ static class Adapter {
static final JsonAdapter<SpanProbe> SPAN_PROBE_JSON_ADAPTER =
MoshiHelper.createMoshiConfig().adapter(SpanProbe.class);

static final JsonAdapter<DebuggerProbe> DEBUGGER_PROBE_JSON_ADAPTER =
MoshiHelper.createMoshiConfig().adapter(DebuggerProbe.class);

static final JsonAdapter<SpanDecorationProbe> SPAN_DECORATION_PROBE_JSON_ADAPTER =
MoshiHelper.createMoshiConfig().adapter(SpanDecorationProbe.class);

Expand All @@ -71,6 +77,10 @@ static SpanProbe deserializeSpanProbe(byte[] content) throws IOException {
return deserialize(SPAN_PROBE_JSON_ADAPTER, content);
}

static DebuggerProbe deserializeDebuggerProbe(byte[] content) throws IOException {
return deserialize(DEBUGGER_PROBE_JSON_ADAPTER, content);
}

static SpanDecorationProbe deserializeSpanDecorationProbe(byte[] content) throws IOException {
return deserialize(SPAN_DECORATION_PROBE_JSON_ADAPTER, content);
}
Expand Down Expand Up @@ -108,6 +118,9 @@ public void accept(ConfigKey configKey, byte[] content, PollingRateHinter pollin
} else if (configId.startsWith(SPAN_PROBE_PREFIX)) {
SpanProbe spanProbe = Adapter.deserializeSpanProbe(content);
configChunks.put(configId, definitions -> definitions.add(spanProbe));
} else if (configId.startsWith(DEBUGGER_PROBE_PREFIX)) {
DebuggerProbe debuggerProbe = Adapter.deserializeDebuggerProbe(content);
configChunks.put(configId, definitions -> definitions.add(debuggerProbe));
} else if (configId.startsWith(SPAN_DECORATION_PROBE_PREFIX)) {
SpanDecorationProbe spanDecorationProbe = Adapter.deserializeSpanDecorationProbe(content);
configChunks.put(configId, definitions -> definitions.add(spanDecorationProbe));
Expand Down Expand Up @@ -148,6 +161,7 @@ public void commit(PollingRateHinter pollingRateHinter) {

static class DefinitionBuilder {
private final Collection<ProbeDefinition> definitions = new ArrayList<>();
private int debuggerProbeCount = 0;
private int metricProbeCount = 0;
private int logProbeCount = 0;
private int spanProbeCount = 0;
Expand Down Expand Up @@ -180,6 +194,15 @@ void add(SpanProbe probe) {
spanProbeCount++;
}

void add(DebuggerProbe probe) {
if (debuggerProbeCount >= MAX_ALLOWED_DEBUGGER_PROBES) {
LOGGER.debug("Max allowed debugger probes reached, ignoring new probe: {}", probe);
return;
}
definitions.add(probe);
debuggerProbeCount++;
}

void add(SpanDecorationProbe probe) {
if (spanDecorationProbeCount >= MAX_ALLOWED_SPAN_DECORATION_PROBES) {
LOGGER.debug("Max allowed span decoration probes reached, ignoring new probe: {}", probe);
Expand All @@ -197,6 +220,8 @@ void addAll(Collection<ProbeDefinition> newDefinitions) {
add((LogProbe) definition);
} else if (definition instanceof SpanProbe) {
add((SpanProbe) definition);
} else if (definition instanceof DebuggerProbe) {
add((DebuggerProbe) definition);
} else if (definition instanceof SpanDecorationProbe) {
add((SpanDecorationProbe) definition);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
import com.datadog.debugger.instrumentation.DiagnosticMessage;
import com.datadog.debugger.instrumentation.InstrumentationResult;
import com.datadog.debugger.instrumentation.MethodInfo;
import com.datadog.debugger.probe.DebuggerProbe;
import com.datadog.debugger.probe.ExceptionProbe;
import com.datadog.debugger.probe.ForceMethodInstrumentation;
import com.datadog.debugger.probe.LogProbe;
Expand Down Expand Up @@ -77,7 +78,12 @@ public class DebuggerTransformer implements ClassFileTransformer {
private static final String CANNOT_FIND_LINE = "No executable code was found at %s:L%s";
private static final Pattern COMMA_PATTERN = Pattern.compile(",");
private static final List<Class<?>> PROBE_ORDER =
Arrays.asList(MetricProbe.class, LogProbe.class, SpanDecorationProbe.class, SpanProbe.class);
Arrays.asList(
DebuggerProbe.class,
MetricProbe.class,
LogProbe.class,
SpanDecorationProbe.class,
SpanProbe.class);
private static final String JAVA_IO_TMPDIR = "java.io.tmpdir";

private final Config config;
Expand Down Expand Up @@ -212,7 +218,7 @@ private Map<Where, List<ProbeDefinition>> mergeLocations(
Map<Where, List<ProbeDefinition>> mergedProbes = new HashMap<>();
for (ProbeDefinition definition : definitions) {
Where where = definition.getWhere();
if (definition instanceof ExceptionProbe) {
if (definition instanceof ForceMethodInstrumentation) {
// normalize where for line => to precise method location
where = Where.convertLineToMethod(definition.getWhere(), classFileLines);
}
Expand Down Expand Up @@ -411,7 +417,7 @@ private void verifyByteCode(String classFilePath, byte[] classFile) {
if (!result.isEmpty()) {
log.warn("Verification of instrumented class {} failed", classFilePath);
log.debug("Verify result: {}", stringWriter);
throw new RuntimeException("Generated bydecode is invalid for " + classFilePath);
throw new RuntimeException("Generated bytecode is invalid for " + classFilePath);
}
}

Expand Down
Loading

0 comments on commit 4abf841

Please sign in to comment.