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

Commit 7b9ea22

Browse files
author
Bogdan Drutu
authored
Add support for child span count. (#1695)
* Add support for child span count. * Fix checker and cleanup implementation * Fix after rebase.
1 parent 8716b0c commit 7b9ea22

File tree

4 files changed

+119
-46
lines changed

4 files changed

+119
-46
lines changed

exporters/trace/stackdriver/src/test/java/io/opencensus/exporter/trace/stackdriver/StackdriverV2ExporterHandlerProtoTest.java

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -389,6 +389,7 @@ public void mapHttpAttributes() {
389389
parentSpanId,
390390
/* hasRemoteParent= */ true,
391391
SPAN_NAME,
392+
null,
392393
startTimestamp,
393394
httpAttributes,
394395
annotations,
@@ -413,6 +414,32 @@ public void mapHttpAttributes() {
413414
.containsEntry("/http/status_code", AttributeValue.newBuilder().setIntValue(200L).build());
414415
}
415416

417+
@Test
418+
public void exportChildSpanCount() {
419+
SpanData spanData =
420+
SpanData.create(
421+
spanContext,
422+
parentSpanId,
423+
/* hasRemoteParent= */ true,
424+
SPAN_NAME,
425+
Kind.SERVER,
426+
startTimestamp,
427+
attributes,
428+
annotations,
429+
messageEvents,
430+
links,
431+
CHILD_SPAN_COUNT,
432+
status,
433+
endTimestamp);
434+
assertThat(
435+
handler
436+
.generateSpan(
437+
spanData, EMPTY_RESOURCE_LABELS, Collections.<String, AttributeValue>emptyMap())
438+
.getChildSpanCount()
439+
.getValue())
440+
.isEqualTo(CHILD_SPAN_COUNT);
441+
}
442+
416443
@Test
417444
public void generateSpanName_ForServer() {
418445
SpanData spanData =

impl_core/src/main/java/io/opencensus/implcore/trace/RecordEventsSpanImpl.java

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,9 @@ public final class RecordEventsSpanImpl extends Span implements Element<RecordEv
9393
@GuardedBy("this")
9494
@Nullable
9595
private TraceEvents<Link> links;
96+
// The number of children.
97+
@GuardedBy("this")
98+
private int numberOfChildren;
9699
// The status of the span.
97100
@GuardedBy("this")
98101
@Nullable
@@ -263,7 +266,7 @@ public SpanData toSpanData() {
263266
annotationsSpanData,
264267
messageEventsSpanData,
265268
linksSpanData,
266-
null, // Not supported yet.
269+
numberOfChildren,
267270
hasBeenEnded ? getStatusWithDefault() : null,
268271
hasBeenEnded ? timestampConverter.convertNanoTime(endNanoTime) : null);
269272
}
@@ -381,6 +384,16 @@ public void end(EndSpanOptions options) {
381384
startEndHandler.onEnd(this);
382385
}
383386

387+
void addChild() {
388+
synchronized (this) {
389+
if (hasBeenEnded) {
390+
logger.log(Level.FINE, "Calling end() on an ended Span.");
391+
return;
392+
}
393+
numberOfChildren++;
394+
}
395+
}
396+
384397
@GuardedBy("this")
385398
private AttributesWithCapacity getInitializedAttributes() {
386399
if (attributes == null) {
@@ -568,6 +581,7 @@ private RecordEventsSpanImpl(
568581
this.clock = clock;
569582
this.hasBeenEnded = false;
570583
this.sampleToLocalSpanStore = false;
584+
this.numberOfChildren = 0;
571585
this.timestampConverter =
572586
timestampConverter != null ? timestampConverter : TimestampConverter.now(clock);
573587
startNanoTime = clock.nowNanos();

impl_core/src/main/java/io/opencensus/implcore/trace/SpanBuilderImpl.java

Lines changed: 50 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -58,35 +58,35 @@ final class SpanBuilderImpl extends SpanBuilder {
5858
@Nullable private Kind kind;
5959

6060
private Span startSpanInternal(
61-
@Nullable SpanContext parent,
61+
@Nullable SpanContext parentContext,
6262
@Nullable Boolean hasRemoteParent,
6363
String name,
6464
@Nullable Sampler sampler,
6565
List<Span> parentLinks,
6666
@Nullable Boolean recordEvents,
6767
@Nullable Kind kind,
68-
@Nullable TimestampConverter timestampConverter) {
68+
@Nullable Span parentSpan) {
6969
TraceParams activeTraceParams = options.traceConfig.getActiveTraceParams();
7070
Random random = options.randomHandler.current();
7171
TraceId traceId;
7272
SpanId spanId = SpanId.generateRandomId(random);
7373
SpanId parentSpanId = null;
7474
// TODO(bdrutu): Handle tracestate correctly not just propagate.
7575
Tracestate tracestate = TRACESTATE_DEFAULT;
76-
if (parent == null || !parent.isValid()) {
76+
if (parentContext == null || !parentContext.isValid()) {
7777
// New root span.
7878
traceId = TraceId.generateRandomId(random);
7979
// This is a root span so no remote or local parent.
8080
hasRemoteParent = null;
8181
} else {
8282
// New child span.
83-
traceId = parent.getTraceId();
84-
parentSpanId = parent.getSpanId();
85-
tracestate = parent.getTracestate();
83+
traceId = parentContext.getTraceId();
84+
parentSpanId = parentContext.getSpanId();
85+
tracestate = parentContext.getTracestate();
8686
}
8787
TraceOptions traceOptions =
8888
makeSamplingDecision(
89-
parent,
89+
parentContext,
9090
hasRemoteParent,
9191
name,
9292
sampler,
@@ -96,22 +96,33 @@ private Span startSpanInternal(
9696
activeTraceParams)
9797
? SAMPLED_TRACE_OPTIONS
9898
: NOT_SAMPLED_TRACE_OPTIONS;
99-
Span span =
100-
(traceOptions.isSampled() || Boolean.TRUE.equals(recordEvents))
101-
? RecordEventsSpanImpl.startSpan(
102-
SpanContext.create(traceId, spanId, traceOptions, tracestate),
103-
name,
104-
kind,
105-
parentSpanId,
106-
hasRemoteParent,
107-
activeTraceParams,
108-
options.startEndHandler,
109-
timestampConverter,
110-
options.clock)
111-
: NoRecordEventsSpanImpl.create(
112-
SpanContext.create(traceId, spanId, traceOptions, tracestate));
113-
linkSpans(span, parentLinks);
114-
return span;
99+
100+
if (traceOptions.isSampled() || Boolean.TRUE.equals(recordEvents)) {
101+
// Pass the timestamp converter from the parent to ensure that the recorded events are in
102+
// the right order. Implementation uses System.nanoTime() which is monotonically increasing.
103+
TimestampConverter timestampConverter = null;
104+
if (parentSpan instanceof RecordEventsSpanImpl) {
105+
RecordEventsSpanImpl parentRecordEventsSpan = (RecordEventsSpanImpl) parentSpan;
106+
timestampConverter = parentRecordEventsSpan.getTimestampConverter();
107+
parentRecordEventsSpan.addChild();
108+
}
109+
Span span =
110+
RecordEventsSpanImpl.startSpan(
111+
SpanContext.create(traceId, spanId, traceOptions, tracestate),
112+
name,
113+
kind,
114+
parentSpanId,
115+
hasRemoteParent,
116+
activeTraceParams,
117+
options.startEndHandler,
118+
timestampConverter,
119+
options.clock);
120+
linkSpans(span, parentLinks);
121+
return span;
122+
} else {
123+
return NoRecordEventsSpanImpl.create(
124+
SpanContext.create(traceId, spanId, traceOptions, tracestate));
125+
}
115126
}
116127

117128
private static boolean makeSamplingDecision(
@@ -179,34 +190,28 @@ private SpanBuilderImpl(
179190

180191
@Override
181192
public Span startSpan() {
182-
SpanContext parentContext = remoteParentSpanContext;
183-
Boolean hasRemoteParent = Boolean.TRUE;
184-
TimestampConverter timestampConverter = null;
185-
if (remoteParentSpanContext == null) {
193+
if (remoteParentSpanContext != null) {
194+
return startSpanInternal(
195+
remoteParentSpanContext,
196+
Boolean.TRUE,
197+
name,
198+
sampler,
199+
parentLinks,
200+
recordEvents,
201+
kind,
202+
null);
203+
} else {
186204
// This is not a child of a remote Span. Get the parent SpanContext from the parent Span if
187205
// any.
188-
Span parent = this.parent;
189-
hasRemoteParent = Boolean.FALSE;
206+
SpanContext parentContext = null;
207+
Boolean hasRemoteParent = null;
190208
if (parent != null) {
191209
parentContext = parent.getContext();
192-
// Pass the timestamp converter from the parent to ensure that the recorded events are in
193-
// the right order. Implementation uses System.nanoTime() which is monotonically increasing.
194-
if (parent instanceof RecordEventsSpanImpl) {
195-
timestampConverter = ((RecordEventsSpanImpl) parent).getTimestampConverter();
196-
}
197-
} else {
198-
hasRemoteParent = null;
210+
hasRemoteParent = Boolean.FALSE;
199211
}
212+
return startSpanInternal(
213+
parentContext, hasRemoteParent, name, sampler, parentLinks, recordEvents, kind, parent);
200214
}
201-
return startSpanInternal(
202-
parentContext,
203-
hasRemoteParent,
204-
name,
205-
sampler,
206-
parentLinks,
207-
recordEvents,
208-
kind,
209-
timestampConverter);
210215
}
211216

212217
static final class Options {

impl_core/src/test/java/io/opencensus/implcore/trace/SpanBuilderImplTest.java

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -138,6 +138,33 @@ public void startSpanNullParentWithRecordEvents() {
138138
assertThat(spanData.getHasRemoteParent()).isNull();
139139
}
140140

141+
@Test
142+
public void startSpanIncreaseNumberOfChildren() {
143+
RecordEventsSpanImpl parent =
144+
(RecordEventsSpanImpl)
145+
SpanBuilderImpl.createWithParent(SPAN_NAME, null, spanBuilderOptions)
146+
.setSampler(Samplers.alwaysSample())
147+
.startSpan();
148+
assertThat(parent.getContext().getTraceOptions().isSampled()).isTrue();
149+
assertThat(parent.toSpanData().getChildSpanCount()).isEqualTo(0);
150+
RecordEventsSpanImpl span =
151+
(RecordEventsSpanImpl)
152+
SpanBuilderImpl.createWithParent(SPAN_NAME, parent, spanBuilderOptions)
153+
.setSampler(Samplers.alwaysSample())
154+
.startSpan();
155+
assertThat(span.getContext().getTraceOptions().isSampled()).isTrue();
156+
assertThat(span.toSpanData().getChildSpanCount()).isEqualTo(0);
157+
assertThat(parent.toSpanData().getChildSpanCount()).isEqualTo(1);
158+
span =
159+
(RecordEventsSpanImpl)
160+
SpanBuilderImpl.createWithParent(SPAN_NAME, parent, spanBuilderOptions)
161+
.setSampler(Samplers.alwaysSample())
162+
.startSpan();
163+
assertThat(span.getContext().getTraceOptions().isSampled()).isTrue();
164+
assertThat(span.toSpanData().getChildSpanCount()).isEqualTo(0);
165+
assertThat(parent.toSpanData().getChildSpanCount()).isEqualTo(2);
166+
}
167+
141168
@Test
142169
public void startSpanNullParentNoRecordOptions() {
143170
Span span =

0 commit comments

Comments
 (0)