Skip to content

Commit c85d09f

Browse files
authored
Split CapturedContext instrumenters (#9778)
make it a specialized version for single probe and keep the previous one as the fallback when multiple probes need to be instrumented for the same location. Introduced SingleCapturedContextIntrumenter and MultipleCapturedContextInstrumenter based on current CapturedContextInstrumenter. Introduced specialized version with only one probe index of methods in DebuggerContext called from the instrumetnation. Introduced CapturedContextProbe interface and move some specific methods for LogProbe from ProbeImplementation. This allow to implement later some optimized version of the instrumentation which is not the case right now. This for now just a refactoring for preparing the next ones
1 parent 4737935 commit c85d09f

20 files changed

+440
-174
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
package datadog.trace.bootstrap.debugger;
2+
3+
public interface CapturedContextProbe {
4+
boolean isCaptureSnapshot();
5+
6+
boolean hasCondition();
7+
8+
boolean isReadyToCapture();
9+
}

dd-java-agent/agent-debugger/debugger-bootstrap/src/main/java/datadog/trace/bootstrap/debugger/DebuggerContext.java

Lines changed: 106 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -246,7 +246,8 @@ public static DebuggerSpan createSpan(String probeId, String operationName, Stri
246246
}
247247

248248
/**
249-
* tests whether the provided probe Ids are ready for capturing data
249+
* tests whether the provided probe Ids are ready for capturing data it allows to skip capture
250+
* part if no condition and sampling is returns false
250251
*
251252
* @return true if can proceed to capture data
252253
*/
@@ -259,6 +260,22 @@ public static boolean isReadyToCapture(Class<?> callingClass, int... probeIndice
259260
}
260261
}
261262

263+
public static boolean isReadyToCapture(Class<?> callingClass, int probeIndex) {
264+
try {
265+
ProbeImplementation probeImplementation = resolveProbe(probeIndex);
266+
if (probeImplementation == null) {
267+
return false;
268+
}
269+
if (((CapturedContextProbe) probeImplementation).isReadyToCapture()) {
270+
return checkAndSetInProbe();
271+
}
272+
return false;
273+
} catch (Exception ex) {
274+
LOGGER.debug("Error in isReadyToCapture: ", ex);
275+
return false;
276+
}
277+
}
278+
262279
public static void disableInProbe() {
263280
IN_PROBE.set(Boolean.FALSE);
264281
}
@@ -277,7 +294,7 @@ public static boolean checkAndSetInProbe() {
277294
}
278295
/**
279296
* resolve probe details based on probe ids and evaluate the captured context regarding summary &
280-
* conditions This is for method probes
297+
* conditions. This is for method probes.
281298
*/
282299
public static void evalContext(
283300
CapturedContext context,
@@ -310,7 +327,38 @@ public static void evalContext(
310327
}
311328

312329
/**
313-
* resolve probe details based on probe ids, evaluate the captured context regarding summary &
330+
* Optimized version of {@link DebuggerContext#evalContext(CapturedContext, Class, long,
331+
* MethodLocation, int...)} for single probe
332+
*/
333+
public static void evalContext(
334+
CapturedContext context,
335+
Class<?> callingClass,
336+
long startTimestamp,
337+
MethodLocation methodLocation,
338+
int probeIndex) {
339+
try {
340+
ProbeImplementation probeImplementation = resolveProbe(probeIndex);
341+
if (probeImplementation == null) {
342+
return;
343+
}
344+
CapturedContext.Status status =
345+
context.evaluate(
346+
probeImplementation, callingClass.getTypeName(), startTimestamp, methodLocation);
347+
boolean needFreeze = status.shouldFreezeContext();
348+
// only freeze the context when we have at lest one snapshot probe, and we should send
349+
// snapshot
350+
if (needFreeze) {
351+
Duration timeout =
352+
Duration.of(Config.get().getDynamicInstrumentationCaptureTimeout(), ChronoUnit.MILLIS);
353+
context.freeze(new TimeoutChecker(timeout));
354+
}
355+
} catch (Exception ex) {
356+
LOGGER.debug("Error in evalContext: ", ex);
357+
}
358+
}
359+
360+
/**
361+
* resolve probe details based on probe indices, evaluate the captured context regarding summary &
314362
* conditions and commit snapshot to send it if needed. This is for line probes.
315363
*/
316364
public static void evalContextAndCommit(
@@ -334,6 +382,26 @@ public static void evalContextAndCommit(
334382
}
335383
}
336384

385+
/**
386+
* Optimized version of {@link DebuggerContext#evalContextAndCommit(CapturedContext, Class, int,
387+
* int...)} for single probe
388+
*/
389+
public static void evalContextAndCommit(
390+
CapturedContext context, Class<?> callingClass, int line, int probeIndex) {
391+
// Cannot call the multi probe version here, because it will add a new level for stacktrace
392+
// recording
393+
try {
394+
ProbeImplementation probeImplementation = resolveProbe(probeIndex);
395+
if (probeImplementation == null) {
396+
return;
397+
}
398+
context.evaluate(probeImplementation, callingClass.getTypeName(), -1, MethodLocation.DEFAULT);
399+
probeImplementation.commit(context, line);
400+
} catch (Exception ex) {
401+
LOGGER.debug("Error in evalContextAndCommit: ", ex);
402+
}
403+
}
404+
337405
public static void codeOrigin(int probeIndex) {
338406
try {
339407
ProbeImplementation probe = probeResolver.resolve(probeIndex);
@@ -381,6 +449,41 @@ public static void commit(
381449
}
382450
}
383451

452+
/**
453+
* Optimized version of {@link DebuggerContext#commit(CapturedContext, CapturedContext, List,
454+
* int...)} for single probe
455+
*/
456+
public static void commit(
457+
CapturedContext entryContext,
458+
CapturedContext exitContext,
459+
List<CapturedContext.CapturedThrowable> caughtExceptions,
460+
int probeIndex) {
461+
// Cannot call the multi probe version here, because it will add a new level for stacktrace
462+
// recording
463+
try {
464+
if (entryContext == CapturedContext.EMPTY_CONTEXT
465+
&& exitContext == CapturedContext.EMPTY_CONTEXT) {
466+
// rate limited
467+
return;
468+
}
469+
CapturedContext.Status entryStatus = entryContext.getStatus(probeIndex);
470+
CapturedContext.Status exitStatus = exitContext.getStatus(probeIndex);
471+
ProbeImplementation probeImplementation;
472+
if (entryStatus.probeImplementation != ProbeImplementation.UNKNOWN
473+
&& (entryStatus.probeImplementation.getEvaluateAt() == MethodLocation.ENTRY
474+
|| entryStatus.probeImplementation.getEvaluateAt() == MethodLocation.DEFAULT)) {
475+
probeImplementation = entryStatus.probeImplementation;
476+
} else if (exitStatus.probeImplementation.getEvaluateAt() == MethodLocation.EXIT) {
477+
probeImplementation = exitStatus.probeImplementation;
478+
} else {
479+
throw new IllegalStateException("no probe details for " + probeIndex);
480+
}
481+
probeImplementation.commit(entryContext, exitContext, caughtExceptions);
482+
} catch (Exception ex) {
483+
LOGGER.debug("Error in commit: ", ex);
484+
}
485+
}
486+
384487
public static void marker() {}
385488

386489
public static void captureCodeOrigin(boolean entry) {

dd-java-agent/agent-debugger/debugger-bootstrap/src/main/java/datadog/trace/bootstrap/debugger/ProbeImplementation.java

Lines changed: 0 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -28,10 +28,6 @@ void commit(
2828

2929
MethodLocation getEvaluateAt();
3030

31-
boolean isCaptureSnapshot();
32-
33-
boolean hasCondition();
34-
3531
CapturedContext.Status createStatus();
3632

3733
class NoopProbeImplementation implements ProbeImplementation {
@@ -102,16 +98,6 @@ public MethodLocation getEvaluateAt() {
10298
return evaluateAt;
10399
}
104100

105-
@Override
106-
public boolean isCaptureSnapshot() {
107-
return captureSnapshot;
108-
}
109-
110-
@Override
111-
public boolean hasCondition() {
112-
return script != null;
113-
}
114-
115101
@Override
116102
public CapturedContext.Status createStatus() {
117103
return CapturedContext.Status.EMPTY_CAPTURING_STATUS;

0 commit comments

Comments
 (0)