aboutsummaryrefslogtreecommitdiff
path: root/impl_core/src/main/java/io/opencensus/implcore/trace/SpanBuilderImpl.java
diff options
context:
space:
mode:
Diffstat (limited to 'impl_core/src/main/java/io/opencensus/implcore/trace/SpanBuilderImpl.java')
-rw-r--r--impl_core/src/main/java/io/opencensus/implcore/trace/SpanBuilderImpl.java253
1 files changed, 253 insertions, 0 deletions
diff --git a/impl_core/src/main/java/io/opencensus/implcore/trace/SpanBuilderImpl.java b/impl_core/src/main/java/io/opencensus/implcore/trace/SpanBuilderImpl.java
new file mode 100644
index 00000000..5565e9de
--- /dev/null
+++ b/impl_core/src/main/java/io/opencensus/implcore/trace/SpanBuilderImpl.java
@@ -0,0 +1,253 @@
+/*
+ * Copyright 2017, OpenCensus Authors
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package io.opencensus.implcore.trace;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+
+import io.opencensus.common.Clock;
+import io.opencensus.implcore.internal.TimestampConverter;
+import io.opencensus.implcore.trace.internal.RandomHandler;
+import io.opencensus.trace.Link;
+import io.opencensus.trace.Link.Type;
+import io.opencensus.trace.Sampler;
+import io.opencensus.trace.Span;
+import io.opencensus.trace.Span.Kind;
+import io.opencensus.trace.SpanBuilder;
+import io.opencensus.trace.SpanContext;
+import io.opencensus.trace.SpanId;
+import io.opencensus.trace.TraceId;
+import io.opencensus.trace.TraceOptions;
+import io.opencensus.trace.Tracestate;
+import io.opencensus.trace.config.TraceConfig;
+import io.opencensus.trace.config.TraceParams;
+import java.util.Collections;
+import java.util.List;
+import java.util.Random;
+import javax.annotation.Nullable;
+
+/** Implementation of the {@link SpanBuilder}. */
+final class SpanBuilderImpl extends SpanBuilder {
+ private static final Tracestate TRACESTATE_DEFAULT = Tracestate.builder().build();
+
+ private static final TraceOptions SAMPLED_TRACE_OPTIONS =
+ TraceOptions.builder().setIsSampled(true).build();
+ private static final TraceOptions NOT_SAMPLED_TRACE_OPTIONS =
+ TraceOptions.builder().setIsSampled(false).build();
+
+ private final Options options;
+ private final String name;
+ @Nullable private final Span parent;
+ @Nullable private final SpanContext remoteParentSpanContext;
+ @Nullable private Sampler sampler;
+ private List<Span> parentLinks = Collections.<Span>emptyList();
+ @Nullable private Boolean recordEvents;
+ @Nullable private Kind kind;
+
+ private Span startSpanInternal(
+ @Nullable SpanContext parent,
+ @Nullable Boolean hasRemoteParent,
+ String name,
+ @Nullable Sampler sampler,
+ List<Span> parentLinks,
+ @Nullable Boolean recordEvents,
+ @Nullable Kind kind,
+ @Nullable TimestampConverter timestampConverter) {
+ TraceParams activeTraceParams = options.traceConfig.getActiveTraceParams();
+ Random random = options.randomHandler.current();
+ TraceId traceId;
+ SpanId spanId = SpanId.generateRandomId(random);
+ SpanId parentSpanId = null;
+ // TODO(bdrutu): Handle tracestate correctly not just propagate.
+ Tracestate tracestate = TRACESTATE_DEFAULT;
+ if (parent == null || !parent.isValid()) {
+ // New root span.
+ traceId = TraceId.generateRandomId(random);
+ // This is a root span so no remote or local parent.
+ hasRemoteParent = null;
+ } else {
+ // New child span.
+ traceId = parent.getTraceId();
+ parentSpanId = parent.getSpanId();
+ tracestate = parent.getTracestate();
+ }
+ TraceOptions traceOptions =
+ makeSamplingDecision(
+ parent,
+ hasRemoteParent,
+ name,
+ sampler,
+ parentLinks,
+ traceId,
+ spanId,
+ activeTraceParams)
+ ? SAMPLED_TRACE_OPTIONS
+ : NOT_SAMPLED_TRACE_OPTIONS;
+ Span span =
+ (traceOptions.isSampled() || Boolean.TRUE.equals(recordEvents))
+ ? RecordEventsSpanImpl.startSpan(
+ SpanContext.create(traceId, spanId, traceOptions, tracestate),
+ name,
+ kind,
+ parentSpanId,
+ hasRemoteParent,
+ activeTraceParams,
+ options.startEndHandler,
+ timestampConverter,
+ options.clock)
+ : NoRecordEventsSpanImpl.create(
+ SpanContext.create(traceId, spanId, traceOptions, tracestate));
+ linkSpans(span, parentLinks);
+ return span;
+ }
+
+ private static boolean makeSamplingDecision(
+ @Nullable SpanContext parent,
+ @Nullable Boolean hasRemoteParent,
+ String name,
+ @Nullable Sampler sampler,
+ List<Span> parentLinks,
+ TraceId traceId,
+ SpanId spanId,
+ TraceParams activeTraceParams) {
+ // If users set a specific sampler in the SpanBuilder, use it.
+ if (sampler != null) {
+ return sampler.shouldSample(parent, hasRemoteParent, traceId, spanId, name, parentLinks);
+ }
+ // Use the default sampler if this is a root Span or this is an entry point Span (has remote
+ // parent).
+ if (Boolean.TRUE.equals(hasRemoteParent) || parent == null || !parent.isValid()) {
+ return activeTraceParams
+ .getSampler()
+ .shouldSample(parent, hasRemoteParent, traceId, spanId, name, parentLinks);
+ }
+ // Parent is always different than null because otherwise we use the default sampler.
+ return parent.getTraceOptions().isSampled() || isAnyParentLinkSampled(parentLinks);
+ }
+
+ private static boolean isAnyParentLinkSampled(List<Span> parentLinks) {
+ for (Span parentLink : parentLinks) {
+ if (parentLink.getContext().getTraceOptions().isSampled()) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ private static void linkSpans(Span span, List<Span> parentLinks) {
+ if (!parentLinks.isEmpty()) {
+ Link childLink = Link.fromSpanContext(span.getContext(), Type.CHILD_LINKED_SPAN);
+ for (Span linkedSpan : parentLinks) {
+ linkedSpan.addLink(childLink);
+ span.addLink(Link.fromSpanContext(linkedSpan.getContext(), Type.PARENT_LINKED_SPAN));
+ }
+ }
+ }
+
+ static SpanBuilderImpl createWithParent(String spanName, @Nullable Span parent, Options options) {
+ return new SpanBuilderImpl(spanName, null, parent, options);
+ }
+
+ static SpanBuilderImpl createWithRemoteParent(
+ String spanName, @Nullable SpanContext remoteParentSpanContext, Options options) {
+ return new SpanBuilderImpl(spanName, remoteParentSpanContext, null, options);
+ }
+
+ private SpanBuilderImpl(
+ String name,
+ @Nullable SpanContext remoteParentSpanContext,
+ @Nullable Span parent,
+ Options options) {
+ this.name = checkNotNull(name, "name");
+ this.parent = parent;
+ this.remoteParentSpanContext = remoteParentSpanContext;
+ this.options = options;
+ }
+
+ @Override
+ public Span startSpan() {
+ SpanContext parentContext = remoteParentSpanContext;
+ Boolean hasRemoteParent = Boolean.TRUE;
+ TimestampConverter timestampConverter = null;
+ if (remoteParentSpanContext == null) {
+ // This is not a child of a remote Span. Get the parent SpanContext from the parent Span if
+ // any.
+ Span parent = this.parent;
+ hasRemoteParent = Boolean.FALSE;
+ if (parent != null) {
+ parentContext = parent.getContext();
+ // Pass the timestamp converter from the parent to ensure that the recorded events are in
+ // the right order. Implementation uses System.nanoTime() which is monotonically increasing.
+ if (parent instanceof RecordEventsSpanImpl) {
+ timestampConverter = ((RecordEventsSpanImpl) parent).getTimestampConverter();
+ }
+ } else {
+ hasRemoteParent = null;
+ }
+ }
+ return startSpanInternal(
+ parentContext,
+ hasRemoteParent,
+ name,
+ sampler,
+ parentLinks,
+ recordEvents,
+ kind,
+ timestampConverter);
+ }
+
+ static final class Options {
+ private final RandomHandler randomHandler;
+ private final RecordEventsSpanImpl.StartEndHandler startEndHandler;
+ private final Clock clock;
+ private final TraceConfig traceConfig;
+
+ Options(
+ RandomHandler randomHandler,
+ RecordEventsSpanImpl.StartEndHandler startEndHandler,
+ Clock clock,
+ TraceConfig traceConfig) {
+ this.randomHandler = checkNotNull(randomHandler, "randomHandler");
+ this.startEndHandler = checkNotNull(startEndHandler, "startEndHandler");
+ this.clock = checkNotNull(clock, "clock");
+ this.traceConfig = checkNotNull(traceConfig, "traceConfig");
+ }
+ }
+
+ @Override
+ public SpanBuilderImpl setSampler(Sampler sampler) {
+ this.sampler = checkNotNull(sampler, "sampler");
+ return this;
+ }
+
+ @Override
+ public SpanBuilderImpl setParentLinks(List<Span> parentLinks) {
+ this.parentLinks = checkNotNull(parentLinks, "parentLinks");
+ return this;
+ }
+
+ @Override
+ public SpanBuilderImpl setRecordEvents(boolean recordEvents) {
+ this.recordEvents = recordEvents;
+ return this;
+ }
+
+ @Override
+ public SpanBuilderImpl setSpanKind(@Nullable Kind kind) {
+ this.kind = kind;
+ return this;
+ }
+}