Skip to content
This repository was archived by the owner on Dec 23, 2023. It is now read-only.

Commit a64c591

Browse files
author
Bogdan Drutu
authored
Add separate buckets for sampled and not sampled spans. (#592)
1 parent 365c32f commit a64c591

File tree

3 files changed

+120
-35
lines changed

3 files changed

+120
-35
lines changed

contrib/zpages/src/main/java/io/opencensus/contrib/zpages/TracezZPageHandler.java

Lines changed: 22 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@
2929
import io.opencensus.trace.AttributeValue;
3030
import io.opencensus.trace.NetworkEvent;
3131
import io.opencensus.trace.NetworkEvent.Type;
32+
import io.opencensus.trace.SpanContext;
3233
import io.opencensus.trace.SpanId;
3334
import io.opencensus.trace.Status;
3435
import io.opencensus.trace.Status.CanonicalCode;
@@ -107,6 +108,10 @@ int getValue() {
107108
private static final Tracer tracer = Tracing.getTracer();
108109
// Color to use for zebra-striping.
109110
private static final String ZEBRA_STRIPE_COLOR = "#eee";
111+
// Color for sampled traceIds.
112+
private static final String SAMPLED_TRACE_ID_COLOR = "blue";
113+
// Color for not sampled traceIds
114+
private static final String NOT_SAMPLED_TRACE_ID_COLOR = "black";
110115
// The header for span name.
111116
private static final String HEADER_SPAN_NAME = "zspanname";
112117
// The header for type (running = 0, latency = 1, error = 2) to display.
@@ -233,6 +238,7 @@ private void emitHtmlBody(Map<String, String> queryMap, PrintWriter out)
233238

234239
if (spans != null) {
235240
emitSpans(out, formatter, spans);
241+
emitLegend(out);
236242
}
237243
}
238244
}
@@ -286,9 +292,10 @@ private static void emitSingleSpan(PrintWriter out, Formatter formatter, SpanDat
286292
* 1.0e-9)
287293
: String.format("%13s", " ");
288294

295+
SpanContext spanContext = span.getContext();
289296
formatter.format(
290-
"<b>%04d/%02d/%02d-%02d:%02d:%02d.%06d %s TraceId: %s SpanId: %s "
291-
+ "ParentSpanId: %s</b>%n",
297+
"<b>%04d/%02d/%02d-%02d:%02d:%02d.%06d %s TraceId: <b style=\"color:%s;\">%s</b> "
298+
+ "SpanId: %s ParentSpanId: %s</b>%n",
292299
calendar.get(Calendar.YEAR),
293300
calendar.get(Calendar.MONTH) + 1,
294301
calendar.get(Calendar.DAY_OF_MONTH),
@@ -297,8 +304,11 @@ private static void emitSingleSpan(PrintWriter out, Formatter formatter, SpanDat
297304
calendar.get(Calendar.SECOND),
298305
microsField,
299306
elapsedSecondsStr,
300-
BaseEncoding.base16().lowerCase().encode(span.getContext().getTraceId().getBytes()),
301-
BaseEncoding.base16().lowerCase().encode(span.getContext().getSpanId().getBytes()),
307+
spanContext.getTraceOptions().isSampled()
308+
? SAMPLED_TRACE_ID_COLOR
309+
: NOT_SAMPLED_TRACE_ID_COLOR,
310+
BaseEncoding.base16().lowerCase().encode(spanContext.getTraceId().getBytes()),
311+
BaseEncoding.base16().lowerCase().encode(spanContext.getSpanId().getBytes()),
302312
BaseEncoding.base16()
303313
.lowerCase()
304314
.encode(
@@ -511,6 +521,14 @@ private static void emitSingleCell(
511521
}
512522
}
513523

524+
private static void emitLegend(PrintWriter out) {
525+
out.write("<br>\n");
526+
out.printf("<p><b style=\"color:%s;\">TraceId</b> means sampled request. "
527+
+ "<b style=\"color:%s;\">TraceId</b> means not sampled request.</p>%n",
528+
SAMPLED_TRACE_ID_COLOR,
529+
NOT_SAMPLED_TRACE_ID_COLOR);
530+
}
531+
514532
private static Map<LatencyBucketBoundaries, String> buildLatencyBucketBoundariesStringMap() {
515533
Map<LatencyBucketBoundaries, String> ret = new HashMap<>();
516534
for (LatencyBucketBoundaries latencyBucketBoundaries : LatencyBucketBoundaries.values()) {

impl_core/src/main/java/io/opencensus/implcore/trace/export/SampledSpanStoreImpl.java

Lines changed: 37 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -51,25 +51,44 @@ public final class SampledSpanStoreImpl extends SampledSpanStore {
5151

5252
private static final class Bucket {
5353

54-
private final EvictingQueue<SpanImpl> queue;
55-
private long lastSampleNanoTime;
54+
private final EvictingQueue<SpanImpl> sampledSpansQueue;
55+
private final EvictingQueue<SpanImpl> notSampledSpansQueue;
56+
private long lastSampledNanoTime;
57+
private long lastNotSampledNanoTime;
5658

5759
private Bucket(int numSamples) {
58-
queue = EvictingQueue.create(numSamples);
60+
sampledSpansQueue = EvictingQueue.create(numSamples);
61+
notSampledSpansQueue = EvictingQueue.create(numSamples);
5962
}
6063

6164
private void considerForSampling(SpanImpl span) {
6265
long spanEndNanoTime = span.getEndNanoTime();
63-
// Need to compare by doing the subtraction all the time because in case of an overflow,
64-
// this may never sample again (at least for the next ~200 years). No real chance to
65-
// overflow two times because that means the process runs for ~200 years.
66-
if (spanEndNanoTime - lastSampleNanoTime > TIME_BETWEEN_SAMPLES) {
67-
queue.add(span);
68-
lastSampleNanoTime = spanEndNanoTime;
66+
if (span.getContext().getTraceOptions().isSampled()) {
67+
// Need to compare by doing the subtraction all the time because in case of an overflow,
68+
// this may never sample again (at least for the next ~200 years). No real chance to
69+
// overflow two times because that means the process runs for ~200 years.
70+
if (spanEndNanoTime - lastSampledNanoTime > TIME_BETWEEN_SAMPLES) {
71+
sampledSpansQueue.add(span);
72+
lastSampledNanoTime = spanEndNanoTime;
73+
}
74+
} else {
75+
// Need to compare by doing the subtraction all the time because in case of an overflow,
76+
// this may never sample again (at least for the next ~200 years). No real chance to
77+
// overflow two times because that means the process runs for ~200 years.
78+
if (spanEndNanoTime - lastNotSampledNanoTime > TIME_BETWEEN_SAMPLES) {
79+
notSampledSpansQueue.add(span);
80+
lastNotSampledNanoTime = spanEndNanoTime;
81+
}
6982
}
7083
}
7184

7285
private void getSamples(int maxSpansToReturn, List<SpanImpl> output) {
86+
getSamples(sampledSpansQueue, maxSpansToReturn, output);
87+
getSamples(notSampledSpansQueue, maxSpansToReturn, output);
88+
}
89+
90+
private static void getSamples(EvictingQueue<SpanImpl> queue, int maxSpansToReturn,
91+
List<SpanImpl> output) {
7392
for (SpanImpl span : queue) {
7493
if (output.size() >= maxSpansToReturn) {
7594
break;
@@ -80,6 +99,14 @@ private void getSamples(int maxSpansToReturn, List<SpanImpl> output) {
8099

81100
private void getSamplesFilteredByLatency(
82101
long latencyLowerNs, long latencyUpperNs, int maxSpansToReturn, List<SpanImpl> output) {
102+
getSamplesFilteredByLatency(sampledSpansQueue, latencyLowerNs, latencyUpperNs,
103+
maxSpansToReturn, output);
104+
getSamplesFilteredByLatency(notSampledSpansQueue, latencyLowerNs, latencyUpperNs,
105+
maxSpansToReturn, output);
106+
}
107+
108+
private static void getSamplesFilteredByLatency(EvictingQueue<SpanImpl> queue,
109+
long latencyLowerNs, long latencyUpperNs, int maxSpansToReturn, List<SpanImpl> output) {
83110
for (SpanImpl span : queue) {
84111
if (output.size() >= maxSpansToReturn) {
85112
break;
@@ -92,7 +119,7 @@ private void getSamplesFilteredByLatency(
92119
}
93120

94121
private int getNumSamples() {
95-
return queue.size();
122+
return sampledSpansQueue.size() + notSampledSpansQueue.size();
96123
}
97124
}
98125

impl_core/src/test/java/io/opencensus/implcore/trace/export/SampledSpanStoreImplTest.java

Lines changed: 61 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,11 @@ public class SampledSpanStoreImplTest {
6161
TraceId.generateRandomId(random),
6262
SpanId.generateRandomId(random),
6363
TraceOptions.builder().setIsSampled().build());
64+
private final SpanContext notSampledSpanContext =
65+
SpanContext.create(
66+
TraceId.generateRandomId(random),
67+
SpanId.generateRandomId(random),
68+
TraceOptions.DEFAULT);
6469
private final SpanId parentSpanId = SpanId.generateRandomId(random);
6570
private final EnumSet<Options> recordSpanOptions = EnumSet.of(Options.RECORD_EVENTS);
6671
private final TestClock testClock = TestClock.create(Timestamp.create(12345, 54321));
@@ -83,7 +88,7 @@ public void setUp() {
8388
sampleStore.registerSpanNamesForCollection(Arrays.asList(REGISTERED_SPAN_NAME));
8489
}
8590

86-
SpanImpl createSpan(String spanName) {
91+
SpanImpl createSampledSpan(String spanName) {
8792
SpanImpl span =
8893
SpanImpl.startSpan(
8994
sampledSpanContext,
@@ -98,9 +103,25 @@ SpanImpl createSpan(String spanName) {
98103
return span;
99104
}
100105

106+
SpanImpl createNotSampledSpan(String spanName) {
107+
SpanImpl span =
108+
SpanImpl.startSpan(
109+
notSampledSpanContext,
110+
recordSpanOptions,
111+
spanName,
112+
parentSpanId,
113+
false,
114+
TraceParams.DEFAULT,
115+
startEndHandler,
116+
null,
117+
testClock);
118+
return span;
119+
}
120+
101121
private void addSpanNameToAllLatencyBuckets(String spanName) {
102122
for (LatencyBucketBoundaries boundaries : LatencyBucketBoundaries.values()) {
103-
Span span = createSpan(spanName);
123+
Span sampledSpan = createSampledSpan(spanName);
124+
Span notSampledSpan = createNotSampledSpan(spanName);
104125
if (boundaries.getLatencyLowerNs() < NUM_NANOS_PER_SECOND) {
105126
testClock.advanceTime(Duration.create(0, (int) boundaries.getLatencyLowerNs()));
106127
} else {
@@ -109,16 +130,19 @@ private void addSpanNameToAllLatencyBuckets(String spanName) {
109130
boundaries.getLatencyLowerNs() / NUM_NANOS_PER_SECOND,
110131
(int) (boundaries.getLatencyLowerNs() % NUM_NANOS_PER_SECOND)));
111132
}
112-
span.end();
133+
sampledSpan.end();
134+
notSampledSpan.end();
113135
}
114136
}
115137

116138
private void addSpanNameToAllErrorBuckets(String spanName) {
117139
for (CanonicalCode code : CanonicalCode.values()) {
118140
if (code != CanonicalCode.OK) {
119-
Span span = createSpan(spanName);
141+
Span sampledSpan = createSampledSpan(spanName);
142+
Span notSampledSpan = createNotSampledSpan(spanName);
120143
testClock.advanceTime(Duration.create(0, 1000));
121-
span.end(EndSpanOptions.builder().setStatus(code.toStatus()).build());
144+
sampledSpan.end(EndSpanOptions.builder().setStatus(code.toStatus()).build());
145+
notSampledSpan.end(EndSpanOptions.builder().setStatus(code.toStatus()).build());
122146
}
123147
}
124148
}
@@ -133,7 +157,7 @@ public void addSpansWithRegisteredNamesInAllLatencyBuckets() {
133157
perSpanNameSummary.get(REGISTERED_SPAN_NAME).getNumbersOfLatencySampledSpans();
134158
assertThat(latencyBucketsSummaries.size()).isEqualTo(LatencyBucketBoundaries.values().length);
135159
for (Map.Entry<LatencyBucketBoundaries, Integer> it : latencyBucketsSummaries.entrySet()) {
136-
assertThat(it.getValue()).isEqualTo(1);
160+
assertThat(it.getValue()).isEqualTo(2);
137161
}
138162
}
139163

@@ -173,7 +197,7 @@ public void addSpansWithRegisteredNamesInAllErrorBuckets() {
173197
perSpanNameSummary.get(REGISTERED_SPAN_NAME).getNumbersOfErrorSampledSpans();
174198
assertThat(errorBucketsSummaries.size()).isEqualTo(CanonicalCode.values().length - 1);
175199
for (Map.Entry<CanonicalCode, Integer> it : errorBucketsSummaries.entrySet()) {
176-
assertThat(it.getValue()).isEqualTo(1);
200+
assertThat(it.getValue()).isEqualTo(2);
177201
}
178202
}
179203

@@ -188,7 +212,7 @@ public void addSpansWithoutRegisteredNamesInAllErrorBuckets() {
188212

189213
@Test
190214
public void getErrorSampledSpans() {
191-
SpanImpl span = createSpan(REGISTERED_SPAN_NAME);
215+
SpanImpl span = createSampledSpan(REGISTERED_SPAN_NAME);
192216
testClock.advanceTime(Duration.create(0, 1000));
193217
span.end(EndSpanOptions.builder().setStatus(Status.CANCELLED).build());
194218
Collection<SpanData> samples =
@@ -200,12 +224,12 @@ public void getErrorSampledSpans() {
200224

201225
@Test
202226
public void getErrorSampledSpans_MaxSpansToReturn() {
203-
SpanImpl span1 = createSpan(REGISTERED_SPAN_NAME);
227+
SpanImpl span1 = createSampledSpan(REGISTERED_SPAN_NAME);
204228
testClock.advanceTime(Duration.create(0, 1000));
205229
span1.end(EndSpanOptions.builder().setStatus(Status.CANCELLED).build());
206230
// Advance time to allow other spans to be sampled.
207231
testClock.advanceTime(Duration.create(5, 0));
208-
SpanImpl span2 = createSpan(REGISTERED_SPAN_NAME);
232+
SpanImpl span2 = createSampledSpan(REGISTERED_SPAN_NAME);
209233
testClock.advanceTime(Duration.create(0, 1000));
210234
span2.end(EndSpanOptions.builder().setStatus(Status.CANCELLED).build());
211235
Collection<SpanData> samples =
@@ -218,10 +242,10 @@ public void getErrorSampledSpans_MaxSpansToReturn() {
218242

219243
@Test
220244
public void getErrorSampledSpans_NullCode() {
221-
SpanImpl span1 = createSpan(REGISTERED_SPAN_NAME);
245+
SpanImpl span1 = createSampledSpan(REGISTERED_SPAN_NAME);
222246
testClock.advanceTime(Duration.create(0, 1000));
223247
span1.end(EndSpanOptions.builder().setStatus(Status.CANCELLED).build());
224-
SpanImpl span2 = createSpan(REGISTERED_SPAN_NAME);
248+
SpanImpl span2 = createSampledSpan(REGISTERED_SPAN_NAME);
225249
testClock.advanceTime(Duration.create(0, 1000));
226250
span2.end(EndSpanOptions.builder().setStatus(Status.UNKNOWN).build());
227251
Collection<SpanData> samples =
@@ -232,10 +256,10 @@ public void getErrorSampledSpans_NullCode() {
232256

233257
@Test
234258
public void getErrorSampledSpans_NullCode_MaxSpansToReturn() {
235-
SpanImpl span1 = createSpan(REGISTERED_SPAN_NAME);
259+
SpanImpl span1 = createSampledSpan(REGISTERED_SPAN_NAME);
236260
testClock.advanceTime(Duration.create(0, 1000));
237261
span1.end(EndSpanOptions.builder().setStatus(Status.CANCELLED).build());
238-
SpanImpl span2 = createSpan(REGISTERED_SPAN_NAME);
262+
SpanImpl span2 = createSampledSpan(REGISTERED_SPAN_NAME);
239263
testClock.advanceTime(Duration.create(0, 1000));
240264
span2.end(EndSpanOptions.builder().setStatus(Status.UNKNOWN).build());
241265
Collection<SpanData> samples =
@@ -246,7 +270,7 @@ public void getErrorSampledSpans_NullCode_MaxSpansToReturn() {
246270

247271
@Test
248272
public void getLatencySampledSpans() {
249-
SpanImpl span = createSpan(REGISTERED_SPAN_NAME);
273+
SpanImpl span = createSampledSpan(REGISTERED_SPAN_NAME);
250274
testClock.advanceTime(Duration.create(0, (int) TimeUnit.MICROSECONDS.toNanos(20)));
251275
span.end();
252276
Collection<SpanData> samples =
@@ -262,7 +286,7 @@ public void getLatencySampledSpans() {
262286

263287
@Test
264288
public void getLatencySampledSpans_ExclusiveUpperBound() {
265-
SpanImpl span = createSpan(REGISTERED_SPAN_NAME);
289+
SpanImpl span = createSampledSpan(REGISTERED_SPAN_NAME);
266290
testClock.advanceTime(Duration.create(0, (int) TimeUnit.MICROSECONDS.toNanos(20)));
267291
span.end();
268292
Collection<SpanData> samples =
@@ -277,7 +301,7 @@ public void getLatencySampledSpans_ExclusiveUpperBound() {
277301

278302
@Test
279303
public void getLatencySampledSpans_InclusiveLowerBound() {
280-
SpanImpl span = createSpan(REGISTERED_SPAN_NAME);
304+
SpanImpl span = createSampledSpan(REGISTERED_SPAN_NAME);
281305
testClock.advanceTime(Duration.create(0, (int) TimeUnit.MICROSECONDS.toNanos(20)));
282306
span.end();
283307
Collection<SpanData> samples =
@@ -293,12 +317,12 @@ public void getLatencySampledSpans_InclusiveLowerBound() {
293317

294318
@Test
295319
public void getLatencySampledSpans_QueryBetweenMultipleBuckets() {
296-
SpanImpl span1 = createSpan(REGISTERED_SPAN_NAME);
320+
SpanImpl span1 = createSampledSpan(REGISTERED_SPAN_NAME);
297321
testClock.advanceTime(Duration.create(0, (int) TimeUnit.MICROSECONDS.toNanos(20)));
298322
span1.end();
299323
// Advance time to allow other spans to be sampled.
300324
testClock.advanceTime(Duration.create(5, 0));
301-
SpanImpl span2 = createSpan(REGISTERED_SPAN_NAME);
325+
SpanImpl span2 = createSampledSpan(REGISTERED_SPAN_NAME);
302326
testClock.advanceTime(Duration.create(0, (int) TimeUnit.MICROSECONDS.toNanos(200)));
303327
span2.end();
304328
Collection<SpanData> samples =
@@ -313,12 +337,12 @@ public void getLatencySampledSpans_QueryBetweenMultipleBuckets() {
313337

314338
@Test
315339
public void getLatencySampledSpans_MaxSpansToReturn() {
316-
SpanImpl span1 = createSpan(REGISTERED_SPAN_NAME);
340+
SpanImpl span1 = createSampledSpan(REGISTERED_SPAN_NAME);
317341
testClock.advanceTime(Duration.create(0, (int) TimeUnit.MICROSECONDS.toNanos(20)));
318342
span1.end();
319343
// Advance time to allow other spans to be sampled.
320344
testClock.advanceTime(Duration.create(5, 0));
321-
SpanImpl span2 = createSpan(REGISTERED_SPAN_NAME);
345+
SpanImpl span2 = createSampledSpan(REGISTERED_SPAN_NAME);
322346
testClock.advanceTime(Duration.create(0, (int) TimeUnit.MICROSECONDS.toNanos(200)));
323347
span2.end();
324348
Collection<SpanData> samples =
@@ -331,4 +355,20 @@ public void getLatencySampledSpans_MaxSpansToReturn() {
331355
assertThat(samples.size()).isEqualTo(1);
332356
assertThat(samples.contains(span1.toSpanData())).isTrue();
333357
}
358+
359+
@Test
360+
public void ignoreNegativeSpanLatency() {
361+
SpanImpl span = createSampledSpan(REGISTERED_SPAN_NAME);
362+
testClock.advanceTime(Duration.create(0, (int) TimeUnit.MICROSECONDS.toNanos(-20)));
363+
span.end();
364+
Collection<SpanData> samples =
365+
sampleStore.getLatencySampledSpans(
366+
LatencyFilter.create(
367+
REGISTERED_SPAN_NAME,
368+
0,
369+
Long.MAX_VALUE,
370+
0));
371+
assertThat(samples.size()).isEqualTo(0);
372+
}
373+
334374
}

0 commit comments

Comments
 (0)