Skip to content

Commit

Permalink
Refactoring and fix stacktrace recording
Browse files Browse the repository at this point in the history
  • Loading branch information
jpbempel committed Mar 19, 2024
1 parent 2a8b908 commit 8c50d27
Show file tree
Hide file tree
Showing 3 changed files with 63 additions and 41 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -21,9 +21,10 @@
*/
public class DefaultExceptionDebugger implements DebuggerContext.ExceptionDebugger {
private static final Logger LOGGER = LoggerFactory.getLogger(DefaultExceptionDebugger.class);
public static final String DD_DEBUG_ERROR_EXCEPTION_ID = "_dd.debug.error.exception_id";
public static final String DD_DEBUG_ERROR_PREFIX = "_dd.debug.error.";
public static final String DD_DEBUG_ERROR_EXCEPTION_ID = DD_DEBUG_ERROR_PREFIX + "exception_id";
public static final String ERROR_DEBUG_INFO_CAPTURED = "error.debug_info_captured";
public static final String SNAPSHOT_ID_TAG_FMT = "_dd.debug.error.%d.snapshot_id";
public static final String SNAPSHOT_ID_TAG_FMT = DD_DEBUG_ERROR_PREFIX + "%d.snapshot_id";

private final ExceptionProbeManager exceptionProbeManager;
private final ConfigurationUpdater configurationUpdater;
Expand Down Expand Up @@ -61,51 +62,60 @@ public void handleException(Throwable t, AgentSpan span) {
LOGGER.debug("Unable to find state for throwable: {}", innerMostException.toString());
return;
}
span.setTag(ERROR_DEBUG_INFO_CAPTURED, true);
if (span.getTag(DD_DEBUG_ERROR_EXCEPTION_ID) != null) {
LOGGER.debug("Clear previous frame tags");
// already set for this span, clear the frame tags
span.getTags()
.forEach(
(k, v) -> {
if (k.startsWith("_dd.debug.error.")) {
span.setTag(k, (String) null);
}
});
processSnapshotsAndSetTags(t, span, state, innerMostException);
} else {
exceptionProbeManager.createProbesForException(
fingerprint, innerMostException.getStackTrace());
// TODO make it async
configurationUpdater.accept(EXCEPTION, exceptionProbeManager.getProbes());
}
}

private static void processSnapshotsAndSetTags(
Throwable t, AgentSpan span, ThrowableState state, Throwable innerMostException) {
if (span.getTag(DD_DEBUG_ERROR_EXCEPTION_ID) != null) {
LOGGER.debug("Clear previous frame tags");
// already set for this span, clear the frame tags
span.getTags()
.forEach(
(k, v) -> {
if (k.startsWith(DD_DEBUG_ERROR_PREFIX)) {
span.setTag(k, (String) null);
}
});
}
int[] mapping = createThrowableMapping(innerMostException, t);
StackTraceElement[] innerTrace = innerMostException.getStackTrace();
int currentIdx = 0;
boolean snapshotAssigned = false;
List<Snapshot> snapshots = state.getSnapshots();
for (int i = 0; i < snapshots.size(); i++) {
Snapshot snapshot = snapshots.get(i);
String className = snapshot.getProbe().getLocation().getType();
String methodName = snapshot.getProbe().getLocation().getMethod();
while (currentIdx < innerTrace.length
&& !innerTrace[currentIdx].getClassName().equals(className)
&& !innerTrace[currentIdx].getMethodName().equals(methodName)) {
currentIdx++;
}
int frameIndex = mapping[currentIdx++];
if (frameIndex == -1) {
continue;
}
String tagName = String.format(SNAPSHOT_ID_TAG_FMT, frameIndex);
span.setTag(tagName, snapshot.getId());
LOGGER.debug("add tag to span[{}]: {}: {}", span.getSpanId(), tagName, snapshot.getId());
DebuggerAgent.getSink().addSnapshot(snapshot);
snapshotAssigned = true;
}
if (snapshotAssigned) {
span.setTag(DD_DEBUG_ERROR_EXCEPTION_ID, state.getExceptionId());
LOGGER.debug(
"add tag to span[{}]: {}: {}",
span.getSpanId(),
DD_DEBUG_ERROR_EXCEPTION_ID,
state.getExceptionId());
int[] mapping = createThrowableMapping(innerMostException, t);
StackTraceElement[] innerTrace = innerMostException.getStackTrace();
int currentIdx = 0;
List<Snapshot> snapshots = state.getSnapshots();
for (int i = 0; i < snapshots.size(); i++) {
Snapshot snapshot = snapshots.get(i);
String className = snapshot.getProbe().getLocation().getType();
String methodName = snapshot.getProbe().getLocation().getMethod();
while (currentIdx < innerTrace.length
&& !innerTrace[currentIdx].getClassName().equals(className)
&& !innerTrace[currentIdx].getMethodName().equals(methodName)) {
currentIdx++;
}
int frameIndex = mapping[currentIdx++];
if (frameIndex == -1) {
continue;
}
String tagName = String.format(SNAPSHOT_ID_TAG_FMT, frameIndex);
span.setTag(tagName, snapshot.getId());
LOGGER.debug("add tag to span[{}]: {}: {}", span.getSpanId(), tagName, snapshot.getId());
DebuggerAgent.getSink().addSnapshot(snapshot);
}
} else {
exceptionProbeManager.createProbesForException(
fingerprint, innerMostException.getStackTrace());
// TODO make it async
configurationUpdater.accept(EXCEPTION, exceptionProbeManager.getProbes());
span.setTag(ERROR_DEBUG_INFO_CAPTURED, true);
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,15 @@ public void commit(
Snapshot snapshot = createSnapshot();
boolean shouldCommit = fillSnapshot(entryContext, exitContext, caughtExceptions, snapshot);
if (shouldCommit) {
snapshot.recordStackTrace(5);
/*
* Record stack trace having the caller of this method as 'top' frame.
* For this it is necessary to discard:
* - Thread.currentThread().getStackTrace()
* - Snapshot.recordStackTrace()
* - ExceptionProbe.commit()
* - DebuggerContext.commit()
*/
snapshot.recordStackTrace(4);
// add snapshot for later to wait for triggering point (ExceptionDebugger::handleException)
exceptionProbeManager.addSnapshot(snapshot);
LOGGER.debug(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
import datadog.trace.api.Config;
import datadog.trace.api.interceptor.MutableSpan;
import datadog.trace.bootstrap.debugger.DebuggerContext;
import datadog.trace.bootstrap.debugger.ProbeLocation;
import datadog.trace.core.CoreTracer;
import java.lang.instrument.ClassFileTransformer;
import java.lang.instrument.Instrumentation;
Expand Down Expand Up @@ -100,6 +101,9 @@ public void instrumentAndCaptureSnapshots() throws Exception {
assertProbeId(probeIdsByMethodName, "processWithException", snapshot0.getProbe().getId());
assertEquals("oops", snapshot0.getCaptures().getReturn().getCapturedThrowable().getMessage());
assertTrue(snapshot0.getCaptures().getReturn().getLocals().containsKey("@exception"));
ProbeLocation location = snapshot0.getProbe().getLocation();
assertEquals(
location.getType() + "." + location.getMethod(), snapshot0.getStack().get(0).getFunction());
MutableSpan span = traceInterceptor.getFirstSpan();
assertEquals(snapshot0.getExceptionId(), span.getTags().get(DD_DEBUG_ERROR_EXCEPTION_ID));
assertEquals(Boolean.TRUE, span.getTags().get(ERROR_DEBUG_INFO_CAPTURED));
Expand Down

0 comments on commit 8c50d27

Please sign in to comment.