Skip to content

Commit c4c84d6

Browse files
add basic exception replay integration in agent mode
1 parent d20159e commit c4c84d6

File tree

5 files changed

+70
-3
lines changed

5 files changed

+70
-3
lines changed

dd-java-agent/agent-ci-visibility/src/main/java/datadog/trace/civisibility/CiVisibilitySystem.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,10 @@ public static void start(Instrumentation inst, SharedCommunicationObjects sco) {
101101
inst.addTransformer(new CoverageClassTransformer(instrumentationFilter));
102102
}
103103

104+
if (executionSettings.isFailedTestReplayEnabled()) {
105+
// TODO
106+
}
107+
104108
CiVisibilityCoverageServices.Child coverageServices =
105109
new CiVisibilityCoverageServices.Child(services, repoServices, executionSettings);
106110
TestEventsHandlerFactory testEventsHandlerFactory =

dd-java-agent/agent-ci-visibility/src/main/java/datadog/trace/civisibility/domain/buildsystem/BuildSystemModuleImpl.java

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,9 @@
1212
import datadog.trace.api.civisibility.domain.JavaAgent;
1313
import datadog.trace.api.civisibility.telemetry.CiVisibilityMetricCollector;
1414
import datadog.trace.api.config.CiVisibilityConfig;
15+
import datadog.trace.api.config.DebuggerConfig;
1516
import datadog.trace.api.config.GeneralConfig;
17+
import datadog.trace.api.config.RemoteConfigConfig;
1618
import datadog.trace.bootstrap.instrumentation.api.AgentSpan;
1719
import datadog.trace.bootstrap.instrumentation.api.AgentSpanContext;
1820
import datadog.trace.bootstrap.instrumentation.api.Tags;
@@ -182,6 +184,20 @@ private Map<String, String> getPropertiesPropagatedToChildProcess(
182184
Strings.propertyNameToSystemPropertyName(CiVisibilityConfig.TEST_MANAGEMENT_ENABLED),
183185
Boolean.toString(executionSettings.getTestManagementSettings().isEnabled()));
184186

187+
// enable exception replay if failed test replay is enabled
188+
if (executionSettings.isFailedTestReplayEnabled()) {
189+
propagatedSystemProperties.put(
190+
Strings.propertyNameToSystemPropertyName(
191+
CiVisibilityConfig.TEST_FAILED_TEST_REPLAY_ENABLED),
192+
"true");
193+
propagatedSystemProperties.put(
194+
Strings.propertyNameToSystemPropertyName(DebuggerConfig.EXCEPTION_REPLAY_ENABLED),
195+
"true");
196+
propagatedSystemProperties.put(
197+
Strings.propertyNameToSystemPropertyName(RemoteConfigConfig.REMOTE_CONFIGURATION_ENABLED),
198+
"true");
199+
}
200+
185201
// explicitly disable build instrumentation in child processes,
186202
// because some projects run "embedded" Maven/Gradle builds as part of their integration tests,
187203
// and we don't want to show those as if they were regular build executions

dd-java-agent/agent-debugger/src/main/java/com/datadog/debugger/exception/DefaultExceptionDebugger.java

Lines changed: 30 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
import com.datadog.debugger.sink.Snapshot;
1010
import com.datadog.debugger.util.CircuitBreaker;
1111
import com.datadog.debugger.util.ExceptionHelper;
12+
import datadog.trace.api.Config;
1213
import datadog.trace.bootstrap.debugger.DebuggerContext;
1314
import datadog.trace.bootstrap.debugger.DebuggerContext.ClassNameFilter;
1415
import datadog.trace.bootstrap.instrumentation.api.AgentSpan;
@@ -34,6 +35,10 @@ public class DefaultExceptionDebugger implements DebuggerContext.ExceptionDebugg
3435
public static final String ERROR_DEBUG_INFO_CAPTURED = "error.debug_info_captured";
3536
public static final String SNAPSHOT_ID_TAG_FMT = DD_DEBUG_ERROR_PREFIX + "%d.snapshot_id";
3637

38+
// Test Optimization / Failed Test Replay specific
39+
public static final String TEST_DEBUG_ERROR_FILE_TAG_FMT = DD_DEBUG_ERROR_PREFIX + "%d.file";
40+
public static final String TEST_DEBUG_ERROR_LINE_TAG_FMT = DD_DEBUG_ERROR_PREFIX + "%d.line";
41+
3742
private final ExceptionProbeManager exceptionProbeManager;
3843
private final ConfigurationUpdater configurationUpdater;
3944
private final ClassNameFilter classNameFiltering;
@@ -69,7 +74,7 @@ public DefaultExceptionDebugger(
6974

7075
@Override
7176
public void handleException(Throwable t, AgentSpan span) {
72-
if (t instanceof Error) {
77+
if (t instanceof Error && !Config.get().isCiVisibilityEnabled()) {
7378
if (LOGGER.isDebugEnabled()) {
7479
LOGGER.debug("Skip handling error: {}", t.toString());
7580
}
@@ -93,6 +98,7 @@ public void handleException(Throwable t, AgentSpan span) {
9398
if (exceptionProbeManager.isAlreadyInstrumented(fingerprint)) {
9499
ThrowableState state = exceptionProbeManager.getStateByThrowable(innerMostException);
95100
if (state == null) {
101+
LOGGER.info("Unable to find state for throwable: {}", innerMostException.toString());
96102
LOGGER.debug("Unable to find state for throwable: {}", innerMostException.toString());
97103
return;
98104
}
@@ -108,7 +114,12 @@ public void handleException(Throwable t, AgentSpan span) {
108114
exceptionProbeManager.createProbesForException(
109115
throwable.getStackTrace(), chainedExceptionIdx);
110116
if (creationResult.probesCreated > 0) {
111-
AgentTaskScheduler.INSTANCE.execute(() -> applyExceptionConfiguration(fingerprint));
117+
LOGGER.info("Creating probes for: {}", t.getMessage());
118+
if (Config.get().isCiVisibilityEnabled()) {
119+
applyExceptionConfiguration(fingerprint);
120+
} else {
121+
AgentTaskScheduler.INSTANCE.execute(() -> applyExceptionConfiguration(fingerprint));
122+
}
112123
break;
113124
} else {
114125
if (LOGGER.isDebugEnabled()) {
@@ -147,6 +158,7 @@ private static void processSnapshotsAndSetTags(
147158
}
148159
});
149160
}
161+
LOGGER.info("Processing exception snapshot for: {}", t.getMessage());
150162
boolean snapshotAssigned = false;
151163
List<Snapshot> snapshots = state.getSnapshots();
152164
int maxSnapshotSize = Math.min(snapshots.size(), maxCapturedFrames);
@@ -166,10 +178,26 @@ private static void processSnapshotsAndSetTags(
166178
String tagName = String.format(SNAPSHOT_ID_TAG_FMT, frameIndex);
167179
span.setTag(tagName, snapshot.getId());
168180
LOGGER.debug("add tag to span[{}]: {}: {}", span.getSpanId(), tagName, snapshot.getId());
181+
182+
StackTraceElement stackFrame = innerTrace[currentIdx];
183+
String fileTag = String.format(TEST_DEBUG_ERROR_FILE_TAG_FMT, frameIndex);
184+
String lineTag = String.format(TEST_DEBUG_ERROR_LINE_TAG_FMT, frameIndex);
185+
span.setTag(fileTag, stackFrame.getFileName());
186+
span.setTag(lineTag, stackFrame.getLineNumber());
187+
188+
LOGGER.debug(
189+
"add ftr debug tags to span[{}]: {}={}, {}={}",
190+
span.getSpanId(),
191+
fileTag,
192+
stackFrame.getFileName(),
193+
lineTag,
194+
stackFrame.getLineNumber());
195+
169196
if (!state.isSnapshotSent()) {
170197
DebuggerAgent.getSink().addSnapshot(snapshot);
171198
}
172199
snapshotAssigned = true;
200+
LOGGER.info("Capture for {}: {}", t.getMessage(), snapshots.get(i).getVariables());
173201
}
174202
if (snapshotAssigned) {
175203
state.markAsSnapshotSent();

dd-java-agent/agent-debugger/src/main/java/com/datadog/debugger/sink/Snapshot.java

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
import java.util.List;
1313
import java.util.Map;
1414
import java.util.Objects;
15+
import java.util.stream.Collectors;
1516

1617
/** Data class representing all data collected at a probe location */
1718
public class Snapshot {
@@ -161,6 +162,18 @@ public List<EvaluationError> getEvaluationErrors() {
161162
return evaluationErrors;
162163
}
163164

165+
public String getVariables() {
166+
String variables = "";
167+
CapturedContext returnContext = captures.getReturn();
168+
if (returnContext != null) {
169+
Map<String, CapturedContext.CapturedValue> allVars = new HashMap<>();
170+
if (returnContext.getArguments() != null) allVars.putAll(returnContext.getArguments());
171+
if (returnContext.getLocals() != null) allVars.putAll(returnContext.getLocals());
172+
variables = allVars.entrySet().stream().map(e -> e.getKey() + "=" + e.getValue().getStrValue()).collect(Collectors.joining(", "));
173+
}
174+
return variables;
175+
}
176+
164177
public void addEvaluationErrors(List<EvaluationError> errors) {
165178
if (errors == null || errors.isEmpty()) {
166179
return;

internal-api/src/main/java/datadog/trace/api/Config.java

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4009,7 +4009,13 @@ public Set<String> getThirdPartyShadingIdentifiers() {
40094009
}
40104010

40114011
private String getFinalDebuggerBaseUrl() {
4012-
if (agentUrl.startsWith("unix:")) {
4012+
if (isCiVisibilityEnabled() && isCiVisibilityAgentlessEnabled()) {
4013+
String agentlessUrl = getCiVisibilityAgentlessUrl();
4014+
if (Strings.isNotBlank(agentlessUrl)) {
4015+
return agentlessUrl;
4016+
}
4017+
return "https://http-intake.logs." + getSite();
4018+
} else if (agentUrl.startsWith("unix:")) {
40134019
// provide placeholder agent URL, in practice we'll be tunnelling over UDS
40144020
return "http://" + agentHost + ":" + agentPort;
40154021
} else {

0 commit comments

Comments
 (0)