Skip to content

Commit ce49eb9

Browse files
committed
institute a 10 snapshot per probe per trace budget
1 parent 991929d commit ce49eb9

File tree

3 files changed

+59
-1
lines changed

3 files changed

+59
-1
lines changed

dd-java-agent/agent-debugger/src/main/java/com/datadog/debugger/probe/LogProbe.java

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,12 +16,14 @@
1616
import com.datadog.debugger.sink.DebuggerSink;
1717
import com.datadog.debugger.sink.Snapshot;
1818
import com.datadog.debugger.util.MoshiHelper;
19+
import com.datadog.debugger.util.WeakIdentityHashMap;
1920
import com.squareup.moshi.Json;
2021
import com.squareup.moshi.JsonAdapter;
2122
import com.squareup.moshi.JsonReader;
2223
import com.squareup.moshi.JsonWriter;
2324
import com.squareup.moshi.Types;
2425
import datadog.trace.api.Config;
26+
import datadog.trace.api.DDTraceId;
2527
import datadog.trace.bootstrap.debugger.CapturedContext;
2628
import datadog.trace.bootstrap.debugger.CorrelationAccess;
2729
import datadog.trace.bootstrap.debugger.DebuggerContext;
@@ -49,6 +51,7 @@
4951
import java.util.List;
5052
import java.util.Map;
5153
import java.util.Objects;
54+
import java.util.concurrent.atomic.AtomicInteger;
5255
import java.util.function.Consumer;
5356
import org.slf4j.Logger;
5457
import org.slf4j.LoggerFactory;
@@ -59,6 +62,8 @@ public class LogProbe extends ProbeDefinition implements Sampled {
5962
private static final Limits LIMITS = new Limits(1, 3, 8192, 5);
6063
private static final int LOG_MSG_LIMIT = 8192;
6164

65+
protected static final int PROBE_BUDGET = 10;
66+
6267
/** Stores part of a templated message either a str or an expression */
6368
public static class Segment {
6469
private final String str;
@@ -278,6 +283,7 @@ public String toString() {
278283
private final Capture capture;
279284
private final Sampling sampling;
280285
private transient Consumer<Snapshot> snapshotProcessor;
286+
private transient Map<DDTraceId, AtomicInteger> budget = new WeakIdentityHashMap<>();
281287

282288
// no-arg constructor is required by Moshi to avoid creating instance with unsafe and by-passing
283289
// constructors, including field initializers.
@@ -568,7 +574,8 @@ public void commit(
568574
CapturedContext exitContext,
569575
List<CapturedContext.CapturedThrowable> caughtExceptions) {
570576
Snapshot snapshot = createSnapshot();
571-
boolean shouldCommit = fillSnapshot(entryContext, exitContext, caughtExceptions, snapshot);
577+
boolean shouldCommit =
578+
inBudget() && fillSnapshot(entryContext, exitContext, caughtExceptions, snapshot);
572579
DebuggerSink sink = DebuggerAgent.getSink();
573580
if (shouldCommit) {
574581
commitSnapshot(snapshot, sink);
@@ -855,6 +862,15 @@ public String toString() {
855862
}
856863
}
857864

865+
private boolean inBudget() {
866+
AgentSpan span = AgentTracer.activeSpan();
867+
return span == null
868+
|| budget
869+
.computeIfAbsent(span.getLocalRootSpan().getTraceId(), id -> new AtomicInteger())
870+
.getAndIncrement()
871+
< PROBE_BUDGET;
872+
}
873+
858874
@Generated
859875
@Override
860876
public boolean equals(Object o) {

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

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,10 @@ public SnapshotSink(Config config, String tags, BatchUploader snapshotUploader)
5353
this.snapshotUploader = snapshotUploader;
5454
}
5555

56+
public BlockingQueue<Snapshot> getLowRateSnapshots() {
57+
return lowRateSnapshots;
58+
}
59+
5660
public void start() {
5761
if (started.compareAndSet(false, true)) {
5862
highRateScheduled =

dd-java-agent/agent-debugger/src/test/java/com/datadog/debugger/probe/LogProbeTest.java

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,44 @@ public void noDebugSession() {
7878
"With no debug sessions, snapshots should get filled.");
7979
}
8080

81+
@Test
82+
public void budgets() {
83+
DebuggerSink sink = new DebuggerSink(getConfig(), mock(ProbeStatusSink.class));
84+
DebuggerAgentHelper.injectSink(sink);
85+
assertEquals(0, sink.getSnapshotSink().getLowRateSnapshots().size());
86+
TracerAPI tracer =
87+
CoreTracer.builder().idGenerationStrategy(IdGenerationStrategy.fromName("random")).build();
88+
AgentTracer.registerIfAbsent(tracer);
89+
int runs = 100;
90+
for (int i = 0; i < runs; i++) {
91+
runTrace(tracer);
92+
}
93+
assertEquals(runs * LogProbe.PROBE_BUDGET, sink.getSnapshotSink().getLowRateSnapshots().size());
94+
}
95+
96+
private void runTrace(TracerAPI tracer) {
97+
AgentSpan span = tracer.startSpan("budget testing", "test span");
98+
try (AgentScope scope = tracer.activateSpan(span, ScopeSource.MANUAL)) {
99+
100+
LogProbe logProbe =
101+
createLog("I'm in a debug session")
102+
.probeId(ProbeId.newId())
103+
.captureSnapshot(true)
104+
.build();
105+
106+
CapturedContext entryContext = capturedContext(span, logProbe);
107+
CapturedContext exitContext = capturedContext(span, logProbe);
108+
logProbe.evaluate(entryContext, new LogStatus(logProbe), MethodLocation.ENTRY);
109+
logProbe.evaluate(exitContext, new LogStatus(logProbe), MethodLocation.EXIT);
110+
111+
for (int i = 0; i < 20; i++) {
112+
logProbe.commit(entryContext, exitContext, emptyList());
113+
}
114+
tracer.startSpan("budget testing", "test span");
115+
tracer.activateNext(span);
116+
}
117+
}
118+
81119
private boolean fillSnapshot(DebugSessionStatus status) {
82120
DebuggerAgentHelper.injectSink(new DebuggerSink(getConfig(), mock(ProbeStatusSink.class)));
83121
TracerAPI tracer =

0 commit comments

Comments
 (0)