From 7edf0c605414a38f14d719747235d3993791136e Mon Sep 17 00:00:00 2001 From: Kristen Kozak Date: Thu, 17 Aug 2017 12:00:51 -0700 Subject: Use different package names in each artifact. (fixes #379) This commit uses the following package name prefixes in each artifact, in order to ensure that no package is split across artifacts: opencensus-api: io.opencensus opencensus-impl-core: io.opencensus.implcore opencensus-impl: io.opencensus.impl opencensus-impl-lite: io.opencensus.impllite --- .../opencensus/implcore/trace/SpanBuilderImpl.java | 197 ++++++++ .../io/opencensus/implcore/trace/SpanImpl.java | 516 +++++++++++++++++++++ .../implcore/trace/StartEndHandlerImpl.java | 124 +++++ .../implcore/trace/TraceComponentImplBase.java | 87 ++++ .../io/opencensus/implcore/trace/TracerImpl.java | 49 ++ .../implcore/trace/config/TraceConfigImpl.java | 40 ++ .../implcore/trace/export/ExportComponentImpl.java | 79 ++++ .../trace/export/RunningSpanStoreImpl.java | 86 ++++ .../trace/export/SampledSpanStoreImpl.java | 291 ++++++++++++ .../implcore/trace/export/SpanExporterImpl.java | 187 ++++++++ .../trace/internal/ConcurrentIntrusiveList.java | 174 +++++++ .../implcore/trace/internal/RandomHandler.java | 47 ++ .../trace/propagation/BinaryFormatImpl.java | 117 +++++ .../propagation/PropagationComponentImpl.java | 27 ++ 14 files changed, 2021 insertions(+) create mode 100644 impl_core/src/main/java/io/opencensus/implcore/trace/SpanBuilderImpl.java create mode 100644 impl_core/src/main/java/io/opencensus/implcore/trace/SpanImpl.java create mode 100644 impl_core/src/main/java/io/opencensus/implcore/trace/StartEndHandlerImpl.java create mode 100644 impl_core/src/main/java/io/opencensus/implcore/trace/TraceComponentImplBase.java create mode 100644 impl_core/src/main/java/io/opencensus/implcore/trace/TracerImpl.java create mode 100644 impl_core/src/main/java/io/opencensus/implcore/trace/config/TraceConfigImpl.java create mode 100644 impl_core/src/main/java/io/opencensus/implcore/trace/export/ExportComponentImpl.java create mode 100644 impl_core/src/main/java/io/opencensus/implcore/trace/export/RunningSpanStoreImpl.java create mode 100644 impl_core/src/main/java/io/opencensus/implcore/trace/export/SampledSpanStoreImpl.java create mode 100644 impl_core/src/main/java/io/opencensus/implcore/trace/export/SpanExporterImpl.java create mode 100644 impl_core/src/main/java/io/opencensus/implcore/trace/internal/ConcurrentIntrusiveList.java create mode 100644 impl_core/src/main/java/io/opencensus/implcore/trace/internal/RandomHandler.java create mode 100644 impl_core/src/main/java/io/opencensus/implcore/trace/propagation/BinaryFormatImpl.java create mode 100644 impl_core/src/main/java/io/opencensus/implcore/trace/propagation/PropagationComponentImpl.java (limited to 'impl_core/src/main/java/io/opencensus/implcore/trace') 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..21bc3757 --- /dev/null +++ b/impl_core/src/main/java/io/opencensus/implcore/trace/SpanBuilderImpl.java @@ -0,0 +1,197 @@ +/* + * Copyright 2017, Google Inc. + * 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.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.config.TraceConfig; +import io.opencensus.trace.config.TraceParams; +import java.util.Collections; +import java.util.EnumSet; +import java.util.List; +import java.util.Random; +import javax.annotation.Nullable; + +/** Implementation of the {@link SpanBuilder}. */ +final class SpanBuilderImpl extends SpanBuilder { + private final Options options; + + private final String name; + private final Span parent; + private final SpanContext remoteParentSpanContext; + private Sampler sampler; + private List parentLinks = Collections.emptyList(); + private Boolean recordEvents; + + private SpanImpl startSpanInternal( + @Nullable SpanContext parent, + @Nullable Boolean hasRemoteParent, + String name, + Sampler sampler, + List parentLinks, + Boolean recordEvents, + @Nullable TimestampConverter timestampConverter) { + TraceParams activeTraceParams = options.traceConfig.getActiveTraceParams(); + Random random = options.randomHandler.current(); + TraceId traceId; + SpanId spanId = SpanId.generateRandomId(random); + SpanId parentSpanId = null; + TraceOptions.Builder traceOptionsBuilder; + if (parent == null || !parent.isValid()) { + // New root span. + traceId = TraceId.generateRandomId(random); + traceOptionsBuilder = TraceOptions.builder(); + // This is a root span so no remote or local parent. + hasRemoteParent = null; + } else { + // New child span. + traceId = parent.getTraceId(); + parentSpanId = parent.getSpanId(); + traceOptionsBuilder = TraceOptions.builder(parent.getTraceOptions()); + } + if (sampler == null) { + sampler = activeTraceParams.getSampler(); + } + if (sampler.shouldSample(parent, hasRemoteParent, traceId, spanId, name, parentLinks)) { + traceOptionsBuilder.setIsSampled(); + } + TraceOptions traceOptions = traceOptionsBuilder.build(); + EnumSet spanOptions = EnumSet.noneOf(Span.Options.class); + if (traceOptions.isSampled() || Boolean.TRUE.equals(recordEvents)) { + spanOptions.add(Span.Options.RECORD_EVENTS); + } + SpanImpl span = + SpanImpl.startSpan( + SpanContext.create(traceId, spanId, traceOptions), + spanOptions, + name, + parentSpanId, + hasRemoteParent, + activeTraceParams, + options.startEndHandler, + timestampConverter, + options.clock); + linkSpans(span, parentLinks); + return span; + } + + private static void linkSpans(Span span, List 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 SpanImpl 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 SpanImpl) { + timestampConverter = ((SpanImpl) parent).getTimestampConverter(); + } + } else { + hasRemoteParent = null; + } + } + return startSpanInternal( + parentContext, + hasRemoteParent, + name, + sampler, + parentLinks, + recordEvents, + timestampConverter); + } + + static final class Options { + private final RandomHandler randomHandler; + private final SpanImpl.StartEndHandler startEndHandler; + private final Clock clock; + private final TraceConfig traceConfig; + + Options( + RandomHandler randomHandler, + SpanImpl.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 parentLinks) { + this.parentLinks = checkNotNull(parentLinks, "parentLinks"); + return this; + } + + @Override + public SpanBuilderImpl setRecordEvents(boolean recordEvents) { + this.recordEvents = recordEvents; + return this; + } +} diff --git a/impl_core/src/main/java/io/opencensus/implcore/trace/SpanImpl.java b/impl_core/src/main/java/io/opencensus/implcore/trace/SpanImpl.java new file mode 100644 index 00000000..fbc753f5 --- /dev/null +++ b/impl_core/src/main/java/io/opencensus/implcore/trace/SpanImpl.java @@ -0,0 +1,516 @@ +/* + * Copyright 2017, Google Inc. + * 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 static com.google.common.base.Preconditions.checkState; + +import com.google.common.annotations.VisibleForTesting; +import com.google.common.collect.EvictingQueue; +import io.opencensus.common.Clock; +import io.opencensus.implcore.internal.TimestampConverter; +import io.opencensus.implcore.trace.internal.ConcurrentIntrusiveList.Element; +import io.opencensus.trace.Annotation; +import io.opencensus.trace.AttributeValue; +import io.opencensus.trace.EndSpanOptions; +import io.opencensus.trace.Link; +import io.opencensus.trace.NetworkEvent; +import io.opencensus.trace.Span; +import io.opencensus.trace.SpanContext; +import io.opencensus.trace.SpanId; +import io.opencensus.trace.Status; +import io.opencensus.trace.Tracer; +import io.opencensus.trace.config.TraceParams; +import io.opencensus.trace.export.SpanData; +import io.opencensus.trace.export.SpanData.TimedEvent; +import java.util.ArrayList; +import java.util.Collections; +import java.util.EnumSet; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; +import java.util.logging.Level; +import java.util.logging.Logger; +import javax.annotation.Nullable; +import javax.annotation.concurrent.GuardedBy; +import javax.annotation.concurrent.ThreadSafe; + +/** Implementation for the {@link Span} class. */ +@ThreadSafe +public final class SpanImpl extends Span implements Element { + private static final Logger logger = Logger.getLogger(Tracer.class.getName()); + + // The parent SpanId of this span. Null if this is a root span. + private final SpanId parentSpanId; + // True if the parent is on a different process. + private final Boolean hasRemoteParent; + // Active trace params when the Span was created. + private final TraceParams traceParams; + // Handler called when the span starts and ends. + private final StartEndHandler startEndHandler; + // The displayed name of the span. + private final String name; + // The clock used to get the time. + private final Clock clock; + // The time converter used to convert nano time to Timestamp. This is needed because Java has + // millisecond granularity for Timestamp and tracing events are recorded more often. + private final TimestampConverter timestampConverter; + // The start time of the span. Set when the span is created iff the RECORD_EVENTS options is + // set, otherwise 0. + private final long startNanoTime; + // Set of recorded attributes. DO NOT CALL any other method that changes the ordering of events. + @GuardedBy("this") + private AttributesWithCapacity attributes; + // List of recorded annotations. + @GuardedBy("this") + private TraceEvents> annotations; + // List of recorded network events. + @GuardedBy("this") + private TraceEvents> networkEvents; + // List of recorded links to parent and child spans. + @GuardedBy("this") + private TraceEvents links; + // The status of the span. Set when the span is ended iff the RECORD_EVENTS options is set. + @GuardedBy("this") + private Status status; + // The end time of the span. Set when the span is ended iff the RECORD_EVENTS options is set, + // otherwise 0. + @GuardedBy("this") + private long endNanoTime; + // True if the span is ended. + @GuardedBy("this") + private boolean hasBeenEnded; + + // Pointers for the ConcurrentIntrusiveList$Element. Guarded by the ConcurrentIntrusiveList. + private SpanImpl next = null; + private SpanImpl prev = null; + + /** + * Creates and starts a span with the given configuration. + * + * @param context supplies the trace_id and span_id for the newly started span. + * @param options the options for the new span, importantly Options.RECORD_EVENTS. + * @param name the displayed name for the new span. + * @param parentSpanId the span_id of the parent span, or null if the new span is a root span. + * @param hasRemoteParent {@code true} if the parentContext is remote. {@code null} if this is a + * root span. + * @param traceParams trace parameters like sampler and probability. + * @param startEndHandler handler called when the span starts and ends. + * @param timestampConverter null if the span is a root span or the parent is not sampled. If the + * parent is sampled, we should use the same converter to ensure ordering between tracing + * events. + * @param clock the clock used to get the time. + * @return a new and started span. + */ + @VisibleForTesting + public static SpanImpl startSpan( + SpanContext context, + @Nullable EnumSet options, + String name, + @Nullable SpanId parentSpanId, + @Nullable Boolean hasRemoteParent, + TraceParams traceParams, + StartEndHandler startEndHandler, + @Nullable TimestampConverter timestampConverter, + Clock clock) { + SpanImpl span = + new SpanImpl( + context, + options, + name, + parentSpanId, + hasRemoteParent, + traceParams, + startEndHandler, + timestampConverter, + clock); + // Call onStart here instead of calling in the constructor to make sure the span is completely + // initialized. + if (span.getOptions().contains(Options.RECORD_EVENTS)) { + startEndHandler.onStart(span); + } + return span; + } + + /** + * Returns the name of the {@code Span}. + * + * @return the name of the {@code Span}. + */ + public String getName() { + return name; + } + + /** + * Returns the status of the {@code Span}. If not set defaults to {@link Status#OK}. + * + * @return the status of the {@code Span}. + */ + public Status getStatus() { + synchronized (this) { + return status; + } + } + + /** + * Returns the end nano time (see {@link System#nanoTime()}). If the current {@code Span} is not + * ended then returns {@link Clock#nowNanos()}. + * + * @return the end nano time. + */ + public long getEndNanoTime() { + synchronized (this) { + return hasBeenEnded ? endNanoTime : clock.nowNanos(); + } + } + + /** + * Returns the latency of the {@code Span} in nanos. If still active then returns now() - start + * time. + * + * @return the latency of the {@code Span} in nanos. + */ + public long getLatencyNs() { + synchronized (this) { + return hasBeenEnded ? endNanoTime - startNanoTime : clock.nowNanos() - startNanoTime; + } + } + + /** + * Returns the {@code TimestampConverter} used by this {@code Span}. + * + * @return the {@code TimestampConverter} used by this {@code Span}. + */ + @Nullable + TimestampConverter getTimestampConverter() { + return timestampConverter; + } + + /** + * Returns an immutable representation of all the data from this {@code Span}. + * + * @return an immutable representation of all the data from this {@code Span}. + * @throws IllegalStateException if the Span doesn't have RECORD_EVENTS option. + */ + public SpanData toSpanData() { + checkState( + getOptions().contains(Options.RECORD_EVENTS), + "Getting SpanData for a Span without RECORD_EVENTS option."); + synchronized (this) { + SpanData.Attributes attributesSpanData = + attributes == null + ? SpanData.Attributes.create(Collections.emptyMap(), 0) + : SpanData.Attributes.create(attributes, attributes.getNumberOfDroppedAttributes()); + SpanData.TimedEvents annotationsSpanData = + createTimedEvents(annotations, timestampConverter); + SpanData.TimedEvents networkEventsSpanData = + createTimedEvents(networkEvents, timestampConverter); + SpanData.Links linksSpanData = + links == null + ? SpanData.Links.create(Collections.emptyList(), 0) + : SpanData.Links.create( + new ArrayList(links.events), links.getNumberOfDroppedEvents()); + return SpanData.create( + getContext(), + parentSpanId, + hasRemoteParent, + name, + timestampConverter.convertNanoTime(startNanoTime), + attributesSpanData, + annotationsSpanData, + networkEventsSpanData, + linksSpanData, + null, // Not supported yet. + hasBeenEnded ? status : null, + hasBeenEnded ? timestampConverter.convertNanoTime(endNanoTime) : null); + } + } + + @Override + public void addAttributes(Map attributes) { + if (!getOptions().contains(Options.RECORD_EVENTS)) { + return; + } + synchronized (this) { + if (hasBeenEnded) { + logger.log(Level.FINE, "Calling addAttributes() on an ended Span."); + return; + } + getInitializedAttributes().addAttributes(attributes); + } + } + + @Override + public void addAnnotation(String description, Map attributes) { + if (!getOptions().contains(Options.RECORD_EVENTS)) { + return; + } + synchronized (this) { + if (hasBeenEnded) { + logger.log(Level.FINE, "Calling addAnnotation() on an ended Span."); + return; + } + getInitializedAnnotations() + .addEvent( + new EventWithNanoTime( + clock.nowNanos(), + Annotation.fromDescriptionAndAttributes(description, attributes))); + } + } + + @Override + public void addAnnotation(Annotation annotation) { + if (!getOptions().contains(Options.RECORD_EVENTS)) { + return; + } + synchronized (this) { + if (hasBeenEnded) { + logger.log(Level.FINE, "Calling addAnnotation() on an ended Span."); + return; + } + getInitializedAnnotations() + .addEvent( + new EventWithNanoTime( + clock.nowNanos(), checkNotNull(annotation, "annotation"))); + } + } + + @Override + public void addNetworkEvent(NetworkEvent networkEvent) { + if (!getOptions().contains(Options.RECORD_EVENTS)) { + return; + } + synchronized (this) { + if (hasBeenEnded) { + logger.log(Level.FINE, "Calling addNetworkEvent() on an ended Span."); + return; + } + getInitializedNetworkEvents() + .addEvent( + new EventWithNanoTime( + clock.nowNanos(), checkNotNull(networkEvent, "networkEvent"))); + } + } + + @Override + public void addLink(Link link) { + if (!getOptions().contains(Options.RECORD_EVENTS)) { + return; + } + synchronized (this) { + if (hasBeenEnded) { + logger.log(Level.FINE, "Calling addLink() on an ended Span."); + return; + } + getInitializedLinks().addEvent(checkNotNull(link, "link")); + } + } + + @Override + public void end(EndSpanOptions options) { + if (!getOptions().contains(Options.RECORD_EVENTS)) { + return; + } + synchronized (this) { + if (hasBeenEnded) { + logger.log(Level.FINE, "Calling end() on an ended Span."); + return; + } + status = options.getStatus(); + endNanoTime = clock.nowNanos(); + hasBeenEnded = true; + } + startEndHandler.onEnd(this); + } + + @GuardedBy("this") + private AttributesWithCapacity getInitializedAttributes() { + if (attributes == null) { + attributes = new AttributesWithCapacity(traceParams.getMaxNumberOfAttributes()); + } + return attributes; + } + + @GuardedBy("this") + private TraceEvents> getInitializedAnnotations() { + if (annotations == null) { + annotations = + new TraceEvents>(traceParams.getMaxNumberOfAnnotations()); + } + return annotations; + } + + @GuardedBy("this") + private TraceEvents> getInitializedNetworkEvents() { + if (networkEvents == null) { + networkEvents = + new TraceEvents>( + traceParams.getMaxNumberOfNetworkEvents()); + } + return networkEvents; + } + + @GuardedBy("this") + private TraceEvents getInitializedLinks() { + if (links == null) { + links = new TraceEvents(traceParams.getMaxNumberOfLinks()); + } + return links; + } + + private static SpanData.TimedEvents createTimedEvents( + TraceEvents> events, TimestampConverter timestampConverter) { + if (events == null) { + return SpanData.TimedEvents.create(Collections.>emptyList(), 0); + } + List> eventsList = new ArrayList>(events.events.size()); + for (EventWithNanoTime networkEvent : events.events) { + eventsList.add(networkEvent.toSpanDataTimedEvent(timestampConverter)); + } + return SpanData.TimedEvents.create(eventsList, events.getNumberOfDroppedEvents()); + } + + @Override + public SpanImpl getNext() { + return next; + } + + @Override + public void setNext(SpanImpl element) { + next = element; + } + + @Override + public SpanImpl getPrev() { + return prev; + } + + @Override + public void setPrev(SpanImpl element) { + prev = element; + } + + /** + * Interface to handle the start and end operations for a {@link Span} only when the {@code Span} + * has {@link Options#RECORD_EVENTS} option. + * + *

Implementation must avoid high overhead work in any of the methods because the code is + * executed on the critical path. + * + *

One instance can be called by multiple threads in the same time, so the implementation must + * be thread-safe. + */ + public interface StartEndHandler { + void onStart(SpanImpl span); + + void onEnd(SpanImpl span); + } + + // A map implementation with a fixed capacity that drops events when the map gets full. Eviction + // is based on the access order. + private static final class AttributesWithCapacity extends LinkedHashMap { + private final int capacity; + private int totalRecordedAttributes = 0; + // Here because -Werror complains about this: [serial] serializable class AttributesWithCapacity + // has no definition of serialVersionUID. This class shouldn't be serialized. + private static final long serialVersionUID = 42L; + + private AttributesWithCapacity(int capacity) { + // Capacity of the map is capacity + 1 to avoid resizing because removeEldestEntry is invoked + // by put and putAll after inserting a new entry into the map. The loadFactor is set to 1 + // to avoid resizing because. The accessOrder is set to true. + super(capacity + 1, 1, true); + this.capacity = capacity; + } + + // Users must call this method instead of put or putAll to keep count of the total number of + // entries inserted. + private void addAttributes(Map attributes) { + totalRecordedAttributes += attributes.size(); + putAll(attributes); + } + + private int getNumberOfDroppedAttributes() { + return totalRecordedAttributes - size(); + } + + // It is called after each put or putAll call in order to determine if the eldest inserted + // entry should be removed or not. + @Override + protected boolean removeEldestEntry(Map.Entry eldest) { + return size() > this.capacity; + } + } + + private static final class TraceEvents { + private int totalRecordedEvents = 0; + private final EvictingQueue events; + + private int getNumberOfDroppedEvents() { + return totalRecordedEvents - events.size(); + } + + TraceEvents(int maxNumEvents) { + events = EvictingQueue.create(maxNumEvents); + } + + void addEvent(T event) { + totalRecordedEvents++; + events.add(event); + } + } + + // Timed event that uses nanoTime to represent the Timestamp. + private static final class EventWithNanoTime { + private final long nanoTime; + private final T event; + + private EventWithNanoTime(long nanoTime, T event) { + this.nanoTime = nanoTime; + this.event = event; + } + + private TimedEvent toSpanDataTimedEvent(TimestampConverter timestampConverter) { + return TimedEvent.create(timestampConverter.convertNanoTime(nanoTime), event); + } + } + + private SpanImpl( + SpanContext context, + @Nullable EnumSet options, + String name, + @Nullable SpanId parentSpanId, + @Nullable Boolean hasRemoteParent, + TraceParams traceParams, + StartEndHandler startEndHandler, + @Nullable TimestampConverter timestampConverter, + Clock clock) { + super(context, options); + this.parentSpanId = parentSpanId; + this.hasRemoteParent = hasRemoteParent; + this.name = name; + this.traceParams = traceParams; + this.startEndHandler = startEndHandler; + this.clock = clock; + this.hasBeenEnded = false; + if (getOptions().contains(Options.RECORD_EVENTS)) { + this.timestampConverter = + timestampConverter != null ? timestampConverter : TimestampConverter.now(clock); + startNanoTime = clock.nowNanos(); + } else { + this.startNanoTime = 0; + this.timestampConverter = timestampConverter; + } + } +} diff --git a/impl_core/src/main/java/io/opencensus/implcore/trace/StartEndHandlerImpl.java b/impl_core/src/main/java/io/opencensus/implcore/trace/StartEndHandlerImpl.java new file mode 100644 index 00000000..76276cd7 --- /dev/null +++ b/impl_core/src/main/java/io/opencensus/implcore/trace/StartEndHandlerImpl.java @@ -0,0 +1,124 @@ +/* + * Copyright 2017, Google Inc. + * 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 io.opencensus.implcore.internal.EventQueue; +import io.opencensus.implcore.trace.SpanImpl.StartEndHandler; +import io.opencensus.implcore.trace.export.RunningSpanStoreImpl; +import io.opencensus.implcore.trace.export.SampledSpanStoreImpl; +import io.opencensus.implcore.trace.export.SpanExporterImpl; +import io.opencensus.trace.Span.Options; +import io.opencensus.trace.export.SpanData; +import javax.annotation.Nullable; +import javax.annotation.concurrent.ThreadSafe; + +/** + * Uses the provided {@link EventQueue} to defer processing/exporting of the {@link SpanData} to + * avoid impacting the critical path. + */ +@ThreadSafe +public final class StartEndHandlerImpl implements StartEndHandler { + private final SpanExporterImpl spanExporter; + private final RunningSpanStoreImpl runningSpanStore; + private final SampledSpanStoreImpl sampledSpanStore; + private final EventQueue eventQueue; + // true if any of (runningSpanStore OR sampledSpanStore) are different than null, which + // means the spans with RECORD_EVENTS should be enqueued in the queue. + private final boolean enqueueEventForNonSampledSpans; + + /** + * Constructs a new {@code StartEndHandlerImpl}. + * + * @param spanExporter the {@code SpanExporter} implementation. + * @param runningSpanStore the {@code RunningSpanStore} implementation. + * @param sampledSpanStore the {@code SampledSpanStore} implementation. + * @param eventQueue the event queue where all the events are enqueued. + */ + public StartEndHandlerImpl( + SpanExporterImpl spanExporter, + @Nullable RunningSpanStoreImpl runningSpanStore, + @Nullable SampledSpanStoreImpl sampledSpanStore, + EventQueue eventQueue) { + this.spanExporter = spanExporter; + this.runningSpanStore = runningSpanStore; + this.sampledSpanStore = sampledSpanStore; + this.enqueueEventForNonSampledSpans = runningSpanStore != null || sampledSpanStore != null; + this.eventQueue = eventQueue; + } + + @Override + public void onStart(SpanImpl span) { + if (span.getOptions().contains(Options.RECORD_EVENTS) && enqueueEventForNonSampledSpans) { + eventQueue.enqueue(new SpanStartEvent(span, runningSpanStore)); + } + } + + @Override + public void onEnd(SpanImpl span) { + if ((span.getOptions().contains(Options.RECORD_EVENTS) && enqueueEventForNonSampledSpans) + || span.getContext().getTraceOptions().isSampled()) { + eventQueue.enqueue(new SpanEndEvent(span, spanExporter, runningSpanStore, sampledSpanStore)); + } + } + + // An EventQueue entry that records the start of the span event. + private static final class SpanStartEvent implements EventQueue.Entry { + private final SpanImpl span; + private final RunningSpanStoreImpl activeSpansExporter; + + SpanStartEvent(SpanImpl span, @Nullable RunningSpanStoreImpl activeSpansExporter) { + this.span = span; + this.activeSpansExporter = activeSpansExporter; + } + + @Override + public void process() { + if (activeSpansExporter != null) { + activeSpansExporter.onStart(span); + } + } + } + + // An EventQueue entry that records the end of the span event. + private static final class SpanEndEvent implements EventQueue.Entry { + private final SpanImpl span; + private final RunningSpanStoreImpl runningSpanStore; + private final SpanExporterImpl spanExporter; + private final SampledSpanStoreImpl sampledSpanStore; + + SpanEndEvent( + SpanImpl span, + SpanExporterImpl spanExporter, + @Nullable RunningSpanStoreImpl runningSpanStore, + @Nullable SampledSpanStoreImpl sampledSpanStore) { + this.span = span; + this.runningSpanStore = runningSpanStore; + this.spanExporter = spanExporter; + this.sampledSpanStore = sampledSpanStore; + } + + @Override + public void process() { + if (span.getContext().getTraceOptions().isSampled()) { + spanExporter.addSpan(span); + } + if (runningSpanStore != null) { + runningSpanStore.onEnd(span); + } + if (sampledSpanStore != null) { + sampledSpanStore.considerForSampling(span); + } + } + } +} diff --git a/impl_core/src/main/java/io/opencensus/implcore/trace/TraceComponentImplBase.java b/impl_core/src/main/java/io/opencensus/implcore/trace/TraceComponentImplBase.java new file mode 100644 index 00000000..8c16950d --- /dev/null +++ b/impl_core/src/main/java/io/opencensus/implcore/trace/TraceComponentImplBase.java @@ -0,0 +1,87 @@ +/* + * Copyright 2017, Google Inc. + * 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 io.opencensus.common.Clock; +import io.opencensus.implcore.internal.EventQueue; +import io.opencensus.implcore.internal.SimpleEventQueue; +import io.opencensus.implcore.trace.SpanImpl.StartEndHandler; +import io.opencensus.implcore.trace.config.TraceConfigImpl; +import io.opencensus.implcore.trace.export.ExportComponentImpl; +import io.opencensus.implcore.trace.internal.RandomHandler; +import io.opencensus.implcore.trace.propagation.PropagationComponentImpl; +import io.opencensus.trace.TraceComponent; +import io.opencensus.trace.Tracer; +import io.opencensus.trace.config.TraceConfig; +import io.opencensus.trace.export.ExportComponent; +import io.opencensus.trace.propagation.PropagationComponent; + +/** Base implementation of the {@link TraceComponent}. */ +public class TraceComponentImplBase extends TraceComponent { + private final ExportComponentImpl exportComponent; + private final PropagationComponent propagationComponent = new PropagationComponentImpl(); + private final Clock clock; + private final StartEndHandler startEndHandler; + private final TraceConfig traceConfig = new TraceConfigImpl(); + private final Tracer tracer; + + /** + * Creates a new {@code TraceComponentImplBase}. + * + * @param clock the clock to use throughout tracing. + * @param randomHandler the random number generator for generating trace and span IDs. + * @param eventQueue the queue implementation. + */ + public TraceComponentImplBase(Clock clock, RandomHandler randomHandler, EventQueue eventQueue) { + this.clock = clock; + // TODO(bdrutu): Add a config/argument for supportInProcessStores. + if (eventQueue instanceof SimpleEventQueue) { + exportComponent = ExportComponentImpl.createWithoutInProcessStores(); + } else { + exportComponent = ExportComponentImpl.createWithInProcessStores(); + } + startEndHandler = + new StartEndHandlerImpl( + exportComponent.getSpanExporter(), + exportComponent.getRunningSpanStore(), + exportComponent.getSampledSpanStore(), + eventQueue); + tracer = new TracerImpl(randomHandler, startEndHandler, clock, traceConfig); + } + + @Override + public Tracer getTracer() { + return tracer; + } + + @Override + public PropagationComponent getPropagationComponent() { + return propagationComponent; + } + + @Override + public final Clock getClock() { + return clock; + } + + @Override + public ExportComponent getExportComponent() { + return exportComponent; + } + + @Override + public TraceConfig getTraceConfig() { + return traceConfig; + } +} diff --git a/impl_core/src/main/java/io/opencensus/implcore/trace/TracerImpl.java b/impl_core/src/main/java/io/opencensus/implcore/trace/TracerImpl.java new file mode 100644 index 00000000..0da79120 --- /dev/null +++ b/impl_core/src/main/java/io/opencensus/implcore/trace/TracerImpl.java @@ -0,0 +1,49 @@ +/* + * Copyright 2017, Google Inc. + * 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 io.opencensus.common.Clock; +import io.opencensus.implcore.trace.internal.RandomHandler; +import io.opencensus.trace.Span; +import io.opencensus.trace.SpanBuilder; +import io.opencensus.trace.SpanContext; +import io.opencensus.trace.Tracer; +import io.opencensus.trace.config.TraceConfig; +import javax.annotation.Nullable; + +/** Implementation of the {@link Tracer}. */ +public final class TracerImpl extends Tracer { + private final SpanBuilderImpl.Options spanBuilderOptions; + + public TracerImpl( + RandomHandler randomHandler, + SpanImpl.StartEndHandler startEndHandler, + Clock clock, + TraceConfig traceConfig) { + spanBuilderOptions = + new SpanBuilderImpl.Options(randomHandler, startEndHandler, clock, traceConfig); + } + + @Override + public SpanBuilder spanBuilderWithExplicitParent(String spanName, @Nullable Span parent) { + return SpanBuilderImpl.createWithParent(spanName, parent, spanBuilderOptions); + } + + @Override + public SpanBuilder spanBuilderWithRemoteParent( + String spanName, @Nullable SpanContext remoteParentSpanContext) { + return SpanBuilderImpl.createWithRemoteParent( + spanName, remoteParentSpanContext, spanBuilderOptions); + } +} diff --git a/impl_core/src/main/java/io/opencensus/implcore/trace/config/TraceConfigImpl.java b/impl_core/src/main/java/io/opencensus/implcore/trace/config/TraceConfigImpl.java new file mode 100644 index 00000000..1f14226b --- /dev/null +++ b/impl_core/src/main/java/io/opencensus/implcore/trace/config/TraceConfigImpl.java @@ -0,0 +1,40 @@ +/* + * Copyright 2017, Google Inc. + * 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.config; + +import io.opencensus.trace.config.TraceConfig; +import io.opencensus.trace.config.TraceParams; + +/** + * Global configuration of the trace service. This allows users to change configs for the default + * sampler, maximum events to be kept, etc. + */ +public final class TraceConfigImpl extends TraceConfig { + // Reads and writes are atomic for reference variables. Use volatile to ensure that these + // operations are visible on other CPUs as well. + private volatile TraceParams activeTraceParams = TraceParams.DEFAULT; + + /** Constructs a new {@code TraceConfigImpl}. */ + public TraceConfigImpl() {} + + @Override + public TraceParams getActiveTraceParams() { + return activeTraceParams; + } + + @Override + public void updateActiveTraceParams(TraceParams traceParams) { + activeTraceParams = traceParams; + } +} diff --git a/impl_core/src/main/java/io/opencensus/implcore/trace/export/ExportComponentImpl.java b/impl_core/src/main/java/io/opencensus/implcore/trace/export/ExportComponentImpl.java new file mode 100644 index 00000000..ac0f8087 --- /dev/null +++ b/impl_core/src/main/java/io/opencensus/implcore/trace/export/ExportComponentImpl.java @@ -0,0 +1,79 @@ +/* + * Copyright 2017, Google Inc. + * 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.export; + +import io.opencensus.trace.export.ExportComponent; +import io.opencensus.trace.export.RunningSpanStore; +import io.opencensus.trace.export.SampledSpanStore; +import javax.annotation.Nullable; + +/** Implementation of the {@link ExportComponent}. */ +public final class ExportComponentImpl extends ExportComponent { + private static final int EXPORTER_BUFFER_SIZE = 32; + // Enforces that trace export exports data at least once every 2 seconds. + private static final long EXPORTER_SCHEDULE_DELAY_MS = 2000; + + private final SpanExporterImpl spanExporter; + private final RunningSpanStoreImpl runningSpanStore; + private final SampledSpanStoreImpl sampledSpanStore; + + @Override + public SpanExporterImpl getSpanExporter() { + return spanExporter; + } + + @Nullable + @Override + public RunningSpanStoreImpl getRunningSpanStore() { + return runningSpanStore; + } + + @Nullable + @Override + public SampledSpanStoreImpl getSampledSpanStore() { + return sampledSpanStore; + } + + /** + * Returns a new {@code ExportComponentImpl} that has valid instances for {@link RunningSpanStore} + * and {@link SampledSpanStore}. + * + * @return a new {@code ExportComponentImpl}. + */ + public static ExportComponentImpl createWithInProcessStores() { + return new ExportComponentImpl(true); + } + + /** + * Returns a new {@code ExportComponentImpl} that has {@code null} instances for {@link + * RunningSpanStore} and {@link SampledSpanStore}. + * + * @return a new {@code ExportComponentImpl}. + */ + public static ExportComponentImpl createWithoutInProcessStores() { + return new ExportComponentImpl(false); + } + + /** + * Constructs a new {@code ExportComponentImpl}. + * + * @param supportInProcessStores {@code true} to instantiate {@link RunningSpanStore} and {@link + * SampledSpanStore}. + */ + private ExportComponentImpl(boolean supportInProcessStores) { + this.spanExporter = SpanExporterImpl.create(EXPORTER_BUFFER_SIZE, EXPORTER_SCHEDULE_DELAY_MS); + this.runningSpanStore = supportInProcessStores ? new RunningSpanStoreImpl() : null; + this.sampledSpanStore = supportInProcessStores ? new SampledSpanStoreImpl() : null; + } +} diff --git a/impl_core/src/main/java/io/opencensus/implcore/trace/export/RunningSpanStoreImpl.java b/impl_core/src/main/java/io/opencensus/implcore/trace/export/RunningSpanStoreImpl.java new file mode 100644 index 00000000..a793644a --- /dev/null +++ b/impl_core/src/main/java/io/opencensus/implcore/trace/export/RunningSpanStoreImpl.java @@ -0,0 +1,86 @@ +/* + * Copyright 2017, Google Inc. + * 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.export; + +import io.opencensus.implcore.trace.SpanImpl; +import io.opencensus.implcore.trace.internal.ConcurrentIntrusiveList; +import io.opencensus.trace.export.RunningSpanStore; +import io.opencensus.trace.export.SpanData; +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import javax.annotation.concurrent.ThreadSafe; + +/** Implementation of the {@link RunningSpanStore}. */ +@ThreadSafe +public final class RunningSpanStoreImpl extends RunningSpanStore { + private final ConcurrentIntrusiveList runningSpans; + + public RunningSpanStoreImpl() { + runningSpans = new ConcurrentIntrusiveList(); + } + + /** + * Adds the {@code Span} into the running spans list when the {@code Span} starts. + * + * @param span the {@code Span} that started. + */ + public void onStart(SpanImpl span) { + runningSpans.addElement(span); + } + + /** + * Removes the {@code Span} from the running spans list when the {@code Span} ends. + * + * @param span the {@code Span} that ended. + */ + public void onEnd(SpanImpl span) { + runningSpans.removeElement(span); + } + + @Override + public Summary getSummary() { + Collection allRunningSpans = runningSpans.getAll(); + Map numSpansPerName = new HashMap(); + for (SpanImpl span : allRunningSpans) { + Integer prevValue = numSpansPerName.get(span.getName()); + numSpansPerName.put(span.getName(), prevValue != null ? prevValue + 1 : 1); + } + Map perSpanNameSummary = new HashMap(); + for (Map.Entry it : numSpansPerName.entrySet()) { + perSpanNameSummary.put(it.getKey(), PerSpanNameSummary.create(it.getValue())); + } + Summary summary = Summary.create(perSpanNameSummary); + return summary; + } + + @Override + public Collection getRunningSpans(Filter filter) { + Collection allRunningSpans = runningSpans.getAll(); + int maxSpansToReturn = + filter.getMaxSpansToReturn() == 0 ? allRunningSpans.size() : filter.getMaxSpansToReturn(); + List ret = new ArrayList(maxSpansToReturn); + for (SpanImpl span : allRunningSpans) { + if (ret.size() == maxSpansToReturn) { + break; + } + if (span.getName().equals(filter.getSpanName())) { + ret.add(span.toSpanData()); + } + } + return ret; + } +} diff --git a/impl_core/src/main/java/io/opencensus/implcore/trace/export/SampledSpanStoreImpl.java b/impl_core/src/main/java/io/opencensus/implcore/trace/export/SampledSpanStoreImpl.java new file mode 100644 index 00000000..5331ade6 --- /dev/null +++ b/impl_core/src/main/java/io/opencensus/implcore/trace/export/SampledSpanStoreImpl.java @@ -0,0 +1,291 @@ +/* + * Copyright 2017, Google Inc. + * 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.export; + +import com.google.common.collect.EvictingQueue; +import io.opencensus.implcore.trace.SpanImpl; +import io.opencensus.trace.Status; +import io.opencensus.trace.Status.CanonicalCode; +import io.opencensus.trace.export.SampledSpanStore; +import io.opencensus.trace.export.SpanData; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.EnumMap; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.concurrent.TimeUnit; +import javax.annotation.concurrent.GuardedBy; +import javax.annotation.concurrent.ThreadSafe; + +/** Implementation of the {@link SampledSpanStore}. */ +@ThreadSafe +public final class SampledSpanStoreImpl extends SampledSpanStore { + private static final int NUM_SAMPLES_PER_LATENCY_BUCKET = 10; + private static final int NUM_SAMPLES_PER_ERROR_BUCKET = 5; + private static final long TIME_BETWEEN_SAMPLES = TimeUnit.SECONDS.toNanos(1); + private static final int NUM_LATENCY_BUCKETS = LatencyBucketBoundaries.values().length; + // The total number of canonical codes - 1 (the OK code). + private static final int NUM_ERROR_BUCKETS = CanonicalCode.values().length - 1; + private static final int MAX_PER_SPAN_NAME_SAMPLES = + NUM_SAMPLES_PER_LATENCY_BUCKET * NUM_LATENCY_BUCKETS + + NUM_SAMPLES_PER_ERROR_BUCKET * NUM_ERROR_BUCKETS; + + @GuardedBy("samples") + private final Map samples; + + private static final class Bucket { + + private final EvictingQueue queue; + private long lastSampleNanoTime; + + private Bucket(int numSamples) { + queue = EvictingQueue.create(numSamples); + } + + private void considerForSampling(SpanImpl span) { + long spanEndNanoTime = span.getEndNanoTime(); + // Need to compare by doing the subtraction all the time because in case of an overflow, + // this may never sample again (at least for the next ~200 years). No real chance to + // overflow two times because that means the process runs for ~200 years. + if (spanEndNanoTime - lastSampleNanoTime > TIME_BETWEEN_SAMPLES) { + queue.add(span); + lastSampleNanoTime = spanEndNanoTime; + } + } + + private void getSamples(int maxSpansToReturn, List output) { + for (SpanImpl span : queue) { + if (output.size() >= maxSpansToReturn) { + break; + } + output.add(span); + } + } + + private void getSamplesFilteredByLatency( + long latencyLowerNs, long latencyUpperNs, int maxSpansToReturn, List output) { + for (SpanImpl span : queue) { + if (output.size() >= maxSpansToReturn) { + break; + } + long spanLatencyNs = span.getLatencyNs(); + if (spanLatencyNs >= latencyLowerNs && spanLatencyNs < latencyUpperNs) { + output.add(span); + } + } + } + + private int getNumSamples() { + return queue.size(); + } + } + + /** + * Keeps samples for a given span name. Samples for all the latency buckets and for all canonical + * codes other than OK. + */ + private static final class PerSpanNameSamples { + + private final Bucket[] latencyBuckets; + private final Bucket[] errorBuckets; + + private PerSpanNameSamples() { + latencyBuckets = new Bucket[NUM_LATENCY_BUCKETS]; + for (int i = 0; i < NUM_LATENCY_BUCKETS; i++) { + latencyBuckets[i] = new Bucket(NUM_SAMPLES_PER_LATENCY_BUCKET); + } + errorBuckets = new Bucket[NUM_ERROR_BUCKETS]; + for (int i = 0; i < NUM_ERROR_BUCKETS; i++) { + errorBuckets[i] = new Bucket(NUM_SAMPLES_PER_ERROR_BUCKET); + } + } + + private Bucket getLatencyBucket(long latencyNs) { + for (int i = 0; i < NUM_LATENCY_BUCKETS; i++) { + LatencyBucketBoundaries boundaries = LatencyBucketBoundaries.values()[i]; + if (latencyNs >= boundaries.getLatencyLowerNs() + && latencyNs < boundaries.getLatencyUpperNs()) { + return latencyBuckets[i]; + } + } + // latencyNs is negative or Long.MAX_VALUE, so this Span can be ignored. This cannot happen + // in real production because System#nanoTime is monotonic. + return null; + } + + private Bucket getErrorBucket(CanonicalCode code) { + return errorBuckets[code.value() - 1]; + } + + private void considerForSampling(SpanImpl span) { + Status status = span.getStatus(); + // Null status means running Span, this should not happen in production, but the library + // should not crash because of this. + if (status != null) { + Bucket bucket = + status.isOk() + ? getLatencyBucket(span.getLatencyNs()) + : getErrorBucket(status.getCanonicalCode()); + // If unable to find the bucket, ignore this Span. + if (bucket != null) { + bucket.considerForSampling(span); + } + } + } + + private Map getNumbersOfLatencySampledSpans() { + Map latencyBucketSummaries = + new EnumMap(LatencyBucketBoundaries.class); + for (int i = 0; i < NUM_LATENCY_BUCKETS; i++) { + latencyBucketSummaries.put( + LatencyBucketBoundaries.values()[i], latencyBuckets[i].getNumSamples()); + } + return latencyBucketSummaries; + } + + private Map getNumbersOfErrorSampledSpans() { + Map errorBucketSummaries = + new EnumMap(CanonicalCode.class); + for (int i = 0; i < NUM_ERROR_BUCKETS; i++) { + errorBucketSummaries.put(CanonicalCode.values()[i + 1], errorBuckets[i].getNumSamples()); + } + return errorBucketSummaries; + } + + private List getErrorSamples(CanonicalCode code, int maxSpansToReturn) { + ArrayList output = new ArrayList(maxSpansToReturn); + if (code != null) { + getErrorBucket(code).getSamples(maxSpansToReturn, output); + } else { + for (int i = 0; i < NUM_ERROR_BUCKETS; i++) { + errorBuckets[i].getSamples(maxSpansToReturn, output); + } + } + return output; + } + + private List getLatencySamples( + long latencyLowerNs, long latencyUpperNs, int maxSpansToReturn) { + ArrayList output = new ArrayList(maxSpansToReturn); + for (int i = 0; i < NUM_LATENCY_BUCKETS; i++) { + LatencyBucketBoundaries boundaries = LatencyBucketBoundaries.values()[i]; + if (latencyUpperNs >= boundaries.getLatencyLowerNs() + && latencyLowerNs < boundaries.getLatencyUpperNs()) { + latencyBuckets[i].getSamplesFilteredByLatency( + latencyLowerNs, latencyUpperNs, maxSpansToReturn, output); + } + } + return output; + } + } + + /** Constructs a new {@code SampledSpanStoreImpl}. */ + public SampledSpanStoreImpl() { + samples = new HashMap(); + } + + @Override + public Summary getSummary() { + Map ret = new HashMap(); + synchronized (samples) { + for (Map.Entry it : samples.entrySet()) { + ret.put( + it.getKey(), + PerSpanNameSummary.create( + it.getValue().getNumbersOfLatencySampledSpans(), + it.getValue().getNumbersOfErrorSampledSpans())); + } + } + return Summary.create(ret); + } + + /** + * Considers to save the given spans to the stored samples. This must be called at the end of each + * Span with the option RECORD_EVENTS. + * + * @param span the span to be consider for storing into the store buckets. + */ + public void considerForSampling(SpanImpl span) { + synchronized (samples) { + PerSpanNameSamples perSpanNameSamples = samples.get(span.getName()); + if (perSpanNameSamples != null) { + perSpanNameSamples.considerForSampling(span); + } + } + } + + @Override + public void registerSpanNamesForCollection(Collection spanNames) { + synchronized (samples) { + for (String spanName : spanNames) { + if (!samples.containsKey(spanName)) { + samples.put(spanName, new PerSpanNameSamples()); + } + } + } + } + + @Override + public void unregisterSpanNamesForCollection(Collection spanNames) { + synchronized (samples) { + samples.keySet().removeAll(spanNames); + } + } + + @Override + public Collection getErrorSampledSpans(ErrorFilter filter) { + int numSpansToReturn = + filter.getMaxSpansToReturn() == 0 + ? MAX_PER_SPAN_NAME_SAMPLES + : filter.getMaxSpansToReturn(); + List spans = Collections.emptyList(); + // Try to not keep the lock to much, do the SpanImpl -> SpanData conversion outside the lock. + synchronized (samples) { + PerSpanNameSamples perSpanNameSamples = samples.get(filter.getSpanName()); + if (perSpanNameSamples != null) { + spans = perSpanNameSamples.getErrorSamples(filter.getCanonicalCode(), numSpansToReturn); + } + } + List ret = new ArrayList(spans.size()); + for (SpanImpl span : spans) { + ret.add(span.toSpanData()); + } + return Collections.unmodifiableList(ret); + } + + @Override + public Collection getLatencySampledSpans(LatencyFilter filter) { + int numSpansToReturn = + filter.getMaxSpansToReturn() == 0 + ? MAX_PER_SPAN_NAME_SAMPLES + : filter.getMaxSpansToReturn(); + List spans = Collections.emptyList(); + // Try to not keep the lock to much, do the SpanImpl -> SpanData conversion outside the lock. + synchronized (samples) { + PerSpanNameSamples perSpanNameSamples = samples.get(filter.getSpanName()); + if (perSpanNameSamples != null) { + spans = + perSpanNameSamples.getLatencySamples( + filter.getLatencyLowerNs(), filter.getLatencyUpperNs(), numSpansToReturn); + } + } + List ret = new ArrayList(spans.size()); + for (SpanImpl span : spans) { + ret.add(span.toSpanData()); + } + return Collections.unmodifiableList(ret); + } +} diff --git a/impl_core/src/main/java/io/opencensus/implcore/trace/export/SpanExporterImpl.java b/impl_core/src/main/java/io/opencensus/implcore/trace/export/SpanExporterImpl.java new file mode 100644 index 00000000..af46cf54 --- /dev/null +++ b/impl_core/src/main/java/io/opencensus/implcore/trace/export/SpanExporterImpl.java @@ -0,0 +1,187 @@ +/* + * Copyright 2017, Google Inc. + * 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.export; + +import com.google.common.annotations.VisibleForTesting; +import io.opencensus.implcore.trace.SpanImpl; +import io.opencensus.trace.export.ExportComponent; +import io.opencensus.trace.export.SpanData; +import io.opencensus.trace.export.SpanExporter; +import java.util.ArrayList; +import java.util.Collections; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; +import java.util.logging.Level; +import java.util.logging.Logger; +import javax.annotation.concurrent.GuardedBy; + +/** Implementation of the {@link SpanExporter}. */ +public final class SpanExporterImpl extends SpanExporter { + private static final Logger logger = Logger.getLogger(ExportComponent.class.getName()); + + private final WorkerThread workerThread; + + /** + * Constructs a {@code SpanExporterImpl} that exports the {@link SpanData} asynchronously. + * + *

Starts a separate thread that wakes up every {@code scheduleDelay} and exports any available + * spans data. If the number of buffered SpanData objects is greater than {@code bufferSize} then + * the thread wakes up sooner. + * + * @param bufferSize the size of the buffered span data. + * @param scheduleDelayMillis the maximum delay in milliseconds. + */ + static SpanExporterImpl create(int bufferSize, long scheduleDelayMillis) { + // TODO(bdrutu): Consider to add a shutdown hook to not avoid dropping data. + WorkerThread workerThread = new WorkerThread(bufferSize, scheduleDelayMillis); + workerThread.start(); + return new SpanExporterImpl(workerThread); + } + + /** + * Adds a Span to the exporting service. + * + * @param span the {@code Span} to be added. + */ + public void addSpan(SpanImpl span) { + workerThread.addSpan(span); + } + + @Override + public void registerHandler(String name, Handler handler) { + workerThread.registerHandler(name, handler); + } + + @Override + public void unregisterHandler(String name) { + workerThread.unregisterHandler(name); + } + + private SpanExporterImpl(WorkerThread workerThread) { + this.workerThread = workerThread; + } + + @VisibleForTesting + Thread getServiceExporterThread() { + return workerThread; + } + + // Worker thread that batches multiple span data and calls the registered services to export + // that data. + // + // The map of registered handlers is implemented using ConcurrentHashMap ensuring full + // concurrency of retrievals and adjustable expected concurrency for updates. Retrievals + // reflect the results of the most recently completed update operations held upon their onset. + // + // The list of batched data is protected by an explicit monitor object which ensures full + // concurrency. + private static final class WorkerThread extends Thread { + private final Object monitor = new Object(); + + @GuardedBy("monitor") + private final List spans; + + private final Map serviceHandlers = new ConcurrentHashMap(); + private final int bufferSize; + private final long scheduleDelayMillis; + + // See SpanExporterImpl#addSpan. + private void addSpan(SpanImpl span) { + synchronized (monitor) { + this.spans.add(span); + if (spans.size() > bufferSize) { + monitor.notifyAll(); + } + } + } + + // See SpanExporter#registerHandler. + private void registerHandler(String name, Handler serviceHandler) { + serviceHandlers.put(name, serviceHandler); + } + + // See SpanExporter#unregisterHandler. + private void unregisterHandler(String name) { + serviceHandlers.remove(name); + } + + // Exports the list of SpanData to all the ServiceHandlers. + private void onBatchExport(List spanDataList) { + // From the java documentation of the ConcurrentHashMap#entrySet(): + // The view's iterator is a "weakly consistent" iterator that will never throw + // ConcurrentModificationException, and guarantees to traverse elements as they existed + // upon construction of the iterator, and may (but is not guaranteed to) reflect any + // modifications subsequent to construction. + for (Map.Entry it : serviceHandlers.entrySet()) { + // In case of any exception thrown by the service handlers continue to run. + try { + it.getValue().export(spanDataList); + } catch (Throwable e) { + logger.log(Level.WARNING, "Exception thrown by the service export " + it.getKey(), e); + } + } + } + + private WorkerThread(int bufferSize, long scheduleDelayMillis) { + spans = new LinkedList(); + this.bufferSize = bufferSize; + this.scheduleDelayMillis = scheduleDelayMillis; + setDaemon(true); + setName("ExportComponent.ServiceExporterThread"); + } + + // Returns an unmodifiable list of all buffered spans data to ensure that any registered + // service handler cannot modify the list. + private static List fromSpanImplToSpanData(List spans) { + List spanDatas = new ArrayList(spans.size()); + for (SpanImpl span : spans) { + spanDatas.add(span.toSpanData()); + } + return Collections.unmodifiableList(spanDatas); + } + + @Override + public void run() { + while (true) { + // Copy all the batched spans in a separate list to release the monitor lock asap to + // avoid blocking the producer thread. + List spansCopy; + synchronized (monitor) { + if (spans.size() < bufferSize) { + do { + // In the case of a spurious wakeup we export only if we have at least one span in + // the batch. It is acceptable because batching is a best effort mechanism here. + try { + monitor.wait(scheduleDelayMillis); + } catch (InterruptedException ie) { + // Preserve the interruption status as per guidance and stop doing any work. + Thread.currentThread().interrupt(); + return; + } + } while (spans.isEmpty()); + } + spansCopy = new ArrayList(spans); + spans.clear(); + } + // Execute the batch export outside the synchronized to not block all producers. + final List spanDataList = fromSpanImplToSpanData(spansCopy); + if (!spanDataList.isEmpty()) { + onBatchExport(spanDataList); + } + } + } + } +} diff --git a/impl_core/src/main/java/io/opencensus/implcore/trace/internal/ConcurrentIntrusiveList.java b/impl_core/src/main/java/io/opencensus/implcore/trace/internal/ConcurrentIntrusiveList.java new file mode 100644 index 00000000..ef2388c2 --- /dev/null +++ b/impl_core/src/main/java/io/opencensus/implcore/trace/internal/ConcurrentIntrusiveList.java @@ -0,0 +1,174 @@ +/* + * Copyright 2017, Google Inc. + * 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.internal; + +import static com.google.common.base.Preconditions.checkArgument; + +import io.opencensus.implcore.trace.internal.ConcurrentIntrusiveList.Element; +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; +import javax.annotation.concurrent.ThreadSafe; + +/** + * An {@code ConcurrentIntrusiveList} is a doubly-linked list where the link pointers are + * embedded in the elements. This makes insertion and removal into a known position constant time. + * + *

Elements must derive from the {@code Element>} interface: + * + *

{@code
+ * class MyClass implements Element {
+ *   private MyClass next = null;
+ *   private MyClass prev = null;
+ *
+ *   {@literal @}Override
+ *   MyClass getNext() {
+ *     return next;
+ *   }
+ *
+ *   {@literal @}Override
+ *   void setNext(MyClass element) {
+ *     next = element;
+ *   }
+ *
+ *   {@literal @}Override
+ *   MyClass getPrev() {
+ *     return prev;
+ *   }
+ *
+ *   {@literal @}Override
+ *   void setPrev(MyClass element) {
+ *     prev = element;
+ *   }
+ * }
+ * }
+ */ +@ThreadSafe +public final class ConcurrentIntrusiveList> { + private int size = 0; + private T head = null; + + public ConcurrentIntrusiveList() {} + + /** + * Adds the given {@code element} to the list. + * + * @param element the element to add. + * @throws IllegalArgumentException if the element is already in a list. + */ + public synchronized void addElement(T element) { + checkArgument( + element.getNext() == null && element.getPrev() == null && element != head, + "Element already in a list."); + size++; + if (head == null) { + head = element; + } else { + element.setNext(head); + head.setPrev(element); + head = element; + } + } + + /** + * Removes the given {@code element} from the list. + * + * @param element the element to remove. + * @throws IllegalArgumentException if the element is not in the list. + */ + public synchronized void removeElement(T element) { + checkArgument( + element.getNext() != null || element.getPrev() != null || element == head, + "Element not in the list."); + size--; + if (element.getPrev() == null) { + // This is the first element + head = element.getNext(); + if (head != null) { + // If more than one element in the list. + head.setPrev(null); + element.setNext(null); + } + } else if (element.getNext() == null) { + // This is the last element, and there is at least another element because + // element.getPrev() != null. + element.getPrev().setNext(null); + element.setPrev(null); + } else { + element.getPrev().setNext(element.getNext()); + element.getNext().setPrev(element.getPrev()); + element.setNext(null); + element.setPrev(null); + } + } + + /** + * Returns the number of elements in this list. + * + * @return the number of elements in this list. + */ + public synchronized int size() { + return size; + } + + /** + * Returns all the elements from this list. + * + * @return all the elements from this list. + */ + public synchronized Collection getAll() { + List all = new ArrayList(size); + for (T e = head; e != null; e = e.getNext()) { + all.add(e); + } + return all; + } + + /** + * This is an interface that must be implemented by any element that uses {@link + * ConcurrentIntrusiveList}. + * + * @param the element that will be used for the list. + */ + public interface Element> { + + /** + * Returns a reference to the next element in the list. + * + * @return a reference to the next element in the list. + */ + T getNext(); + + /** + * Sets the reference to the next element in the list. + * + * @param element the reference to the next element in the list. + */ + void setNext(T element); + + /** + * Returns a reference to the previous element in the list. + * + * @return a reference to the previous element in the list. + */ + T getPrev(); + + /** + * Sets the reference to the previous element in the list. + * + * @param element the reference to the previous element in the list. + */ + void setPrev(T element); + } +} diff --git a/impl_core/src/main/java/io/opencensus/implcore/trace/internal/RandomHandler.java b/impl_core/src/main/java/io/opencensus/implcore/trace/internal/RandomHandler.java new file mode 100644 index 00000000..702bd474 --- /dev/null +++ b/impl_core/src/main/java/io/opencensus/implcore/trace/internal/RandomHandler.java @@ -0,0 +1,47 @@ +/* + * Copyright 2017, Google Inc. + * 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.internal; + +import java.security.SecureRandom; +import java.util.Random; +import javax.annotation.concurrent.ThreadSafe; + +/** + * Abstract class to access the current {@link Random}. + * + *

Implementation can have a per thread instance or a single global instance. + */ +@ThreadSafe +public abstract class RandomHandler { + /** + * Returns the current {@link Random}. + * + * @return the current {@code Random}. + */ + public abstract Random current(); + + /** Implementation of the {@link RandomHandler} using {@link SecureRandom}. */ + @ThreadSafe + public static final class SecureRandomHandler extends RandomHandler { + private final Random random = new SecureRandom(); + + /** Constructs a new {@link SecureRandomHandler}. */ + public SecureRandomHandler() {} + + @Override + public Random current() { + return random; + } + } +} diff --git a/impl_core/src/main/java/io/opencensus/implcore/trace/propagation/BinaryFormatImpl.java b/impl_core/src/main/java/io/opencensus/implcore/trace/propagation/BinaryFormatImpl.java new file mode 100644 index 00000000..0aa70189 --- /dev/null +++ b/impl_core/src/main/java/io/opencensus/implcore/trace/propagation/BinaryFormatImpl.java @@ -0,0 +1,117 @@ +/* + * Copyright 2017, Google Inc. + * 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.propagation; + +import static com.google.common.base.Preconditions.checkNotNull; + +import io.opencensus.trace.SpanContext; +import io.opencensus.trace.SpanId; +import io.opencensus.trace.TraceId; +import io.opencensus.trace.TraceOptions; +import io.opencensus.trace.propagation.BinaryFormat; +import java.text.ParseException; + +/** + * Implementation of the {@link BinaryFormat}. + * + *

BinaryFormat format: + * + *

    + *
  • Binary value: <version_id><version_format> + *
  • version_id: 1-byte representing the version id. + *
  • For version_id = 0: + *
      + *
    • version_format: <field><field> + *
    • field_format: <field_id><field_format> + *
    • Fields: + *
        + *
      • TraceId: (field_id = 0, len = 16, default = "0000000000000000") - + * 16-byte array representing the trace_id. + *
      • SpanId: (field_id = 1, len = 8, default = "00000000") - 8-byte array + * representing the span_id. + *
      • TraceOptions: (field_id = 2, len = 1, default = "0") - 1-byte array + * representing the trace_options. + *
      + *
    • Fields MUST be encoded using the field id order (smaller to higher). + *
    • Valid value example: + *
        + *
      • {0, 0, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 1, 97, + * 98, 99, 100, 101, 102, 103, 104, 2, 1} + *
      • version_id = 0; + *
      • trace_id = {64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79} + *
      • span_id = {97, 98, 99, 100, 101, 102, 103, 104}; + *
      • trace_options = {1}; + *
      + *
    + *
+ */ +public final class BinaryFormatImpl extends BinaryFormat { + private static final byte VERSION_ID = 0; + private static final int VERSION_ID_OFFSET = 0; + // The version_id/field_id size in bytes. + private static final byte ID_SIZE = 1; + private static final byte TRACE_ID_FIELD_ID = 0; + private static final int TRACE_ID_FIELD_ID_OFFSET = VERSION_ID_OFFSET + ID_SIZE; + private static final int TRACE_ID_OFFSET = TRACE_ID_FIELD_ID_OFFSET + ID_SIZE; + private static final byte SPAN_ID_FIELD_ID = 1; + private static final int SPAN_ID_FIELD_ID_OFFSET = TRACE_ID_OFFSET + TraceId.SIZE; + private static final int SPAN_ID_OFFSET = SPAN_ID_FIELD_ID_OFFSET + ID_SIZE; + private static final byte TRACE_OPTION_FIELD_ID = 2; + private static final int TRACE_OPTION_FIELD_ID_OFFSET = SPAN_ID_OFFSET + SpanId.SIZE; + private static final int TRACE_OPTIONS_OFFSET = TRACE_OPTION_FIELD_ID_OFFSET + ID_SIZE; + private static final int FORMAT_LENGTH = + 4 * ID_SIZE + TraceId.SIZE + SpanId.SIZE + TraceOptions.SIZE; + + @Override + public byte[] toBinaryValue(SpanContext spanContext) { + checkNotNull(spanContext, "spanContext"); + byte[] bytes = new byte[FORMAT_LENGTH]; + bytes[VERSION_ID_OFFSET] = VERSION_ID; + bytes[TRACE_ID_FIELD_ID_OFFSET] = TRACE_ID_FIELD_ID; + spanContext.getTraceId().copyBytesTo(bytes, TRACE_ID_OFFSET); + bytes[SPAN_ID_FIELD_ID_OFFSET] = SPAN_ID_FIELD_ID; + spanContext.getSpanId().copyBytesTo(bytes, SPAN_ID_OFFSET); + bytes[TRACE_OPTION_FIELD_ID_OFFSET] = TRACE_OPTION_FIELD_ID; + spanContext.getTraceOptions().copyBytesTo(bytes, TRACE_OPTIONS_OFFSET); + return bytes; + } + + @Override + public SpanContext fromBinaryValue(byte[] bytes) throws ParseException { + checkNotNull(bytes, "bytes"); + if (bytes.length == 0 || bytes[0] != VERSION_ID) { + throw new ParseException("Unsupported version.", 0); + } + TraceId traceId = TraceId.INVALID; + SpanId spanId = SpanId.INVALID; + TraceOptions traceOptions = TraceOptions.DEFAULT; + int pos = 1; + try { + if (bytes.length > pos && bytes[pos] == TRACE_ID_FIELD_ID) { + traceId = TraceId.fromBytes(bytes, pos + ID_SIZE); + pos += ID_SIZE + TraceId.SIZE; + } + if (bytes.length > pos && bytes[pos] == SPAN_ID_FIELD_ID) { + spanId = SpanId.fromBytes(bytes, pos + ID_SIZE); + pos += ID_SIZE + SpanId.SIZE; + } + if (bytes.length > pos && bytes[pos] == TRACE_OPTION_FIELD_ID) { + traceOptions = TraceOptions.fromBytes(bytes, pos + ID_SIZE); + } + return SpanContext.create(traceId, spanId, traceOptions); + } catch (IndexOutOfBoundsException e) { + throw new ParseException("Invalid input: " + e.toString(), pos); + } + } +} diff --git a/impl_core/src/main/java/io/opencensus/implcore/trace/propagation/PropagationComponentImpl.java b/impl_core/src/main/java/io/opencensus/implcore/trace/propagation/PropagationComponentImpl.java new file mode 100644 index 00000000..b090ab76 --- /dev/null +++ b/impl_core/src/main/java/io/opencensus/implcore/trace/propagation/PropagationComponentImpl.java @@ -0,0 +1,27 @@ +/* + * Copyright 2017, Google Inc. + * 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.propagation; + +import io.opencensus.trace.propagation.BinaryFormat; +import io.opencensus.trace.propagation.PropagationComponent; + +/** Implementation of the {@link PropagationComponent}. */ +public class PropagationComponentImpl extends PropagationComponent { + private final BinaryFormat binaryFormat = new BinaryFormatImpl(); + + @Override + public BinaryFormat getBinaryFormat() { + return binaryFormat; + } +} -- cgit v1.2.3 From b2f48c5d608c154d75ae7616c660e053f6e5c5f7 Mon Sep 17 00:00:00 2001 From: Bogdan Drutu Date: Wed, 23 Aug 2017 09:52:48 -0700 Subject: Change the licence to OpenCensus authors. (#539) --- .../src/main/java/io/opencensus/implcore/trace/SpanBuilderImpl.java | 5 ++++- impl_core/src/main/java/io/opencensus/implcore/trace/SpanImpl.java | 5 ++++- .../main/java/io/opencensus/implcore/trace/StartEndHandlerImpl.java | 5 ++++- .../java/io/opencensus/implcore/trace/TraceComponentImplBase.java | 5 ++++- impl_core/src/main/java/io/opencensus/implcore/trace/TracerImpl.java | 5 ++++- .../java/io/opencensus/implcore/trace/config/TraceConfigImpl.java | 5 ++++- .../io/opencensus/implcore/trace/export/ExportComponentImpl.java | 5 ++++- .../io/opencensus/implcore/trace/export/RunningSpanStoreImpl.java | 5 ++++- .../io/opencensus/implcore/trace/export/SampledSpanStoreImpl.java | 5 ++++- .../java/io/opencensus/implcore/trace/export/SpanExporterImpl.java | 5 ++++- .../opencensus/implcore/trace/internal/ConcurrentIntrusiveList.java | 5 ++++- .../java/io/opencensus/implcore/trace/internal/RandomHandler.java | 5 ++++- .../io/opencensus/implcore/trace/propagation/BinaryFormatImpl.java | 5 ++++- .../implcore/trace/propagation/PropagationComponentImpl.java | 5 ++++- 14 files changed, 56 insertions(+), 14 deletions(-) (limited to 'impl_core/src/main/java/io/opencensus/implcore/trace') 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 index 21bc3757..b66a354f 100644 --- a/impl_core/src/main/java/io/opencensus/implcore/trace/SpanBuilderImpl.java +++ b/impl_core/src/main/java/io/opencensus/implcore/trace/SpanBuilderImpl.java @@ -1,9 +1,12 @@ /* - * Copyright 2017, Google Inc. + * 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. diff --git a/impl_core/src/main/java/io/opencensus/implcore/trace/SpanImpl.java b/impl_core/src/main/java/io/opencensus/implcore/trace/SpanImpl.java index fbc753f5..7715a89f 100644 --- a/impl_core/src/main/java/io/opencensus/implcore/trace/SpanImpl.java +++ b/impl_core/src/main/java/io/opencensus/implcore/trace/SpanImpl.java @@ -1,9 +1,12 @@ /* - * Copyright 2017, Google Inc. + * 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. diff --git a/impl_core/src/main/java/io/opencensus/implcore/trace/StartEndHandlerImpl.java b/impl_core/src/main/java/io/opencensus/implcore/trace/StartEndHandlerImpl.java index 76276cd7..fdb6147c 100644 --- a/impl_core/src/main/java/io/opencensus/implcore/trace/StartEndHandlerImpl.java +++ b/impl_core/src/main/java/io/opencensus/implcore/trace/StartEndHandlerImpl.java @@ -1,9 +1,12 @@ /* - * Copyright 2017, Google Inc. + * 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. diff --git a/impl_core/src/main/java/io/opencensus/implcore/trace/TraceComponentImplBase.java b/impl_core/src/main/java/io/opencensus/implcore/trace/TraceComponentImplBase.java index 8c16950d..c4856499 100644 --- a/impl_core/src/main/java/io/opencensus/implcore/trace/TraceComponentImplBase.java +++ b/impl_core/src/main/java/io/opencensus/implcore/trace/TraceComponentImplBase.java @@ -1,9 +1,12 @@ /* - * Copyright 2017, Google Inc. + * 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. diff --git a/impl_core/src/main/java/io/opencensus/implcore/trace/TracerImpl.java b/impl_core/src/main/java/io/opencensus/implcore/trace/TracerImpl.java index 0da79120..fcf30ff0 100644 --- a/impl_core/src/main/java/io/opencensus/implcore/trace/TracerImpl.java +++ b/impl_core/src/main/java/io/opencensus/implcore/trace/TracerImpl.java @@ -1,9 +1,12 @@ /* - * Copyright 2017, Google Inc. + * 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. diff --git a/impl_core/src/main/java/io/opencensus/implcore/trace/config/TraceConfigImpl.java b/impl_core/src/main/java/io/opencensus/implcore/trace/config/TraceConfigImpl.java index 1f14226b..25f0c613 100644 --- a/impl_core/src/main/java/io/opencensus/implcore/trace/config/TraceConfigImpl.java +++ b/impl_core/src/main/java/io/opencensus/implcore/trace/config/TraceConfigImpl.java @@ -1,9 +1,12 @@ /* - * Copyright 2017, Google Inc. + * 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. diff --git a/impl_core/src/main/java/io/opencensus/implcore/trace/export/ExportComponentImpl.java b/impl_core/src/main/java/io/opencensus/implcore/trace/export/ExportComponentImpl.java index ac0f8087..7d9b1895 100644 --- a/impl_core/src/main/java/io/opencensus/implcore/trace/export/ExportComponentImpl.java +++ b/impl_core/src/main/java/io/opencensus/implcore/trace/export/ExportComponentImpl.java @@ -1,9 +1,12 @@ /* - * Copyright 2017, Google Inc. + * 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. diff --git a/impl_core/src/main/java/io/opencensus/implcore/trace/export/RunningSpanStoreImpl.java b/impl_core/src/main/java/io/opencensus/implcore/trace/export/RunningSpanStoreImpl.java index a793644a..98a51707 100644 --- a/impl_core/src/main/java/io/opencensus/implcore/trace/export/RunningSpanStoreImpl.java +++ b/impl_core/src/main/java/io/opencensus/implcore/trace/export/RunningSpanStoreImpl.java @@ -1,9 +1,12 @@ /* - * Copyright 2017, Google Inc. + * 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. diff --git a/impl_core/src/main/java/io/opencensus/implcore/trace/export/SampledSpanStoreImpl.java b/impl_core/src/main/java/io/opencensus/implcore/trace/export/SampledSpanStoreImpl.java index 5331ade6..554666bd 100644 --- a/impl_core/src/main/java/io/opencensus/implcore/trace/export/SampledSpanStoreImpl.java +++ b/impl_core/src/main/java/io/opencensus/implcore/trace/export/SampledSpanStoreImpl.java @@ -1,9 +1,12 @@ /* - * Copyright 2017, Google Inc. + * 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. diff --git a/impl_core/src/main/java/io/opencensus/implcore/trace/export/SpanExporterImpl.java b/impl_core/src/main/java/io/opencensus/implcore/trace/export/SpanExporterImpl.java index af46cf54..c7664ecc 100644 --- a/impl_core/src/main/java/io/opencensus/implcore/trace/export/SpanExporterImpl.java +++ b/impl_core/src/main/java/io/opencensus/implcore/trace/export/SpanExporterImpl.java @@ -1,9 +1,12 @@ /* - * Copyright 2017, Google Inc. + * 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. diff --git a/impl_core/src/main/java/io/opencensus/implcore/trace/internal/ConcurrentIntrusiveList.java b/impl_core/src/main/java/io/opencensus/implcore/trace/internal/ConcurrentIntrusiveList.java index ef2388c2..95906012 100644 --- a/impl_core/src/main/java/io/opencensus/implcore/trace/internal/ConcurrentIntrusiveList.java +++ b/impl_core/src/main/java/io/opencensus/implcore/trace/internal/ConcurrentIntrusiveList.java @@ -1,9 +1,12 @@ /* - * Copyright 2017, Google Inc. + * 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. diff --git a/impl_core/src/main/java/io/opencensus/implcore/trace/internal/RandomHandler.java b/impl_core/src/main/java/io/opencensus/implcore/trace/internal/RandomHandler.java index 702bd474..70be5a90 100644 --- a/impl_core/src/main/java/io/opencensus/implcore/trace/internal/RandomHandler.java +++ b/impl_core/src/main/java/io/opencensus/implcore/trace/internal/RandomHandler.java @@ -1,9 +1,12 @@ /* - * Copyright 2017, Google Inc. + * 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. diff --git a/impl_core/src/main/java/io/opencensus/implcore/trace/propagation/BinaryFormatImpl.java b/impl_core/src/main/java/io/opencensus/implcore/trace/propagation/BinaryFormatImpl.java index 0aa70189..c388ae94 100644 --- a/impl_core/src/main/java/io/opencensus/implcore/trace/propagation/BinaryFormatImpl.java +++ b/impl_core/src/main/java/io/opencensus/implcore/trace/propagation/BinaryFormatImpl.java @@ -1,9 +1,12 @@ /* - * Copyright 2017, Google Inc. + * 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. diff --git a/impl_core/src/main/java/io/opencensus/implcore/trace/propagation/PropagationComponentImpl.java b/impl_core/src/main/java/io/opencensus/implcore/trace/propagation/PropagationComponentImpl.java index b090ab76..757623a3 100644 --- a/impl_core/src/main/java/io/opencensus/implcore/trace/propagation/PropagationComponentImpl.java +++ b/impl_core/src/main/java/io/opencensus/implcore/trace/propagation/PropagationComponentImpl.java @@ -1,9 +1,12 @@ /* - * Copyright 2017, Google Inc. + * 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. -- cgit v1.2.3 From 1fb102567c48b02ece1f8a7d8ba50cacab1f46d1 Mon Sep 17 00:00:00 2001 From: Bogdan Drutu Date: Tue, 29 Aug 2017 22:33:13 -0700 Subject: Add new api that is easier to use for user to add only one Attribute. (#571) * Add new api that is easier to use for user to add only one Attribute. * Rename addAttribute[s] to putAttribute[s] and deprecate the old API. * Update tests to use putAttributes. --- .../io/opencensus/implcore/trace/SpanImpl.java | 37 +++++++++++++++++++--- 1 file changed, 32 insertions(+), 5 deletions(-) (limited to 'impl_core/src/main/java/io/opencensus/implcore/trace') diff --git a/impl_core/src/main/java/io/opencensus/implcore/trace/SpanImpl.java b/impl_core/src/main/java/io/opencensus/implcore/trace/SpanImpl.java index 7715a89f..0a22f726 100644 --- a/impl_core/src/main/java/io/opencensus/implcore/trace/SpanImpl.java +++ b/impl_core/src/main/java/io/opencensus/implcore/trace/SpanImpl.java @@ -241,16 +241,36 @@ public final class SpanImpl extends Span implements Element { } @Override + public void putAttribute(String key, AttributeValue value) { + if (!getOptions().contains(Options.RECORD_EVENTS)) { + return; + } + synchronized (this) { + if (hasBeenEnded) { + logger.log(Level.FINE, "Calling putAttributes() on an ended Span."); + return; + } + getInitializedAttributes().putAttribute(key, value); + } + } + + @Override + @SuppressWarnings("deprecation") public void addAttributes(Map attributes) { + putAttributes(attributes); + } + + @Override + public void putAttributes(Map attributes) { if (!getOptions().contains(Options.RECORD_EVENTS)) { return; } synchronized (this) { if (hasBeenEnded) { - logger.log(Level.FINE, "Calling addAttributes() on an ended Span."); + logger.log(Level.FINE, "Calling putAttributes() on an ended Span."); return; } - getInitializedAttributes().addAttributes(attributes); + getInitializedAttributes().putAttributes(attributes); } } @@ -437,9 +457,16 @@ public final class SpanImpl extends Span implements Element { this.capacity = capacity; } - // Users must call this method instead of put or putAll to keep count of the total number of - // entries inserted. - private void addAttributes(Map attributes) { + // Users must call this method instead of put to keep count of the total number of entries + // inserted. + private void putAttribute(String key, AttributeValue value) { + totalRecordedAttributes += 1; + put(key, value); + } + + // Users must call this method instead of putAll to keep count of the total number of entries + // inserted. + private void putAttributes(Map attributes) { totalRecordedAttributes += attributes.size(); putAll(attributes); } -- cgit v1.2.3 From f2714546d47aab1e904fd1c42e147549964c7341 Mon Sep 17 00:00:00 2001 From: Bogdan Drutu Date: Thu, 31 Aug 2017 09:52:56 -0700 Subject: Fix backwards compatibility between TraceComponentBaseImpl and TraceComponent. (#575) --- .../opencensus/implcore/trace/TraceComponentImplBase.java | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) (limited to 'impl_core/src/main/java/io/opencensus/implcore/trace') diff --git a/impl_core/src/main/java/io/opencensus/implcore/trace/TraceComponentImplBase.java b/impl_core/src/main/java/io/opencensus/implcore/trace/TraceComponentImplBase.java index c4856499..f5f70a52 100644 --- a/impl_core/src/main/java/io/opencensus/implcore/trace/TraceComponentImplBase.java +++ b/impl_core/src/main/java/io/opencensus/implcore/trace/TraceComponentImplBase.java @@ -30,8 +30,14 @@ import io.opencensus.trace.config.TraceConfig; import io.opencensus.trace.export.ExportComponent; import io.opencensus.trace.propagation.PropagationComponent; -/** Base implementation of the {@link TraceComponent}. */ -public class TraceComponentImplBase extends TraceComponent { +/** + * Helper class to allow sharing the code for all the {@link TraceComponent} implementations. This + * class cannot use inheritance because in version 0.5.* the constructor of the {@code + * TraceComponent} is package protected. + * + *

This can be changed back to inheritance when version 0.5.* is no longer supported. + */ +public final class TraceComponentImplBase { private final ExportComponentImpl exportComponent; private final PropagationComponent propagationComponent = new PropagationComponentImpl(); private final Clock clock; @@ -63,27 +69,22 @@ public class TraceComponentImplBase extends TraceComponent { tracer = new TracerImpl(randomHandler, startEndHandler, clock, traceConfig); } - @Override public Tracer getTracer() { return tracer; } - @Override public PropagationComponent getPropagationComponent() { return propagationComponent; } - @Override public final Clock getClock() { return clock; } - @Override public ExportComponent getExportComponent() { return exportComponent; } - @Override public TraceConfig getTraceConfig() { return traceConfig; } -- cgit v1.2.3 From a64c591fcb0294873398617093d8d3e5bb3de626 Mon Sep 17 00:00:00 2001 From: Bogdan Drutu Date: Thu, 7 Sep 2017 18:47:15 -0700 Subject: Add separate buckets for sampled and not sampled spans. (#592) --- .../trace/export/SampledSpanStoreImpl.java | 47 +++++++++++++++++----- 1 file changed, 37 insertions(+), 10 deletions(-) (limited to 'impl_core/src/main/java/io/opencensus/implcore/trace') diff --git a/impl_core/src/main/java/io/opencensus/implcore/trace/export/SampledSpanStoreImpl.java b/impl_core/src/main/java/io/opencensus/implcore/trace/export/SampledSpanStoreImpl.java index 554666bd..fc77a09a 100644 --- a/impl_core/src/main/java/io/opencensus/implcore/trace/export/SampledSpanStoreImpl.java +++ b/impl_core/src/main/java/io/opencensus/implcore/trace/export/SampledSpanStoreImpl.java @@ -51,25 +51,44 @@ public final class SampledSpanStoreImpl extends SampledSpanStore { private static final class Bucket { - private final EvictingQueue queue; - private long lastSampleNanoTime; + private final EvictingQueue sampledSpansQueue; + private final EvictingQueue notSampledSpansQueue; + private long lastSampledNanoTime; + private long lastNotSampledNanoTime; private Bucket(int numSamples) { - queue = EvictingQueue.create(numSamples); + sampledSpansQueue = EvictingQueue.create(numSamples); + notSampledSpansQueue = EvictingQueue.create(numSamples); } private void considerForSampling(SpanImpl span) { long spanEndNanoTime = span.getEndNanoTime(); - // Need to compare by doing the subtraction all the time because in case of an overflow, - // this may never sample again (at least for the next ~200 years). No real chance to - // overflow two times because that means the process runs for ~200 years. - if (spanEndNanoTime - lastSampleNanoTime > TIME_BETWEEN_SAMPLES) { - queue.add(span); - lastSampleNanoTime = spanEndNanoTime; + if (span.getContext().getTraceOptions().isSampled()) { + // Need to compare by doing the subtraction all the time because in case of an overflow, + // this may never sample again (at least for the next ~200 years). No real chance to + // overflow two times because that means the process runs for ~200 years. + if (spanEndNanoTime - lastSampledNanoTime > TIME_BETWEEN_SAMPLES) { + sampledSpansQueue.add(span); + lastSampledNanoTime = spanEndNanoTime; + } + } else { + // Need to compare by doing the subtraction all the time because in case of an overflow, + // this may never sample again (at least for the next ~200 years). No real chance to + // overflow two times because that means the process runs for ~200 years. + if (spanEndNanoTime - lastNotSampledNanoTime > TIME_BETWEEN_SAMPLES) { + notSampledSpansQueue.add(span); + lastNotSampledNanoTime = spanEndNanoTime; + } } } private void getSamples(int maxSpansToReturn, List output) { + getSamples(sampledSpansQueue, maxSpansToReturn, output); + getSamples(notSampledSpansQueue, maxSpansToReturn, output); + } + + private static void getSamples(EvictingQueue queue, int maxSpansToReturn, + List output) { for (SpanImpl span : queue) { if (output.size() >= maxSpansToReturn) { break; @@ -80,6 +99,14 @@ public final class SampledSpanStoreImpl extends SampledSpanStore { private void getSamplesFilteredByLatency( long latencyLowerNs, long latencyUpperNs, int maxSpansToReturn, List output) { + getSamplesFilteredByLatency(sampledSpansQueue, latencyLowerNs, latencyUpperNs, + maxSpansToReturn, output); + getSamplesFilteredByLatency(notSampledSpansQueue, latencyLowerNs, latencyUpperNs, + maxSpansToReturn, output); + } + + private static void getSamplesFilteredByLatency(EvictingQueue queue, + long latencyLowerNs, long latencyUpperNs, int maxSpansToReturn, List output) { for (SpanImpl span : queue) { if (output.size() >= maxSpansToReturn) { break; @@ -92,7 +119,7 @@ public final class SampledSpanStoreImpl extends SampledSpanStore { } private int getNumSamples() { - return queue.size(); + return sampledSpansQueue.size() + notSampledSpansQueue.size(); } } -- cgit v1.2.3 From 150cc0515e259b3886b241fab91b91c7d143b0a1 Mon Sep 17 00:00:00 2001 From: Bogdan Drutu Date: Wed, 13 Sep 2017 16:45:53 -0700 Subject: Add a method to list all registered span names. (#623) * Add a method to list all registered span names. * Change the name to getRegisteredSpanNamesForCollection --- .../opencensus/implcore/trace/export/SampledSpanStoreImpl.java | 9 +++++++++ 1 file changed, 9 insertions(+) (limited to 'impl_core/src/main/java/io/opencensus/implcore/trace') diff --git a/impl_core/src/main/java/io/opencensus/implcore/trace/export/SampledSpanStoreImpl.java b/impl_core/src/main/java/io/opencensus/implcore/trace/export/SampledSpanStoreImpl.java index fc77a09a..07207e1b 100644 --- a/impl_core/src/main/java/io/opencensus/implcore/trace/export/SampledSpanStoreImpl.java +++ b/impl_core/src/main/java/io/opencensus/implcore/trace/export/SampledSpanStoreImpl.java @@ -27,8 +27,10 @@ import java.util.Collection; import java.util.Collections; import java.util.EnumMap; import java.util.HashMap; +import java.util.HashSet; import java.util.List; import java.util.Map; +import java.util.Set; import java.util.concurrent.TimeUnit; import javax.annotation.concurrent.GuardedBy; import javax.annotation.concurrent.ThreadSafe; @@ -275,6 +277,13 @@ public final class SampledSpanStoreImpl extends SampledSpanStore { } } + @Override + public Set getRegisteredSpanNamesForCollection() { + synchronized (samples) { + return Collections.unmodifiableSet(new HashSet(samples.keySet())); + } + } + @Override public Collection getErrorSampledSpans(ErrorFilter filter) { int numSpansToReturn = -- cgit v1.2.3 From 7782a953a5c6ea4ecfe127ae7bff053f6c2c22d5 Mon Sep 17 00:00:00 2001 From: Bogdan Drutu Date: Sat, 16 Sep 2017 08:20:38 -0700 Subject: Implement deprecated method addAttributes in the Span and remove it from anywhere else. (#633) * Implement deprecated method addAttributes in the Span and remove it from anywhere else. * Fix tests and add warning to override putAttributes. --- impl_core/src/main/java/io/opencensus/implcore/trace/SpanImpl.java | 6 ------ 1 file changed, 6 deletions(-) (limited to 'impl_core/src/main/java/io/opencensus/implcore/trace') diff --git a/impl_core/src/main/java/io/opencensus/implcore/trace/SpanImpl.java b/impl_core/src/main/java/io/opencensus/implcore/trace/SpanImpl.java index 0a22f726..bd5ea5d2 100644 --- a/impl_core/src/main/java/io/opencensus/implcore/trace/SpanImpl.java +++ b/impl_core/src/main/java/io/opencensus/implcore/trace/SpanImpl.java @@ -254,12 +254,6 @@ public final class SpanImpl extends Span implements Element { } } - @Override - @SuppressWarnings("deprecation") - public void addAttributes(Map attributes) { - putAttributes(attributes); - } - @Override public void putAttributes(Map attributes) { if (!getOptions().contains(Options.RECORD_EVENTS)) { -- cgit v1.2.3 From 53cb6c8bec4540c66c4cbd22535797a76fef921a Mon Sep 17 00:00:00 2001 From: Bogdan Drutu Date: Mon, 18 Sep 2017 11:33:49 -0700 Subject: Add a new SpanContextParseException and use it in BinaryFormat. (#642) * Add a new SpanContextParseException and use it in BinaryFormat * Fix review comments. --- .../implcore/trace/propagation/BinaryFormatImpl.java | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'impl_core/src/main/java/io/opencensus/implcore/trace') diff --git a/impl_core/src/main/java/io/opencensus/implcore/trace/propagation/BinaryFormatImpl.java b/impl_core/src/main/java/io/opencensus/implcore/trace/propagation/BinaryFormatImpl.java index c388ae94..6075c80b 100644 --- a/impl_core/src/main/java/io/opencensus/implcore/trace/propagation/BinaryFormatImpl.java +++ b/impl_core/src/main/java/io/opencensus/implcore/trace/propagation/BinaryFormatImpl.java @@ -23,7 +23,7 @@ import io.opencensus.trace.SpanId; import io.opencensus.trace.TraceId; import io.opencensus.trace.TraceOptions; import io.opencensus.trace.propagation.BinaryFormat; -import java.text.ParseException; +import io.opencensus.trace.propagation.SpanContextParseException; /** * Implementation of the {@link BinaryFormat}. @@ -77,7 +77,7 @@ public final class BinaryFormatImpl extends BinaryFormat { 4 * ID_SIZE + TraceId.SIZE + SpanId.SIZE + TraceOptions.SIZE; @Override - public byte[] toBinaryValue(SpanContext spanContext) { + public byte[] toByteArray(SpanContext spanContext) { checkNotNull(spanContext, "spanContext"); byte[] bytes = new byte[FORMAT_LENGTH]; bytes[VERSION_ID_OFFSET] = VERSION_ID; @@ -91,10 +91,10 @@ public final class BinaryFormatImpl extends BinaryFormat { } @Override - public SpanContext fromBinaryValue(byte[] bytes) throws ParseException { + public SpanContext fromByteArray(byte[] bytes) throws SpanContextParseException { checkNotNull(bytes, "bytes"); if (bytes.length == 0 || bytes[0] != VERSION_ID) { - throw new ParseException("Unsupported version.", 0); + throw new SpanContextParseException("Unsupported version."); } TraceId traceId = TraceId.INVALID; SpanId spanId = SpanId.INVALID; @@ -114,7 +114,7 @@ public final class BinaryFormatImpl extends BinaryFormat { } return SpanContext.create(traceId, spanId, traceOptions); } catch (IndexOutOfBoundsException e) { - throw new ParseException("Invalid input: " + e.toString(), pos); + throw new SpanContextParseException("Invalid input.", e); } } } -- cgit v1.2.3 From 83fed9c3af641b227496ce96f9cc0b51b316df82 Mon Sep 17 00:00:00 2001 From: Bogdan Drutu Date: Thu, 21 Sep 2017 19:39:25 -0700 Subject: Change when we check the sampler. (#657) * Change when we check the sampler. * Fix comments. * Deprecate setIsSampled without an argument. --- .../opencensus/implcore/trace/SpanBuilderImpl.java | 32 ++++++++++++++++++---- 1 file changed, 26 insertions(+), 6 deletions(-) (limited to 'impl_core/src/main/java/io/opencensus/implcore/trace') 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 index b66a354f..3cee1def 100644 --- a/impl_core/src/main/java/io/opencensus/implcore/trace/SpanBuilderImpl.java +++ b/impl_core/src/main/java/io/opencensus/implcore/trace/SpanBuilderImpl.java @@ -75,12 +75,8 @@ final class SpanBuilderImpl extends SpanBuilder { parentSpanId = parent.getSpanId(); traceOptionsBuilder = TraceOptions.builder(parent.getTraceOptions()); } - if (sampler == null) { - sampler = activeTraceParams.getSampler(); - } - if (sampler.shouldSample(parent, hasRemoteParent, traceId, spanId, name, parentLinks)) { - traceOptionsBuilder.setIsSampled(); - } + traceOptionsBuilder.setIsSampled(makeSamplingDecision( + parent, hasRemoteParent, name, sampler, parentLinks, traceId, spanId, activeTraceParams)); TraceOptions traceOptions = traceOptionsBuilder.build(); EnumSet spanOptions = EnumSet.noneOf(Span.Options.class); if (traceOptions.isSampled() || Boolean.TRUE.equals(recordEvents)) { @@ -101,6 +97,30 @@ final class SpanBuilderImpl extends SpanBuilder { return span; } + private static boolean makeSamplingDecision( + @Nullable SpanContext parent, + @Nullable Boolean hasRemoteParent, + String name, + @Nullable Sampler sampler, + List 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(); + } + private static void linkSpans(Span span, List parentLinks) { if (!parentLinks.isEmpty()) { Link childLink = Link.fromSpanContext(span.getContext(), Type.CHILD_LINKED_SPAN); -- cgit v1.2.3 From 23d498078cf3acd028f5917822be8560cc13df28 Mon Sep 17 00:00:00 2001 From: Bogdan Drutu Date: Fri, 22 Sep 2017 14:08:46 -0700 Subject: Fix probability sampler and sampling. (#661) * Fix probability sampler and sampling. * Add more tests and fix comments. --- .../java/io/opencensus/implcore/trace/SpanBuilderImpl.java | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) (limited to 'impl_core/src/main/java/io/opencensus/implcore/trace') 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 index 3cee1def..a02f6085 100644 --- a/impl_core/src/main/java/io/opencensus/implcore/trace/SpanBuilderImpl.java +++ b/impl_core/src/main/java/io/opencensus/implcore/trace/SpanBuilderImpl.java @@ -118,7 +118,16 @@ final class SpanBuilderImpl extends SpanBuilder { .shouldSample(parent, hasRemoteParent, traceId, spanId, name, parentLinks); } // Parent is always different than null because otherwise we use the default sampler. - return parent.getTraceOptions().isSampled(); + return parent.getTraceOptions().isSampled() || isAnyParentLinkSampled(parentLinks); + } + + private static boolean isAnyParentLinkSampled(List parentLinks) { + for (Span parentLink : parentLinks) { + if (parentLink.getContext().getTraceOptions().isSampled()) { + return true; + } + } + return false; } private static void linkSpans(Span span, List parentLinks) { -- cgit v1.2.3 From dbff329210261a13e5a8c5ab525114cfdbfd8448 Mon Sep 17 00:00:00 2001 From: Bogdan Drutu Date: Wed, 18 Oct 2017 11:48:22 -0700 Subject: Add an option in EndSpanOptions to register the span name for sampled store. (#703) * Add an option in SpanBuilder to register the span name for sampled store. * Change to LocalSpanStore name the SpanBuilder. * Move the option to EndSpanOptions. * Fix comments. --- .../opencensus/implcore/trace/SpanBuilderImpl.java | 12 ++++++++-- .../io/opencensus/implcore/trace/SpanImpl.java | 19 ++++++++++++++- .../trace/export/SampledSpanStoreImpl.java | 28 ++++++++++++++-------- 3 files changed, 46 insertions(+), 13 deletions(-) (limited to 'impl_core/src/main/java/io/opencensus/implcore/trace') 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 index a02f6085..80f904d6 100644 --- a/impl_core/src/main/java/io/opencensus/implcore/trace/SpanBuilderImpl.java +++ b/impl_core/src/main/java/io/opencensus/implcore/trace/SpanBuilderImpl.java @@ -75,8 +75,16 @@ final class SpanBuilderImpl extends SpanBuilder { parentSpanId = parent.getSpanId(); traceOptionsBuilder = TraceOptions.builder(parent.getTraceOptions()); } - traceOptionsBuilder.setIsSampled(makeSamplingDecision( - parent, hasRemoteParent, name, sampler, parentLinks, traceId, spanId, activeTraceParams)); + traceOptionsBuilder.setIsSampled( + makeSamplingDecision( + parent, + hasRemoteParent, + name, + sampler, + parentLinks, + traceId, + spanId, + activeTraceParams)); TraceOptions traceOptions = traceOptionsBuilder.build(); EnumSet spanOptions = EnumSet.noneOf(Span.Options.class); if (traceOptions.isSampled() || Boolean.TRUE.equals(recordEvents)) { diff --git a/impl_core/src/main/java/io/opencensus/implcore/trace/SpanImpl.java b/impl_core/src/main/java/io/opencensus/implcore/trace/SpanImpl.java index bd5ea5d2..fefaf486 100644 --- a/impl_core/src/main/java/io/opencensus/implcore/trace/SpanImpl.java +++ b/impl_core/src/main/java/io/opencensus/implcore/trace/SpanImpl.java @@ -95,6 +95,9 @@ public final class SpanImpl extends Span implements Element { @GuardedBy("this") private boolean hasBeenEnded; + @GuardedBy("this") + private boolean sampleToLocalSpanStore; + // Pointers for the ConcurrentIntrusiveList$Element. Guarded by the ConcurrentIntrusiveList. private SpanImpl next = null; private SpanImpl prev = null; @@ -190,6 +193,18 @@ public final class SpanImpl extends Span implements Element { } } + /** + * Returns if the name of this {@code Span} must be register to the {@code SampledSpanStore}. + * + * @return if the name of this {@code Span} must be register to the {@code SampledSpanStore}. + */ + public boolean getSampleToLocalSpanStore() { + synchronized (this) { + checkState(hasBeenEnded, "Running span does not have the SampleToLocalSpanStore set."); + return sampleToLocalSpanStore; + } + } + /** * Returns the {@code TimestampConverter} used by this {@code Span}. * @@ -234,7 +249,7 @@ public final class SpanImpl extends Span implements Element { annotationsSpanData, networkEventsSpanData, linksSpanData, - null, // Not supported yet. + null, // Not supported yet. hasBeenEnded ? status : null, hasBeenEnded ? timestampConverter.convertNanoTime(endNanoTime) : null); } @@ -345,6 +360,7 @@ public final class SpanImpl extends Span implements Element { return; } status = options.getStatus(); + sampleToLocalSpanStore = options.getSampleToLocalSpanStore(); endNanoTime = clock.nowNanos(); hasBeenEnded = true; } @@ -528,6 +544,7 @@ public final class SpanImpl extends Span implements Element { this.startEndHandler = startEndHandler; this.clock = clock; this.hasBeenEnded = false; + this.sampleToLocalSpanStore = false; if (getOptions().contains(Options.RECORD_EVENTS)) { this.timestampConverter = timestampConverter != null ? timestampConverter : TimestampConverter.now(clock); diff --git a/impl_core/src/main/java/io/opencensus/implcore/trace/export/SampledSpanStoreImpl.java b/impl_core/src/main/java/io/opencensus/implcore/trace/export/SampledSpanStoreImpl.java index 07207e1b..126d4634 100644 --- a/impl_core/src/main/java/io/opencensus/implcore/trace/export/SampledSpanStoreImpl.java +++ b/impl_core/src/main/java/io/opencensus/implcore/trace/export/SampledSpanStoreImpl.java @@ -89,8 +89,8 @@ public final class SampledSpanStoreImpl extends SampledSpanStore { getSamples(notSampledSpansQueue, maxSpansToReturn, output); } - private static void getSamples(EvictingQueue queue, int maxSpansToReturn, - List output) { + private static void getSamples( + EvictingQueue queue, int maxSpansToReturn, List output) { for (SpanImpl span : queue) { if (output.size() >= maxSpansToReturn) { break; @@ -101,14 +101,18 @@ public final class SampledSpanStoreImpl extends SampledSpanStore { private void getSamplesFilteredByLatency( long latencyLowerNs, long latencyUpperNs, int maxSpansToReturn, List output) { - getSamplesFilteredByLatency(sampledSpansQueue, latencyLowerNs, latencyUpperNs, - maxSpansToReturn, output); - getSamplesFilteredByLatency(notSampledSpansQueue, latencyLowerNs, latencyUpperNs, - maxSpansToReturn, output); + getSamplesFilteredByLatency( + sampledSpansQueue, latencyLowerNs, latencyUpperNs, maxSpansToReturn, output); + getSamplesFilteredByLatency( + notSampledSpansQueue, latencyLowerNs, latencyUpperNs, maxSpansToReturn, output); } - private static void getSamplesFilteredByLatency(EvictingQueue queue, - long latencyLowerNs, long latencyUpperNs, int maxSpansToReturn, List output) { + private static void getSamplesFilteredByLatency( + EvictingQueue queue, + long latencyLowerNs, + long latencyUpperNs, + int maxSpansToReturn, + List output) { for (SpanImpl span : queue) { if (output.size() >= maxSpansToReturn) { break; @@ -225,7 +229,7 @@ public final class SampledSpanStoreImpl extends SampledSpanStore { } /** Constructs a new {@code SampledSpanStoreImpl}. */ - public SampledSpanStoreImpl() { + SampledSpanStoreImpl() { samples = new HashMap(); } @@ -252,7 +256,11 @@ public final class SampledSpanStoreImpl extends SampledSpanStore { */ public void considerForSampling(SpanImpl span) { synchronized (samples) { - PerSpanNameSamples perSpanNameSamples = samples.get(span.getName()); + String spanName = span.getName(); + if (span.getSampleToLocalSpanStore() && !samples.containsKey(spanName)) { + samples.put(spanName, new PerSpanNameSamples()); + } + PerSpanNameSamples perSpanNameSamples = samples.get(spanName); if (perSpanNameSamples != null) { perSpanNameSamples.considerForSampling(span); } -- cgit v1.2.3 From 89f06e756efed61b9307f51af760d6a4b291572a Mon Sep 17 00:00:00 2001 From: Bogdan Drutu Date: Wed, 25 Oct 2017 15:25:33 -0700 Subject: Remove contention between threads and worker thread when register span names. (#729) * Remove contention between threads and worker thread when register span names. * Mark getRegisteredSpanNamesForCollection as test only. --- .../implcore/trace/TraceComponentImplBase.java | 7 ++-- .../implcore/trace/export/ExportComponentImpl.java | 13 +++--- .../trace/export/SampledSpanStoreImpl.java | 48 +++++++++++++++++++++- 3 files changed, 57 insertions(+), 11 deletions(-) (limited to 'impl_core/src/main/java/io/opencensus/implcore/trace') diff --git a/impl_core/src/main/java/io/opencensus/implcore/trace/TraceComponentImplBase.java b/impl_core/src/main/java/io/opencensus/implcore/trace/TraceComponentImplBase.java index f5f70a52..f4c5ef76 100644 --- a/impl_core/src/main/java/io/opencensus/implcore/trace/TraceComponentImplBase.java +++ b/impl_core/src/main/java/io/opencensus/implcore/trace/TraceComponentImplBase.java @@ -41,7 +41,6 @@ public final class TraceComponentImplBase { private final ExportComponentImpl exportComponent; private final PropagationComponent propagationComponent = new PropagationComponentImpl(); private final Clock clock; - private final StartEndHandler startEndHandler; private final TraceConfig traceConfig = new TraceConfigImpl(); private final Tracer tracer; @@ -56,11 +55,11 @@ public final class TraceComponentImplBase { this.clock = clock; // TODO(bdrutu): Add a config/argument for supportInProcessStores. if (eventQueue instanceof SimpleEventQueue) { - exportComponent = ExportComponentImpl.createWithoutInProcessStores(); + exportComponent = ExportComponentImpl.createWithoutInProcessStores(eventQueue); } else { - exportComponent = ExportComponentImpl.createWithInProcessStores(); + exportComponent = ExportComponentImpl.createWithInProcessStores(eventQueue); } - startEndHandler = + StartEndHandler startEndHandler = new StartEndHandlerImpl( exportComponent.getSpanExporter(), exportComponent.getRunningSpanStore(), diff --git a/impl_core/src/main/java/io/opencensus/implcore/trace/export/ExportComponentImpl.java b/impl_core/src/main/java/io/opencensus/implcore/trace/export/ExportComponentImpl.java index 7d9b1895..c30f6b3c 100644 --- a/impl_core/src/main/java/io/opencensus/implcore/trace/export/ExportComponentImpl.java +++ b/impl_core/src/main/java/io/opencensus/implcore/trace/export/ExportComponentImpl.java @@ -16,6 +16,7 @@ package io.opencensus.implcore.trace.export; +import io.opencensus.implcore.internal.EventQueue; import io.opencensus.trace.export.ExportComponent; import io.opencensus.trace.export.RunningSpanStore; import io.opencensus.trace.export.SampledSpanStore; @@ -54,8 +55,8 @@ public final class ExportComponentImpl extends ExportComponent { * * @return a new {@code ExportComponentImpl}. */ - public static ExportComponentImpl createWithInProcessStores() { - return new ExportComponentImpl(true); + public static ExportComponentImpl createWithInProcessStores(EventQueue eventQueue) { + return new ExportComponentImpl(true, eventQueue); } /** @@ -64,8 +65,8 @@ public final class ExportComponentImpl extends ExportComponent { * * @return a new {@code ExportComponentImpl}. */ - public static ExportComponentImpl createWithoutInProcessStores() { - return new ExportComponentImpl(false); + public static ExportComponentImpl createWithoutInProcessStores(EventQueue eventQueue) { + return new ExportComponentImpl(false, eventQueue); } /** @@ -74,9 +75,9 @@ public final class ExportComponentImpl extends ExportComponent { * @param supportInProcessStores {@code true} to instantiate {@link RunningSpanStore} and {@link * SampledSpanStore}. */ - private ExportComponentImpl(boolean supportInProcessStores) { + private ExportComponentImpl(boolean supportInProcessStores, EventQueue eventQueue) { this.spanExporter = SpanExporterImpl.create(EXPORTER_BUFFER_SIZE, EXPORTER_SCHEDULE_DELAY_MS); this.runningSpanStore = supportInProcessStores ? new RunningSpanStoreImpl() : null; - this.sampledSpanStore = supportInProcessStores ? new SampledSpanStoreImpl() : null; + this.sampledSpanStore = supportInProcessStores ? new SampledSpanStoreImpl(eventQueue) : null; } } diff --git a/impl_core/src/main/java/io/opencensus/implcore/trace/export/SampledSpanStoreImpl.java b/impl_core/src/main/java/io/opencensus/implcore/trace/export/SampledSpanStoreImpl.java index 126d4634..9235d4f1 100644 --- a/impl_core/src/main/java/io/opencensus/implcore/trace/export/SampledSpanStoreImpl.java +++ b/impl_core/src/main/java/io/opencensus/implcore/trace/export/SampledSpanStoreImpl.java @@ -17,6 +17,7 @@ package io.opencensus.implcore.trace.export; import com.google.common.collect.EvictingQueue; +import io.opencensus.implcore.internal.EventQueue; import io.opencensus.implcore.trace.SpanImpl; import io.opencensus.trace.Status; import io.opencensus.trace.Status.CanonicalCode; @@ -48,6 +49,10 @@ public final class SampledSpanStoreImpl extends SampledSpanStore { NUM_SAMPLES_PER_LATENCY_BUCKET * NUM_LATENCY_BUCKETS + NUM_SAMPLES_PER_ERROR_BUCKET * NUM_ERROR_BUCKETS; + // Used to stream the register/unregister events to the implementation to avoid lock contention + // between the main threads and the worker thread. + private final EventQueue eventQueue; + @GuardedBy("samples") private final Map samples; @@ -229,8 +234,9 @@ public final class SampledSpanStoreImpl extends SampledSpanStore { } /** Constructs a new {@code SampledSpanStoreImpl}. */ - SampledSpanStoreImpl() { + SampledSpanStoreImpl(EventQueue eventQueue) { samples = new HashMap(); + this.eventQueue = eventQueue; } @Override @@ -269,6 +275,10 @@ public final class SampledSpanStoreImpl extends SampledSpanStore { @Override public void registerSpanNamesForCollection(Collection spanNames) { + eventQueue.enqueue(new RegisterSpanNameEvent(this, spanNames)); + } + + private void internaltRegisterSpanNamesForCollection(Collection spanNames) { synchronized (samples) { for (String spanName : spanNames) { if (!samples.containsKey(spanName)) { @@ -278,13 +288,49 @@ public final class SampledSpanStoreImpl extends SampledSpanStore { } } + private static final class RegisterSpanNameEvent implements EventQueue.Entry { + private final SampledSpanStoreImpl sampledSpanStore; + private final Collection spanNames; + + private RegisterSpanNameEvent( + SampledSpanStoreImpl sampledSpanStore, Collection spanNames) { + this.sampledSpanStore = sampledSpanStore; + this.spanNames = new ArrayList(spanNames); + } + + @Override + public void process() { + sampledSpanStore.internaltRegisterSpanNamesForCollection(spanNames); + } + } + @Override public void unregisterSpanNamesForCollection(Collection spanNames) { + eventQueue.enqueue(new UnregisterSpanNameEvent(this, spanNames)); + } + + private void internalUnregisterSpanNamesForCollection(Collection spanNames) { synchronized (samples) { samples.keySet().removeAll(spanNames); } } + private static final class UnregisterSpanNameEvent implements EventQueue.Entry { + private final SampledSpanStoreImpl sampledSpanStore; + private final Collection spanNames; + + private UnregisterSpanNameEvent( + SampledSpanStoreImpl sampledSpanStore, Collection spanNames) { + this.sampledSpanStore = sampledSpanStore; + this.spanNames = new ArrayList(spanNames); + } + + @Override + public void process() { + sampledSpanStore.internalUnregisterSpanNamesForCollection(spanNames); + } + } + @Override public Set getRegisteredSpanNamesForCollection() { synchronized (samples) { -- cgit v1.2.3 From 4833413b2a0e4fa6e4d4b7279f0b28e7e3479a56 Mon Sep 17 00:00:00 2001 From: Bogdan Drutu Date: Tue, 7 Nov 2017 15:32:38 +1100 Subject: Add a setStatus method in the Span. (#779) * Add a setStatus method in the Span. * Update after feedback. * Run ./gradlew goJF * Update comment in EndSpanOptions. --- .../io/opencensus/implcore/trace/SpanImpl.java | 27 +++++++++++++++++++--- 1 file changed, 24 insertions(+), 3 deletions(-) (limited to 'impl_core/src/main/java/io/opencensus/implcore/trace') diff --git a/impl_core/src/main/java/io/opencensus/implcore/trace/SpanImpl.java b/impl_core/src/main/java/io/opencensus/implcore/trace/SpanImpl.java index fefaf486..11d81747 100644 --- a/impl_core/src/main/java/io/opencensus/implcore/trace/SpanImpl.java +++ b/impl_core/src/main/java/io/opencensus/implcore/trace/SpanImpl.java @@ -165,7 +165,7 @@ public final class SpanImpl extends Span implements Element { */ public Status getStatus() { synchronized (this) { - return status; + return getStatusWithDefault(); } } @@ -250,7 +250,7 @@ public final class SpanImpl extends Span implements Element { networkEventsSpanData, linksSpanData, null, // Not supported yet. - hasBeenEnded ? status : null, + hasBeenEnded ? getStatusWithDefault() : null, hasBeenEnded ? timestampConverter.convertNanoTime(endNanoTime) : null); } } @@ -349,6 +349,20 @@ public final class SpanImpl extends Span implements Element { } } + @Override + public void setStatus(Status status) { + if (!getOptions().contains(Options.RECORD_EVENTS)) { + return; + } + synchronized (this) { + if (hasBeenEnded) { + logger.log(Level.FINE, "Calling setStatus() on an ended Span."); + return; + } + this.status = status; + } + } + @Override public void end(EndSpanOptions options) { if (!getOptions().contains(Options.RECORD_EVENTS)) { @@ -359,7 +373,9 @@ public final class SpanImpl extends Span implements Element { logger.log(Level.FINE, "Calling end() on an ended Span."); return; } - status = options.getStatus(); + if (options.getStatus() != null) { + status = options.getStatus(); + } sampleToLocalSpanStore = options.getSampleToLocalSpanStore(); endNanoTime = clock.nowNanos(); hasBeenEnded = true; @@ -402,6 +418,11 @@ public final class SpanImpl extends Span implements Element { return links; } + @GuardedBy("this") + private Status getStatusWithDefault() { + return status == null ? Status.OK : status; + } + private static SpanData.TimedEvents createTimedEvents( TraceEvents> events, TimestampConverter timestampConverter) { if (events == null) { -- cgit v1.2.3 From ba78379bcf98d4a5a1ee7a3230b5a25f27356edf Mon Sep 17 00:00:00 2001 From: Kristen Kozak Date: Fri, 10 Nov 2017 18:28:44 -0800 Subject: com.google.errorprone:error_prone_core: 2.0.19 -> 2.1.2 Other changes: - Remove references to warnings that were removed from Error Prone. - Suppress occurrences of a new warning, JdkObsolete. All of the warnings are about uses of LinkedList. We need to decide whether to use a different class or continue suppressing the warnings. I left TODOs, since each occurrence may need to be handled differently. --- .../main/java/io/opencensus/implcore/trace/export/SpanExporterImpl.java | 2 ++ 1 file changed, 2 insertions(+) (limited to 'impl_core/src/main/java/io/opencensus/implcore/trace') diff --git a/impl_core/src/main/java/io/opencensus/implcore/trace/export/SpanExporterImpl.java b/impl_core/src/main/java/io/opencensus/implcore/trace/export/SpanExporterImpl.java index c7664ecc..13eee9da 100644 --- a/impl_core/src/main/java/io/opencensus/implcore/trace/export/SpanExporterImpl.java +++ b/impl_core/src/main/java/io/opencensus/implcore/trace/export/SpanExporterImpl.java @@ -138,6 +138,8 @@ public final class SpanExporterImpl extends SpanExporter { } } + // TODO: Decide whether to use a different class instead of LinkedList. + @SuppressWarnings("JdkObsolete") private WorkerThread(int bufferSize, long scheduleDelayMillis) { spans = new LinkedList(); this.bufferSize = bufferSize; -- cgit v1.2.3 From c39d244ca356ee2bbbb9a2eaf7323d3d468dbee7 Mon Sep 17 00:00:00 2001 From: Kristen Kozak Date: Mon, 13 Nov 2017 19:01:47 -0800 Subject: Enable new ReturnMissingNullable Error Prone experimental suggestion. I also added some missing Nullable annotations. --- .../java/io/opencensus/implcore/trace/export/SampledSpanStoreImpl.java | 2 ++ 1 file changed, 2 insertions(+) (limited to 'impl_core/src/main/java/io/opencensus/implcore/trace') diff --git a/impl_core/src/main/java/io/opencensus/implcore/trace/export/SampledSpanStoreImpl.java b/impl_core/src/main/java/io/opencensus/implcore/trace/export/SampledSpanStoreImpl.java index 9235d4f1..e0f9b832 100644 --- a/impl_core/src/main/java/io/opencensus/implcore/trace/export/SampledSpanStoreImpl.java +++ b/impl_core/src/main/java/io/opencensus/implcore/trace/export/SampledSpanStoreImpl.java @@ -33,6 +33,7 @@ import java.util.List; import java.util.Map; import java.util.Set; import java.util.concurrent.TimeUnit; +import javax.annotation.Nullable; import javax.annotation.concurrent.GuardedBy; import javax.annotation.concurrent.ThreadSafe; @@ -154,6 +155,7 @@ public final class SampledSpanStoreImpl extends SampledSpanStore { } } + @Nullable private Bucket getLatencyBucket(long latencyNs) { for (int i = 0; i < NUM_LATENCY_BUCKETS; i++) { LatencyBucketBoundaries boundaries = LatencyBucketBoundaries.values()[i]; -- cgit v1.2.3 From d80e6de38c6959aac5736634ca3950101b3392bd Mon Sep 17 00:00:00 2001 From: Kristen Kozak Date: Mon, 13 Nov 2017 19:03:58 -0800 Subject: Enable new InconsistentOverloads Error Prone experimental warning. This commit also fixes two occurrences. --- .../implcore/trace/export/SampledSpanStoreImpl.java | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) (limited to 'impl_core/src/main/java/io/opencensus/implcore/trace') diff --git a/impl_core/src/main/java/io/opencensus/implcore/trace/export/SampledSpanStoreImpl.java b/impl_core/src/main/java/io/opencensus/implcore/trace/export/SampledSpanStoreImpl.java index e0f9b832..60b1433c 100644 --- a/impl_core/src/main/java/io/opencensus/implcore/trace/export/SampledSpanStoreImpl.java +++ b/impl_core/src/main/java/io/opencensus/implcore/trace/export/SampledSpanStoreImpl.java @@ -91,12 +91,12 @@ public final class SampledSpanStoreImpl extends SampledSpanStore { } private void getSamples(int maxSpansToReturn, List output) { - getSamples(sampledSpansQueue, maxSpansToReturn, output); - getSamples(notSampledSpansQueue, maxSpansToReturn, output); + getSamples(maxSpansToReturn, output, sampledSpansQueue); + getSamples(maxSpansToReturn, output, notSampledSpansQueue); } private static void getSamples( - EvictingQueue queue, int maxSpansToReturn, List output) { + int maxSpansToReturn, List output, EvictingQueue queue) { for (SpanImpl span : queue) { if (output.size() >= maxSpansToReturn) { break; @@ -108,17 +108,17 @@ public final class SampledSpanStoreImpl extends SampledSpanStore { private void getSamplesFilteredByLatency( long latencyLowerNs, long latencyUpperNs, int maxSpansToReturn, List output) { getSamplesFilteredByLatency( - sampledSpansQueue, latencyLowerNs, latencyUpperNs, maxSpansToReturn, output); + latencyLowerNs, latencyUpperNs, maxSpansToReturn, output, sampledSpansQueue); getSamplesFilteredByLatency( - notSampledSpansQueue, latencyLowerNs, latencyUpperNs, maxSpansToReturn, output); + latencyLowerNs, latencyUpperNs, maxSpansToReturn, output, notSampledSpansQueue); } private static void getSamplesFilteredByLatency( - EvictingQueue queue, long latencyLowerNs, long latencyUpperNs, int maxSpansToReturn, - List output) { + List output, + EvictingQueue queue) { for (SpanImpl span : queue) { if (output.size() >= maxSpansToReturn) { break; -- cgit v1.2.3 From 82f7125d9396314d045b3de9c26ba6b894f3ece0 Mon Sep 17 00:00:00 2001 From: Hailong Wen Date: Fri, 1 Dec 2017 17:34:25 -0800 Subject: Use AppEngine compatible way to create threads. (fixes #707 and #777) --- .../implcore/trace/export/SpanExporterImpl.java | 30 ++++++++++++---------- 1 file changed, 16 insertions(+), 14 deletions(-) (limited to 'impl_core/src/main/java/io/opencensus/implcore/trace') diff --git a/impl_core/src/main/java/io/opencensus/implcore/trace/export/SpanExporterImpl.java b/impl_core/src/main/java/io/opencensus/implcore/trace/export/SpanExporterImpl.java index 13eee9da..e3bc08b4 100644 --- a/impl_core/src/main/java/io/opencensus/implcore/trace/export/SpanExporterImpl.java +++ b/impl_core/src/main/java/io/opencensus/implcore/trace/export/SpanExporterImpl.java @@ -17,6 +17,7 @@ package io.opencensus.implcore.trace.export; import com.google.common.annotations.VisibleForTesting; +import io.opencensus.implcore.internal.DaemonThreadFactory; import io.opencensus.implcore.trace.SpanImpl; import io.opencensus.trace.export.ExportComponent; import io.opencensus.trace.export.SpanData; @@ -35,7 +36,8 @@ import javax.annotation.concurrent.GuardedBy; public final class SpanExporterImpl extends SpanExporter { private static final Logger logger = Logger.getLogger(ExportComponent.class.getName()); - private final WorkerThread workerThread; + private final Worker worker; + private final Thread workerThread; /** * Constructs a {@code SpanExporterImpl} that exports the {@link SpanData} asynchronously. @@ -49,9 +51,8 @@ public final class SpanExporterImpl extends SpanExporter { */ static SpanExporterImpl create(int bufferSize, long scheduleDelayMillis) { // TODO(bdrutu): Consider to add a shutdown hook to not avoid dropping data. - WorkerThread workerThread = new WorkerThread(bufferSize, scheduleDelayMillis); - workerThread.start(); - return new SpanExporterImpl(workerThread); + Worker worker = new Worker(bufferSize, scheduleDelayMillis); + return new SpanExporterImpl(worker); } /** @@ -60,21 +61,24 @@ public final class SpanExporterImpl extends SpanExporter { * @param span the {@code Span} to be added. */ public void addSpan(SpanImpl span) { - workerThread.addSpan(span); + worker.addSpan(span); } @Override public void registerHandler(String name, Handler handler) { - workerThread.registerHandler(name, handler); + worker.registerHandler(name, handler); } @Override public void unregisterHandler(String name) { - workerThread.unregisterHandler(name); + worker.unregisterHandler(name); } - private SpanExporterImpl(WorkerThread workerThread) { - this.workerThread = workerThread; + private SpanExporterImpl(Worker worker) { + this.workerThread = + new DaemonThreadFactory("ExportComponent.ServiceExporterThread").newThread(worker); + this.workerThread.start(); + this.worker = worker; } @VisibleForTesting @@ -82,7 +86,7 @@ public final class SpanExporterImpl extends SpanExporter { return workerThread; } - // Worker thread that batches multiple span data and calls the registered services to export + // Worker in a thread that batches multiple span data and calls the registered services to export // that data. // // The map of registered handlers is implemented using ConcurrentHashMap ensuring full @@ -91,7 +95,7 @@ public final class SpanExporterImpl extends SpanExporter { // // The list of batched data is protected by an explicit monitor object which ensures full // concurrency. - private static final class WorkerThread extends Thread { + private static final class Worker implements Runnable { private final Object monitor = new Object(); @GuardedBy("monitor") @@ -140,12 +144,10 @@ public final class SpanExporterImpl extends SpanExporter { // TODO: Decide whether to use a different class instead of LinkedList. @SuppressWarnings("JdkObsolete") - private WorkerThread(int bufferSize, long scheduleDelayMillis) { + private Worker(int bufferSize, long scheduleDelayMillis) { spans = new LinkedList(); this.bufferSize = bufferSize; this.scheduleDelayMillis = scheduleDelayMillis; - setDaemon(true); - setName("ExportComponent.ServiceExporterThread"); } // Returns an unmodifiable list of all buffered spans data to ensure that any registered -- cgit v1.2.3 From 381e11c5168e5d31e09ec92840f908b42be647e6 Mon Sep 17 00:00:00 2001 From: Bogdan Drutu Date: Mon, 11 Dec 2017 16:12:53 -0800 Subject: Add initial support for b3-propagation headers. (#889) * Add initial support for b3-propagation headers. * Update tests and throw exception when missing span_id or trace_id. * Cleanup and add more tests. * Update comments. Update tests. --- .../implcore/trace/propagation/B3Format.java | 105 +++++++++++++++++++++ .../trace/propagation/BinaryFormatImpl.java | 2 +- 2 files changed, 106 insertions(+), 1 deletion(-) create mode 100644 impl_core/src/main/java/io/opencensus/implcore/trace/propagation/B3Format.java (limited to 'impl_core/src/main/java/io/opencensus/implcore/trace') diff --git a/impl_core/src/main/java/io/opencensus/implcore/trace/propagation/B3Format.java b/impl_core/src/main/java/io/opencensus/implcore/trace/propagation/B3Format.java new file mode 100644 index 00000000..c27234db --- /dev/null +++ b/impl_core/src/main/java/io/opencensus/implcore/trace/propagation/B3Format.java @@ -0,0 +1,105 @@ +/* + * 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.propagation; + +import static com.google.common.base.Preconditions.checkNotNull; + +import com.google.common.annotations.VisibleForTesting; +import io.opencensus.trace.SpanContext; +import io.opencensus.trace.SpanId; +import io.opencensus.trace.TraceId; +import io.opencensus.trace.TraceOptions; +import io.opencensus.trace.propagation.SpanContextParseException; +import io.opencensus.trace.propagation.TextFormat; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; + +/** + * Implementation of the B3 propagation protocol. See b3-propagation. + */ +final class B3Format extends TextFormat { + @VisibleForTesting static final String X_B3_TRACE_ID = "X─B3─TraceId"; + @VisibleForTesting static final String X_B3_SPAN_ID = "X─B3─SpanId"; + @VisibleForTesting static final String X_B3_PARENT_SPAN_ID = "X─B3─ParentSpanId"; + @VisibleForTesting static final String X_B3_SAMPLED = "X─B3─Sampled"; + @VisibleForTesting static final String X_B3_FLAGS = "X-B3-Flags"; + private static final List FIELDS = + Collections.unmodifiableList( + Arrays.asList( + X_B3_TRACE_ID, X_B3_SPAN_ID, X_B3_PARENT_SPAN_ID, X_B3_SAMPLED, X_B3_FLAGS)); + + // Used as the upper TraceId.SIZE hex characters of the traceID. B3-propagation used to send + // TraceId.SIZE hex characters (8-bytes traceId) in the past. + private static final String UPPER_TRACE_ID = "0000000000000000"; + // Sampled value via the X_B3_SAMPLED header. + private static final String SAMPLED_VALUE = "1"; + // "Debug" sampled value. + private static final String FLAGS_VALUE = "1"; + + @Override + public List fields() { + return FIELDS; + } + + @Override + public void inject(SpanContext spanContext, C carrier, Setter setter) { + checkNotNull(spanContext, "spanContext"); + checkNotNull(setter, "setter"); + checkNotNull(carrier, "carrier"); + setter.put(carrier, X_B3_TRACE_ID, spanContext.getTraceId().toLowerBase16()); + setter.put(carrier, X_B3_SPAN_ID, spanContext.getSpanId().toLowerBase16()); + if (spanContext.getTraceOptions().isSampled()) { + setter.put(carrier, X_B3_SAMPLED, SAMPLED_VALUE); + } + } + + @Override + public SpanContext extract(C carrier, Getter getter) throws SpanContextParseException { + checkNotNull(carrier, "carrier"); + checkNotNull(getter, "getter"); + try { + TraceId traceId; + String traceIdStr = getter.get(carrier, X_B3_TRACE_ID); + if (traceIdStr != null) { + if (traceIdStr.length() == TraceId.SIZE) { + // This is an 8-byte traceID. + traceIdStr = UPPER_TRACE_ID + traceIdStr; + } + traceId = TraceId.fromLowerBase16(traceIdStr); + } else { + throw new SpanContextParseException("Missing X_B3_TRACE_ID."); + } + SpanId spanId; + String spanIdStr = getter.get(carrier, X_B3_SPAN_ID); + if (spanIdStr != null) { + spanId = SpanId.fromLowerBase16(spanIdStr); + } else { + throw new SpanContextParseException("Missing X_B3_SPAN_ID."); + } + TraceOptions traceOptions = TraceOptions.DEFAULT; + if (SAMPLED_VALUE.equals(getter.get(carrier, X_B3_SAMPLED)) + || FLAGS_VALUE.equals(getter.get(carrier, X_B3_FLAGS))) { + traceOptions = TraceOptions.builder().setIsSampled(true).build(); + } + return SpanContext.create(traceId, spanId, traceOptions); + } catch (IllegalArgumentException e) { + throw new SpanContextParseException("Invalid input.", e); + } + } +} diff --git a/impl_core/src/main/java/io/opencensus/implcore/trace/propagation/BinaryFormatImpl.java b/impl_core/src/main/java/io/opencensus/implcore/trace/propagation/BinaryFormatImpl.java index 6075c80b..8a4377d3 100644 --- a/impl_core/src/main/java/io/opencensus/implcore/trace/propagation/BinaryFormatImpl.java +++ b/impl_core/src/main/java/io/opencensus/implcore/trace/propagation/BinaryFormatImpl.java @@ -59,7 +59,7 @@ import io.opencensus.trace.propagation.SpanContextParseException; * * */ -public final class BinaryFormatImpl extends BinaryFormat { +final class BinaryFormatImpl extends BinaryFormat { private static final byte VERSION_ID = 0; private static final int VERSION_ID_OFFSET = 0; // The version_id/field_id size in bytes. -- cgit v1.2.3 From 65398bb0c56beccc0b3058b5b1137aabcbe76cd5 Mon Sep 17 00:00:00 2001 From: Bogdan Drutu Date: Wed, 13 Dec 2017 23:25:04 -0800 Subject: Add methods to wrap Runnable and Callbacks and to run them. (#778) * Add methods to wrap Runnable and Callbacks and to run them. * Fix more comments. * Fix use of Assert.fail(). * Improve javadocs for the start and wrap methods. * Remove startSpanAndWrap API for the moment. * Change wrap to withSpan. * Fix examples in SpanBuilders. --- .../implcore/trace/internal/ConcurrentIntrusiveList.java | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) (limited to 'impl_core/src/main/java/io/opencensus/implcore/trace') diff --git a/impl_core/src/main/java/io/opencensus/implcore/trace/internal/ConcurrentIntrusiveList.java b/impl_core/src/main/java/io/opencensus/implcore/trace/internal/ConcurrentIntrusiveList.java index 95906012..ef0b2664 100644 --- a/impl_core/src/main/java/io/opencensus/implcore/trace/internal/ConcurrentIntrusiveList.java +++ b/impl_core/src/main/java/io/opencensus/implcore/trace/internal/ConcurrentIntrusiveList.java @@ -30,32 +30,32 @@ import javax.annotation.concurrent.ThreadSafe; * *

Elements must derive from the {@code Element>} interface: * - *

{@code
- * class MyClass implements Element {
+ * 

+ * class MyClass implements {@code Element} {
  *   private MyClass next = null;
  *   private MyClass prev = null;
  *
- *   {@literal @}Override
+ *  {@literal @}Override
  *   MyClass getNext() {
  *     return next;
  *   }
  *
- *   {@literal @}Override
+ *  {@literal @}Override
  *   void setNext(MyClass element) {
  *     next = element;
  *   }
  *
- *   {@literal @}Override
+ *  {@literal @}Override
  *   MyClass getPrev() {
  *     return prev;
  *   }
  *
- *   {@literal @}Override
+ *  {@literal @}Override
  *   void setPrev(MyClass element) {
  *     prev = element;
  *   }
  * }
- * }
+ *
*/ @ThreadSafe public final class ConcurrentIntrusiveList> { -- cgit v1.2.3 From fc4671b21df0cebd1500f86a25781b31eb3db8d2 Mon Sep 17 00:00:00 2001 From: Hailong Wen Date: Thu, 14 Dec 2017 14:29:42 -0800 Subject: Add initial support fox X-Cloud-Trace-Context. (#900) --- .../trace/propagation/CloudTraceFormat.java | 141 +++++++++++++++++++++ 1 file changed, 141 insertions(+) create mode 100644 impl_core/src/main/java/io/opencensus/implcore/trace/propagation/CloudTraceFormat.java (limited to 'impl_core/src/main/java/io/opencensus/implcore/trace') diff --git a/impl_core/src/main/java/io/opencensus/implcore/trace/propagation/CloudTraceFormat.java b/impl_core/src/main/java/io/opencensus/implcore/trace/propagation/CloudTraceFormat.java new file mode 100644 index 00000000..ba4cc86a --- /dev/null +++ b/impl_core/src/main/java/io/opencensus/implcore/trace/propagation/CloudTraceFormat.java @@ -0,0 +1,141 @@ +/* + * 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.propagation; + +import static com.google.common.base.Preconditions.checkArgument; +import static com.google.common.base.Preconditions.checkNotNull; + +import com.google.common.primitives.UnsignedInts; +import com.google.common.primitives.UnsignedLongs; +import io.opencensus.trace.SpanContext; +import io.opencensus.trace.SpanId; +import io.opencensus.trace.TraceId; +import io.opencensus.trace.TraceOptions; +import io.opencensus.trace.propagation.SpanContextParseException; +import io.opencensus.trace.propagation.TextFormat; +import java.nio.ByteBuffer; +import java.util.Collections; +import java.util.List; + +/** + * Implementation of the "X-Cloud-Trace-Context" format, defined by the Google Cloud Trace. + * + *

The supported format is the following: + * + *

+ * <TRACE_ID>/<SPAN_ID>[;o=<TRACE_OPTIONS>]
+ * 
+ * + *
    + *
  • TRACE_ID is a 32-character hex value; + *
  • SPAN_ID is a decimal representation of a 64-bit unsigned long; + *
  • TRACE_OPTIONS is a decimal representation of a 32-bit unsigned integer. The least + * significant bit defines whether a request is traced (1 - enabled, 0 - disabled). Behaviors + * of other bits are currently undefined. This value is optional. Although upstream service + * may leave this value unset to leave the sampling decision up to downstream client, this + * utility will always default it to 0 if absent. + *
+ * + *

Valid values: + * + *

    + *
  • "105445aa7843bc8bf206b120001000/123;o=1" + *
  • "105445aa7843bc8bf206b120001000/123" + *
  • "105445aa7843bc8bf206b120001000/123;o=0" + *
+ */ +final class CloudTraceFormat extends TextFormat { + static final String HEADER_NAME = "X-Cloud-Trace-Context"; + static final List FIELDS = Collections.singletonList(HEADER_NAME); + static final char SPAN_ID_DELIMITER = '/'; + static final String TRACE_OPTION_DELIMITER = ";o="; + static final String SAMPLED = "1"; + static final String NOT_SAMPLED = "0"; + static final TraceOptions OPTIONS_SAMPLED = TraceOptions.builder().setIsSampled(true).build(); + static final TraceOptions OPTIONS_NOT_SAMPLED = TraceOptions.DEFAULT; + static final int TRACE_ID_SIZE = 2 * TraceId.SIZE; + static final int TRACE_OPTION_DELIMITER_SIZE = TRACE_OPTION_DELIMITER.length(); + static final int SPAN_ID_START_POS = TRACE_ID_SIZE + 1; + // 32-digit TRACE_ID + 1 digit SPAN_ID_DELIMITER + at least 1 digit SPAN_ID + static final int MIN_HEADER_SIZE = SPAN_ID_START_POS + 1; + static final int CLOUD_TRACE_IS_SAMPLED = 0x1; + + @Override + public List fields() { + return FIELDS; + } + + @Override + public void inject(SpanContext spanContext, C carrier, Setter setter) { + checkNotNull(spanContext, "spanContext"); + checkNotNull(setter, "setter"); + checkNotNull(carrier, "carrier"); + StringBuilder builder = + new StringBuilder() + .append(spanContext.getTraceId().toLowerBase16()) + .append(SPAN_ID_DELIMITER) + .append(UnsignedLongs.toString(spanIdToLong(spanContext.getSpanId()))) + .append(TRACE_OPTION_DELIMITER) + .append(spanContext.getTraceOptions().isSampled() ? SAMPLED : NOT_SAMPLED); + + setter.put(carrier, HEADER_NAME, builder.toString()); + } + + @Override + public SpanContext extract(C carrier, Getter getter) throws SpanContextParseException { + checkNotNull(carrier, "carrier"); + checkNotNull(getter, "getter"); + try { + String headerStr = getter.get(carrier, HEADER_NAME); + if (headerStr == null || headerStr.length() < MIN_HEADER_SIZE) { + throw new SpanContextParseException("Missing or too short header: " + HEADER_NAME); + } + checkArgument(headerStr.charAt(TRACE_ID_SIZE) == SPAN_ID_DELIMITER, "Invalid TRACE_ID size"); + + TraceId traceId = TraceId.fromLowerBase16(headerStr.subSequence(0, TRACE_ID_SIZE)); + int traceOptionsPos = headerStr.indexOf(TRACE_OPTION_DELIMITER, SPAN_ID_DELIMITER); + CharSequence spanIdStr = + headerStr.subSequence( + SPAN_ID_START_POS, traceOptionsPos < 0 ? headerStr.length() : traceOptionsPos); + SpanId spanId = longToSpanId(UnsignedLongs.parseUnsignedLong(spanIdStr.toString(), 10)); + TraceOptions traceOptions = OPTIONS_NOT_SAMPLED; + if (traceOptionsPos > 0) { + String traceOptionsStr = headerStr.substring(traceOptionsPos + TRACE_OPTION_DELIMITER_SIZE); + if ((UnsignedInts.parseUnsignedInt(traceOptionsStr, 10) & CLOUD_TRACE_IS_SAMPLED) != 0) { + traceOptions = OPTIONS_SAMPLED; + } + } + return SpanContext.create(traceId, spanId, traceOptions); + } catch (IllegalArgumentException e) { + throw new SpanContextParseException("Invalid input", e); + } + } + + // Using big-endian encoding. + private static SpanId longToSpanId(long x) { + ByteBuffer buffer = ByteBuffer.allocate(SpanId.SIZE); + buffer.putLong(x); + return SpanId.fromBytes(buffer.array()); + } + + // Using big-endian encoding. + private static long spanIdToLong(SpanId spanId) { + ByteBuffer buffer = ByteBuffer.allocate(SpanId.SIZE); + buffer.put(spanId.getBytes()); + return buffer.getLong(0); + } +} -- cgit v1.2.3 From 082559ce52e665571c1c0f2557696c63291fb0c0 Mon Sep 17 00:00:00 2001 From: Bogdan Drutu Date: Thu, 14 Dec 2017 15:12:13 -0800 Subject: Increase exporting interval and fix warnings. (#905) --- .../implcore/trace/export/ExportComponentImpl.java | 7 ++++--- .../implcore/trace/export/SpanExporterImpl.java | 19 ++++++++++--------- 2 files changed, 14 insertions(+), 12 deletions(-) (limited to 'impl_core/src/main/java/io/opencensus/implcore/trace') diff --git a/impl_core/src/main/java/io/opencensus/implcore/trace/export/ExportComponentImpl.java b/impl_core/src/main/java/io/opencensus/implcore/trace/export/ExportComponentImpl.java index c30f6b3c..26c9004a 100644 --- a/impl_core/src/main/java/io/opencensus/implcore/trace/export/ExportComponentImpl.java +++ b/impl_core/src/main/java/io/opencensus/implcore/trace/export/ExportComponentImpl.java @@ -16,6 +16,7 @@ package io.opencensus.implcore.trace.export; +import io.opencensus.common.Duration; import io.opencensus.implcore.internal.EventQueue; import io.opencensus.trace.export.ExportComponent; import io.opencensus.trace.export.RunningSpanStore; @@ -25,8 +26,8 @@ import javax.annotation.Nullable; /** Implementation of the {@link ExportComponent}. */ public final class ExportComponentImpl extends ExportComponent { private static final int EXPORTER_BUFFER_SIZE = 32; - // Enforces that trace export exports data at least once every 2 seconds. - private static final long EXPORTER_SCHEDULE_DELAY_MS = 2000; + // Enforces that trace export exports data at least once every 5 seconds. + private static final Duration EXPORTER_SCHEDULE_DELAY = Duration.create(5, 0); private final SpanExporterImpl spanExporter; private final RunningSpanStoreImpl runningSpanStore; @@ -76,7 +77,7 @@ public final class ExportComponentImpl extends ExportComponent { * SampledSpanStore}. */ private ExportComponentImpl(boolean supportInProcessStores, EventQueue eventQueue) { - this.spanExporter = SpanExporterImpl.create(EXPORTER_BUFFER_SIZE, EXPORTER_SCHEDULE_DELAY_MS); + this.spanExporter = SpanExporterImpl.create(EXPORTER_BUFFER_SIZE, EXPORTER_SCHEDULE_DELAY); this.runningSpanStore = supportInProcessStores ? new RunningSpanStoreImpl() : null; this.sampledSpanStore = supportInProcessStores ? new SampledSpanStoreImpl(eventQueue) : null; } diff --git a/impl_core/src/main/java/io/opencensus/implcore/trace/export/SpanExporterImpl.java b/impl_core/src/main/java/io/opencensus/implcore/trace/export/SpanExporterImpl.java index e3bc08b4..e5973c0b 100644 --- a/impl_core/src/main/java/io/opencensus/implcore/trace/export/SpanExporterImpl.java +++ b/impl_core/src/main/java/io/opencensus/implcore/trace/export/SpanExporterImpl.java @@ -17,6 +17,7 @@ package io.opencensus.implcore.trace.export; import com.google.common.annotations.VisibleForTesting; +import io.opencensus.common.Duration; import io.opencensus.implcore.internal.DaemonThreadFactory; import io.opencensus.implcore.trace.SpanImpl; import io.opencensus.trace.export.ExportComponent; @@ -24,10 +25,10 @@ import io.opencensus.trace.export.SpanData; import io.opencensus.trace.export.SpanExporter; import java.util.ArrayList; import java.util.Collections; -import java.util.LinkedList; import java.util.List; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.TimeUnit; import java.util.logging.Level; import java.util.logging.Logger; import javax.annotation.concurrent.GuardedBy; @@ -47,11 +48,11 @@ public final class SpanExporterImpl extends SpanExporter { * the thread wakes up sooner. * * @param bufferSize the size of the buffered span data. - * @param scheduleDelayMillis the maximum delay in milliseconds. + * @param scheduleDelay the maximum delay. */ - static SpanExporterImpl create(int bufferSize, long scheduleDelayMillis) { + static SpanExporterImpl create(int bufferSize, Duration scheduleDelay) { // TODO(bdrutu): Consider to add a shutdown hook to not avoid dropping data. - Worker worker = new Worker(bufferSize, scheduleDelayMillis); + Worker worker = new Worker(bufferSize, scheduleDelay); return new SpanExporterImpl(worker); } @@ -142,12 +143,12 @@ public final class SpanExporterImpl extends SpanExporter { } } - // TODO: Decide whether to use a different class instead of LinkedList. - @SuppressWarnings("JdkObsolete") - private Worker(int bufferSize, long scheduleDelayMillis) { - spans = new LinkedList(); + private Worker(int bufferSize, Duration scheduleDelay) { + spans = new ArrayList(bufferSize); this.bufferSize = bufferSize; - this.scheduleDelayMillis = scheduleDelayMillis; + this.scheduleDelayMillis = + TimeUnit.SECONDS.toMillis(scheduleDelay.getSeconds()) + + TimeUnit.NANOSECONDS.toMillis(scheduleDelay.getNanos()); } // Returns an unmodifiable list of all buffered spans data to ensure that any registered -- cgit v1.2.3 From dc0ed0bba9d2adc1f3bee8558746560fbdb0f8a8 Mon Sep 17 00:00:00 2001 From: Kristen Kozak Date: Mon, 18 Dec 2017 22:21:10 -0800 Subject: Add more null annotations (issue #359). This commit adds some Nullable annotations that are required by the Checker Framework, but it doesn't change any other code. It also suppresses some Error Prone and FindBugs warnings that conflict with the Checker Framework, since the three tools use different algorithms. --- .../opencensus/implcore/trace/SpanBuilderImpl.java | 12 +++++------ .../io/opencensus/implcore/trace/SpanImpl.java | 23 ++++++++++++++-------- .../implcore/trace/StartEndHandlerImpl.java | 10 +++++----- .../implcore/trace/export/ExportComponentImpl.java | 4 ++-- .../trace/export/SampledSpanStoreImpl.java | 2 +- .../trace/internal/ConcurrentIntrusiveList.java | 9 ++++++--- 6 files changed, 35 insertions(+), 25 deletions(-) (limited to 'impl_core/src/main/java/io/opencensus/implcore/trace') 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 index 80f904d6..45cf4261 100644 --- a/impl_core/src/main/java/io/opencensus/implcore/trace/SpanBuilderImpl.java +++ b/impl_core/src/main/java/io/opencensus/implcore/trace/SpanBuilderImpl.java @@ -43,19 +43,19 @@ final class SpanBuilderImpl extends SpanBuilder { private final Options options; private final String name; - private final Span parent; - private final SpanContext remoteParentSpanContext; - private Sampler sampler; + @Nullable private final Span parent; + @Nullable private final SpanContext remoteParentSpanContext; + @Nullable private Sampler sampler; private List parentLinks = Collections.emptyList(); - private Boolean recordEvents; + @Nullable private Boolean recordEvents; private SpanImpl startSpanInternal( @Nullable SpanContext parent, @Nullable Boolean hasRemoteParent, String name, - Sampler sampler, + @Nullable Sampler sampler, List parentLinks, - Boolean recordEvents, + @Nullable Boolean recordEvents, @Nullable TimestampConverter timestampConverter) { TraceParams activeTraceParams = options.traceConfig.getActiveTraceParams(); Random random = options.randomHandler.current(); diff --git a/impl_core/src/main/java/io/opencensus/implcore/trace/SpanImpl.java b/impl_core/src/main/java/io/opencensus/implcore/trace/SpanImpl.java index 11d81747..c0682603 100644 --- a/impl_core/src/main/java/io/opencensus/implcore/trace/SpanImpl.java +++ b/impl_core/src/main/java/io/opencensus/implcore/trace/SpanImpl.java @@ -55,9 +55,9 @@ public final class SpanImpl extends Span implements Element { private static final Logger logger = Logger.getLogger(Tracer.class.getName()); // The parent SpanId of this span. Null if this is a root span. - private final SpanId parentSpanId; + @Nullable private final SpanId parentSpanId; // True if the parent is on a different process. - private final Boolean hasRemoteParent; + @Nullable private final Boolean hasRemoteParent; // Active trace params when the Span was created. private final TraceParams traceParams; // Handler called when the span starts and ends. @@ -68,24 +68,29 @@ public final class SpanImpl extends Span implements Element { private final Clock clock; // The time converter used to convert nano time to Timestamp. This is needed because Java has // millisecond granularity for Timestamp and tracing events are recorded more often. - private final TimestampConverter timestampConverter; + @Nullable private final TimestampConverter timestampConverter; // The start time of the span. Set when the span is created iff the RECORD_EVENTS options is // set, otherwise 0. private final long startNanoTime; // Set of recorded attributes. DO NOT CALL any other method that changes the ordering of events. @GuardedBy("this") + @Nullable private AttributesWithCapacity attributes; // List of recorded annotations. @GuardedBy("this") + @Nullable private TraceEvents> annotations; // List of recorded network events. @GuardedBy("this") + @Nullable private TraceEvents> networkEvents; // List of recorded links to parent and child spans. @GuardedBy("this") + @Nullable private TraceEvents links; // The status of the span. Set when the span is ended iff the RECORD_EVENTS options is set. @GuardedBy("this") + @Nullable private Status status; // The end time of the span. Set when the span is ended iff the RECORD_EVENTS options is set, // otherwise 0. @@ -99,8 +104,8 @@ public final class SpanImpl extends Span implements Element { private boolean sampleToLocalSpanStore; // Pointers for the ConcurrentIntrusiveList$Element. Guarded by the ConcurrentIntrusiveList. - private SpanImpl next = null; - private SpanImpl prev = null; + @Nullable private SpanImpl next = null; + @Nullable private SpanImpl prev = null; /** * Creates and starts a span with the given configuration. @@ -424,7 +429,7 @@ public final class SpanImpl extends Span implements Element { } private static SpanData.TimedEvents createTimedEvents( - TraceEvents> events, TimestampConverter timestampConverter) { + TraceEvents> events, @Nullable TimestampConverter timestampConverter) { if (events == null) { return SpanData.TimedEvents.create(Collections.>emptyList(), 0); } @@ -436,22 +441,24 @@ public final class SpanImpl extends Span implements Element { } @Override + @Nullable public SpanImpl getNext() { return next; } @Override - public void setNext(SpanImpl element) { + public void setNext(@Nullable SpanImpl element) { next = element; } @Override + @Nullable public SpanImpl getPrev() { return prev; } @Override - public void setPrev(SpanImpl element) { + public void setPrev(@Nullable SpanImpl element) { prev = element; } diff --git a/impl_core/src/main/java/io/opencensus/implcore/trace/StartEndHandlerImpl.java b/impl_core/src/main/java/io/opencensus/implcore/trace/StartEndHandlerImpl.java index fdb6147c..e22a86bd 100644 --- a/impl_core/src/main/java/io/opencensus/implcore/trace/StartEndHandlerImpl.java +++ b/impl_core/src/main/java/io/opencensus/implcore/trace/StartEndHandlerImpl.java @@ -33,8 +33,8 @@ import javax.annotation.concurrent.ThreadSafe; @ThreadSafe public final class StartEndHandlerImpl implements StartEndHandler { private final SpanExporterImpl spanExporter; - private final RunningSpanStoreImpl runningSpanStore; - private final SampledSpanStoreImpl sampledSpanStore; + @Nullable private final RunningSpanStoreImpl runningSpanStore; + @Nullable private final SampledSpanStoreImpl sampledSpanStore; private final EventQueue eventQueue; // true if any of (runningSpanStore OR sampledSpanStore) are different than null, which // means the spans with RECORD_EVENTS should be enqueued in the queue. @@ -78,7 +78,7 @@ public final class StartEndHandlerImpl implements StartEndHandler { // An EventQueue entry that records the start of the span event. private static final class SpanStartEvent implements EventQueue.Entry { private final SpanImpl span; - private final RunningSpanStoreImpl activeSpansExporter; + @Nullable private final RunningSpanStoreImpl activeSpansExporter; SpanStartEvent(SpanImpl span, @Nullable RunningSpanStoreImpl activeSpansExporter) { this.span = span; @@ -96,9 +96,9 @@ public final class StartEndHandlerImpl implements StartEndHandler { // An EventQueue entry that records the end of the span event. private static final class SpanEndEvent implements EventQueue.Entry { private final SpanImpl span; - private final RunningSpanStoreImpl runningSpanStore; + @Nullable private final RunningSpanStoreImpl runningSpanStore; private final SpanExporterImpl spanExporter; - private final SampledSpanStoreImpl sampledSpanStore; + @Nullable private final SampledSpanStoreImpl sampledSpanStore; SpanEndEvent( SpanImpl span, diff --git a/impl_core/src/main/java/io/opencensus/implcore/trace/export/ExportComponentImpl.java b/impl_core/src/main/java/io/opencensus/implcore/trace/export/ExportComponentImpl.java index 26c9004a..9f17039c 100644 --- a/impl_core/src/main/java/io/opencensus/implcore/trace/export/ExportComponentImpl.java +++ b/impl_core/src/main/java/io/opencensus/implcore/trace/export/ExportComponentImpl.java @@ -30,8 +30,8 @@ public final class ExportComponentImpl extends ExportComponent { private static final Duration EXPORTER_SCHEDULE_DELAY = Duration.create(5, 0); private final SpanExporterImpl spanExporter; - private final RunningSpanStoreImpl runningSpanStore; - private final SampledSpanStoreImpl sampledSpanStore; + @Nullable private final RunningSpanStoreImpl runningSpanStore; + @Nullable private final SampledSpanStoreImpl sampledSpanStore; @Override public SpanExporterImpl getSpanExporter() { diff --git a/impl_core/src/main/java/io/opencensus/implcore/trace/export/SampledSpanStoreImpl.java b/impl_core/src/main/java/io/opencensus/implcore/trace/export/SampledSpanStoreImpl.java index 60b1433c..0fad80fb 100644 --- a/impl_core/src/main/java/io/opencensus/implcore/trace/export/SampledSpanStoreImpl.java +++ b/impl_core/src/main/java/io/opencensus/implcore/trace/export/SampledSpanStoreImpl.java @@ -208,7 +208,7 @@ public final class SampledSpanStoreImpl extends SampledSpanStore { return errorBucketSummaries; } - private List getErrorSamples(CanonicalCode code, int maxSpansToReturn) { + private List getErrorSamples(@Nullable CanonicalCode code, int maxSpansToReturn) { ArrayList output = new ArrayList(maxSpansToReturn); if (code != null) { getErrorBucket(code).getSamples(maxSpansToReturn, output); diff --git a/impl_core/src/main/java/io/opencensus/implcore/trace/internal/ConcurrentIntrusiveList.java b/impl_core/src/main/java/io/opencensus/implcore/trace/internal/ConcurrentIntrusiveList.java index ef0b2664..a1210b00 100644 --- a/impl_core/src/main/java/io/opencensus/implcore/trace/internal/ConcurrentIntrusiveList.java +++ b/impl_core/src/main/java/io/opencensus/implcore/trace/internal/ConcurrentIntrusiveList.java @@ -22,6 +22,7 @@ import io.opencensus.implcore.trace.internal.ConcurrentIntrusiveList.Element; import java.util.ArrayList; import java.util.Collection; import java.util.List; +import javax.annotation.Nullable; import javax.annotation.concurrent.ThreadSafe; /** @@ -60,7 +61,7 @@ import javax.annotation.concurrent.ThreadSafe; @ThreadSafe public final class ConcurrentIntrusiveList> { private int size = 0; - private T head = null; + @Nullable private T head = null; public ConcurrentIntrusiveList() {} @@ -151,6 +152,7 @@ public final class ConcurrentIntrusiveList> { * * @return a reference to the next element in the list. */ + @Nullable T getNext(); /** @@ -158,13 +160,14 @@ public final class ConcurrentIntrusiveList> { * * @param element the reference to the next element in the list. */ - void setNext(T element); + void setNext(@Nullable T element); /** * Returns a reference to the previous element in the list. * * @return a reference to the previous element in the list. */ + @Nullable T getPrev(); /** @@ -172,6 +175,6 @@ public final class ConcurrentIntrusiveList> { * * @param element the reference to the previous element in the list. */ - void setPrev(T element); + void setPrev(@Nullable T element); } } -- cgit v1.2.3 From dad6b90e7979fcbc3fd3bf61f1561faeb07ca8b6 Mon Sep 17 00:00:00 2001 From: Kristen Kozak Date: Tue, 19 Dec 2017 17:17:57 -0800 Subject: Refactor some code to pass Checker Framework null analysis (issue #359). This commit shouldn't change any behavior. It just allows the Checker Framework to determine that there are no NPEs. --- impl_core/src/main/java/io/opencensus/implcore/trace/SpanImpl.java | 6 +++--- .../opencensus/implcore/trace/internal/ConcurrentIntrusiveList.java | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) (limited to 'impl_core/src/main/java/io/opencensus/implcore/trace') diff --git a/impl_core/src/main/java/io/opencensus/implcore/trace/SpanImpl.java b/impl_core/src/main/java/io/opencensus/implcore/trace/SpanImpl.java index c0682603..9f72aa71 100644 --- a/impl_core/src/main/java/io/opencensus/implcore/trace/SpanImpl.java +++ b/impl_core/src/main/java/io/opencensus/implcore/trace/SpanImpl.java @@ -236,9 +236,9 @@ public final class SpanImpl extends Span implements Element { ? SpanData.Attributes.create(Collections.emptyMap(), 0) : SpanData.Attributes.create(attributes, attributes.getNumberOfDroppedAttributes()); SpanData.TimedEvents annotationsSpanData = - createTimedEvents(annotations, timestampConverter); + createTimedEvents(getInitializedAnnotations(), timestampConverter); SpanData.TimedEvents networkEventsSpanData = - createTimedEvents(networkEvents, timestampConverter); + createTimedEvents(getInitializedNetworkEvents(), timestampConverter); SpanData.Links linksSpanData = links == null ? SpanData.Links.create(Collections.emptyList(), 0) @@ -573,7 +573,7 @@ public final class SpanImpl extends Span implements Element { this.clock = clock; this.hasBeenEnded = false; this.sampleToLocalSpanStore = false; - if (getOptions().contains(Options.RECORD_EVENTS)) { + if (options != null && options.contains(Options.RECORD_EVENTS)) { this.timestampConverter = timestampConverter != null ? timestampConverter : TimestampConverter.now(clock); startNanoTime = clock.nowNanos(); diff --git a/impl_core/src/main/java/io/opencensus/implcore/trace/internal/ConcurrentIntrusiveList.java b/impl_core/src/main/java/io/opencensus/implcore/trace/internal/ConcurrentIntrusiveList.java index a1210b00..3eb76ae4 100644 --- a/impl_core/src/main/java/io/opencensus/implcore/trace/internal/ConcurrentIntrusiveList.java +++ b/impl_core/src/main/java/io/opencensus/implcore/trace/internal/ConcurrentIntrusiveList.java @@ -79,8 +79,8 @@ public final class ConcurrentIntrusiveList> { if (head == null) { head = element; } else { - element.setNext(head); head.setPrev(element); + element.setNext(head); head = element; } } -- cgit v1.2.3 From 9b9c936c5f5eebf4e5ae34236cc6f2eacb03fb9d Mon Sep 17 00:00:00 2001 From: Kristen Kozak Date: Tue, 19 Dec 2017 17:19:59 -0800 Subject: Suppress nullness warnings from issue #914. --- .../io/opencensus/implcore/trace/export/ExportComponentImpl.java | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) (limited to 'impl_core/src/main/java/io/opencensus/implcore/trace') diff --git a/impl_core/src/main/java/io/opencensus/implcore/trace/export/ExportComponentImpl.java b/impl_core/src/main/java/io/opencensus/implcore/trace/export/ExportComponentImpl.java index 9f17039c..24042e84 100644 --- a/impl_core/src/main/java/io/opencensus/implcore/trace/export/ExportComponentImpl.java +++ b/impl_core/src/main/java/io/opencensus/implcore/trace/export/ExportComponentImpl.java @@ -38,14 +38,18 @@ public final class ExportComponentImpl extends ExportComponent { return spanExporter; } - @Nullable @Override + // TODO(#914): This method shouldn't be nullable. + @SuppressWarnings("nullness") + @Nullable public RunningSpanStoreImpl getRunningSpanStore() { return runningSpanStore; } - @Nullable @Override + // TODO(#914): This method shouldn't be nullable. + @SuppressWarnings("nullness") + @Nullable public SampledSpanStoreImpl getSampledSpanStore() { return sampledSpanStore; } -- cgit v1.2.3 From 2fc0d4dd057ca28e1e9c37d18ebcfac6d2136de9 Mon Sep 17 00:00:00 2001 From: Kristen Kozak Date: Tue, 19 Dec 2017 20:02:00 -0800 Subject: Suppress some Checker Framework warnings and add TODOs (issue #359). Fixing these warnings will require significant refactoring. --- .../src/main/java/io/opencensus/implcore/trace/SpanImpl.java | 10 +++++++--- .../implcore/trace/internal/ConcurrentIntrusiveList.java | 7 ++++--- 2 files changed, 11 insertions(+), 6 deletions(-) (limited to 'impl_core/src/main/java/io/opencensus/implcore/trace') diff --git a/impl_core/src/main/java/io/opencensus/implcore/trace/SpanImpl.java b/impl_core/src/main/java/io/opencensus/implcore/trace/SpanImpl.java index 9f72aa71..f80ba2bf 100644 --- a/impl_core/src/main/java/io/opencensus/implcore/trace/SpanImpl.java +++ b/impl_core/src/main/java/io/opencensus/implcore/trace/SpanImpl.java @@ -22,6 +22,7 @@ import static com.google.common.base.Preconditions.checkState; import com.google.common.annotations.VisibleForTesting; import com.google.common.collect.EvictingQueue; import io.opencensus.common.Clock; +import io.opencensus.implcore.internal.NullnessUtils; import io.opencensus.implcore.internal.TimestampConverter; import io.opencensus.implcore.trace.internal.ConcurrentIntrusiveList.Element; import io.opencensus.trace.Annotation; @@ -249,14 +250,16 @@ public final class SpanImpl extends Span implements Element { parentSpanId, hasRemoteParent, name, - timestampConverter.convertNanoTime(startNanoTime), + NullnessUtils.castNonNull(timestampConverter).convertNanoTime(startNanoTime), attributesSpanData, annotationsSpanData, networkEventsSpanData, linksSpanData, null, // Not supported yet. hasBeenEnded ? getStatusWithDefault() : null, - hasBeenEnded ? timestampConverter.convertNanoTime(endNanoTime) : null); + hasBeenEnded + ? NullnessUtils.castNonNull(timestampConverter).convertNanoTime(endNanoTime) + : null); } } @@ -435,7 +438,8 @@ public final class SpanImpl extends Span implements Element { } List> eventsList = new ArrayList>(events.events.size()); for (EventWithNanoTime networkEvent : events.events) { - eventsList.add(networkEvent.toSpanDataTimedEvent(timestampConverter)); + eventsList.add( + networkEvent.toSpanDataTimedEvent(NullnessUtils.castNonNull(timestampConverter))); } return SpanData.TimedEvents.create(eventsList, events.getNumberOfDroppedEvents()); } diff --git a/impl_core/src/main/java/io/opencensus/implcore/trace/internal/ConcurrentIntrusiveList.java b/impl_core/src/main/java/io/opencensus/implcore/trace/internal/ConcurrentIntrusiveList.java index 3eb76ae4..5b131756 100644 --- a/impl_core/src/main/java/io/opencensus/implcore/trace/internal/ConcurrentIntrusiveList.java +++ b/impl_core/src/main/java/io/opencensus/implcore/trace/internal/ConcurrentIntrusiveList.java @@ -18,6 +18,7 @@ package io.opencensus.implcore.trace.internal; import static com.google.common.base.Preconditions.checkArgument; +import io.opencensus.implcore.internal.NullnessUtils; import io.opencensus.implcore.trace.internal.ConcurrentIntrusiveList.Element; import java.util.ArrayList; import java.util.Collection; @@ -107,11 +108,11 @@ public final class ConcurrentIntrusiveList> { } else if (element.getNext() == null) { // This is the last element, and there is at least another element because // element.getPrev() != null. - element.getPrev().setNext(null); + NullnessUtils.castNonNull(element.getPrev()).setNext(null); element.setPrev(null); } else { - element.getPrev().setNext(element.getNext()); - element.getNext().setPrev(element.getPrev()); + NullnessUtils.castNonNull(element.getPrev()).setNext(element.getNext()); + NullnessUtils.castNonNull(element.getNext()).setPrev(element.getPrev()); element.setNext(null); element.setPrev(null); } -- cgit v1.2.3 From a2241dd72616869db521cc18724f7beab85be168 Mon Sep 17 00:00:00 2001 From: Kristen Kozak Date: Wed, 20 Dec 2017 10:46:38 -0800 Subject: Rename NullnessUtils to CheckerFrameworkUtils. --- .../src/main/java/io/opencensus/implcore/trace/SpanImpl.java | 8 ++++---- .../implcore/trace/internal/ConcurrentIntrusiveList.java | 8 ++++---- 2 files changed, 8 insertions(+), 8 deletions(-) (limited to 'impl_core/src/main/java/io/opencensus/implcore/trace') diff --git a/impl_core/src/main/java/io/opencensus/implcore/trace/SpanImpl.java b/impl_core/src/main/java/io/opencensus/implcore/trace/SpanImpl.java index f80ba2bf..8ce863e7 100644 --- a/impl_core/src/main/java/io/opencensus/implcore/trace/SpanImpl.java +++ b/impl_core/src/main/java/io/opencensus/implcore/trace/SpanImpl.java @@ -22,7 +22,7 @@ import static com.google.common.base.Preconditions.checkState; import com.google.common.annotations.VisibleForTesting; import com.google.common.collect.EvictingQueue; import io.opencensus.common.Clock; -import io.opencensus.implcore.internal.NullnessUtils; +import io.opencensus.implcore.internal.CheckerFrameworkUtils; import io.opencensus.implcore.internal.TimestampConverter; import io.opencensus.implcore.trace.internal.ConcurrentIntrusiveList.Element; import io.opencensus.trace.Annotation; @@ -250,7 +250,7 @@ public final class SpanImpl extends Span implements Element { parentSpanId, hasRemoteParent, name, - NullnessUtils.castNonNull(timestampConverter).convertNanoTime(startNanoTime), + CheckerFrameworkUtils.castNonNull(timestampConverter).convertNanoTime(startNanoTime), attributesSpanData, annotationsSpanData, networkEventsSpanData, @@ -258,7 +258,7 @@ public final class SpanImpl extends Span implements Element { null, // Not supported yet. hasBeenEnded ? getStatusWithDefault() : null, hasBeenEnded - ? NullnessUtils.castNonNull(timestampConverter).convertNanoTime(endNanoTime) + ? CheckerFrameworkUtils.castNonNull(timestampConverter).convertNanoTime(endNanoTime) : null); } } @@ -439,7 +439,7 @@ public final class SpanImpl extends Span implements Element { List> eventsList = new ArrayList>(events.events.size()); for (EventWithNanoTime networkEvent : events.events) { eventsList.add( - networkEvent.toSpanDataTimedEvent(NullnessUtils.castNonNull(timestampConverter))); + networkEvent.toSpanDataTimedEvent(CheckerFrameworkUtils.castNonNull(timestampConverter))); } return SpanData.TimedEvents.create(eventsList, events.getNumberOfDroppedEvents()); } diff --git a/impl_core/src/main/java/io/opencensus/implcore/trace/internal/ConcurrentIntrusiveList.java b/impl_core/src/main/java/io/opencensus/implcore/trace/internal/ConcurrentIntrusiveList.java index 5b131756..22d8e41a 100644 --- a/impl_core/src/main/java/io/opencensus/implcore/trace/internal/ConcurrentIntrusiveList.java +++ b/impl_core/src/main/java/io/opencensus/implcore/trace/internal/ConcurrentIntrusiveList.java @@ -18,7 +18,7 @@ package io.opencensus.implcore.trace.internal; import static com.google.common.base.Preconditions.checkArgument; -import io.opencensus.implcore.internal.NullnessUtils; +import io.opencensus.implcore.internal.CheckerFrameworkUtils; import io.opencensus.implcore.trace.internal.ConcurrentIntrusiveList.Element; import java.util.ArrayList; import java.util.Collection; @@ -108,11 +108,11 @@ public final class ConcurrentIntrusiveList> { } else if (element.getNext() == null) { // This is the last element, and there is at least another element because // element.getPrev() != null. - NullnessUtils.castNonNull(element.getPrev()).setNext(null); + CheckerFrameworkUtils.castNonNull(element.getPrev()).setNext(null); element.setPrev(null); } else { - NullnessUtils.castNonNull(element.getPrev()).setNext(element.getNext()); - NullnessUtils.castNonNull(element.getNext()).setPrev(element.getPrev()); + CheckerFrameworkUtils.castNonNull(element.getPrev()).setNext(element.getNext()); + CheckerFrameworkUtils.castNonNull(element.getNext()).setPrev(element.getPrev()); element.setNext(null); element.setPrev(null); } -- cgit v1.2.3 From 3b59ca22ca27239039f023919d546c137f867774 Mon Sep 17 00:00:00 2001 From: Hailong Wen Date: Wed, 17 Jan 2018 15:03:49 -0800 Subject: Add http propagation APIs. (#930) * Add http propagation APIs. * Add an API in `PropagationComponent` for B3 format access. * Add contrib-http-util, with initial SD format support. --- .../trace/propagation/CloudTraceFormat.java | 141 --------------------- .../propagation/PropagationComponentImpl.java | 7 + 2 files changed, 7 insertions(+), 141 deletions(-) delete mode 100644 impl_core/src/main/java/io/opencensus/implcore/trace/propagation/CloudTraceFormat.java (limited to 'impl_core/src/main/java/io/opencensus/implcore/trace') diff --git a/impl_core/src/main/java/io/opencensus/implcore/trace/propagation/CloudTraceFormat.java b/impl_core/src/main/java/io/opencensus/implcore/trace/propagation/CloudTraceFormat.java deleted file mode 100644 index ba4cc86a..00000000 --- a/impl_core/src/main/java/io/opencensus/implcore/trace/propagation/CloudTraceFormat.java +++ /dev/null @@ -1,141 +0,0 @@ -/* - * 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.propagation; - -import static com.google.common.base.Preconditions.checkArgument; -import static com.google.common.base.Preconditions.checkNotNull; - -import com.google.common.primitives.UnsignedInts; -import com.google.common.primitives.UnsignedLongs; -import io.opencensus.trace.SpanContext; -import io.opencensus.trace.SpanId; -import io.opencensus.trace.TraceId; -import io.opencensus.trace.TraceOptions; -import io.opencensus.trace.propagation.SpanContextParseException; -import io.opencensus.trace.propagation.TextFormat; -import java.nio.ByteBuffer; -import java.util.Collections; -import java.util.List; - -/** - * Implementation of the "X-Cloud-Trace-Context" format, defined by the Google Cloud Trace. - * - *

The supported format is the following: - * - *

- * <TRACE_ID>/<SPAN_ID>[;o=<TRACE_OPTIONS>]
- * 
- * - *
    - *
  • TRACE_ID is a 32-character hex value; - *
  • SPAN_ID is a decimal representation of a 64-bit unsigned long; - *
  • TRACE_OPTIONS is a decimal representation of a 32-bit unsigned integer. The least - * significant bit defines whether a request is traced (1 - enabled, 0 - disabled). Behaviors - * of other bits are currently undefined. This value is optional. Although upstream service - * may leave this value unset to leave the sampling decision up to downstream client, this - * utility will always default it to 0 if absent. - *
- * - *

Valid values: - * - *

    - *
  • "105445aa7843bc8bf206b120001000/123;o=1" - *
  • "105445aa7843bc8bf206b120001000/123" - *
  • "105445aa7843bc8bf206b120001000/123;o=0" - *
- */ -final class CloudTraceFormat extends TextFormat { - static final String HEADER_NAME = "X-Cloud-Trace-Context"; - static final List FIELDS = Collections.singletonList(HEADER_NAME); - static final char SPAN_ID_DELIMITER = '/'; - static final String TRACE_OPTION_DELIMITER = ";o="; - static final String SAMPLED = "1"; - static final String NOT_SAMPLED = "0"; - static final TraceOptions OPTIONS_SAMPLED = TraceOptions.builder().setIsSampled(true).build(); - static final TraceOptions OPTIONS_NOT_SAMPLED = TraceOptions.DEFAULT; - static final int TRACE_ID_SIZE = 2 * TraceId.SIZE; - static final int TRACE_OPTION_DELIMITER_SIZE = TRACE_OPTION_DELIMITER.length(); - static final int SPAN_ID_START_POS = TRACE_ID_SIZE + 1; - // 32-digit TRACE_ID + 1 digit SPAN_ID_DELIMITER + at least 1 digit SPAN_ID - static final int MIN_HEADER_SIZE = SPAN_ID_START_POS + 1; - static final int CLOUD_TRACE_IS_SAMPLED = 0x1; - - @Override - public List fields() { - return FIELDS; - } - - @Override - public void inject(SpanContext spanContext, C carrier, Setter setter) { - checkNotNull(spanContext, "spanContext"); - checkNotNull(setter, "setter"); - checkNotNull(carrier, "carrier"); - StringBuilder builder = - new StringBuilder() - .append(spanContext.getTraceId().toLowerBase16()) - .append(SPAN_ID_DELIMITER) - .append(UnsignedLongs.toString(spanIdToLong(spanContext.getSpanId()))) - .append(TRACE_OPTION_DELIMITER) - .append(spanContext.getTraceOptions().isSampled() ? SAMPLED : NOT_SAMPLED); - - setter.put(carrier, HEADER_NAME, builder.toString()); - } - - @Override - public SpanContext extract(C carrier, Getter getter) throws SpanContextParseException { - checkNotNull(carrier, "carrier"); - checkNotNull(getter, "getter"); - try { - String headerStr = getter.get(carrier, HEADER_NAME); - if (headerStr == null || headerStr.length() < MIN_HEADER_SIZE) { - throw new SpanContextParseException("Missing or too short header: " + HEADER_NAME); - } - checkArgument(headerStr.charAt(TRACE_ID_SIZE) == SPAN_ID_DELIMITER, "Invalid TRACE_ID size"); - - TraceId traceId = TraceId.fromLowerBase16(headerStr.subSequence(0, TRACE_ID_SIZE)); - int traceOptionsPos = headerStr.indexOf(TRACE_OPTION_DELIMITER, SPAN_ID_DELIMITER); - CharSequence spanIdStr = - headerStr.subSequence( - SPAN_ID_START_POS, traceOptionsPos < 0 ? headerStr.length() : traceOptionsPos); - SpanId spanId = longToSpanId(UnsignedLongs.parseUnsignedLong(spanIdStr.toString(), 10)); - TraceOptions traceOptions = OPTIONS_NOT_SAMPLED; - if (traceOptionsPos > 0) { - String traceOptionsStr = headerStr.substring(traceOptionsPos + TRACE_OPTION_DELIMITER_SIZE); - if ((UnsignedInts.parseUnsignedInt(traceOptionsStr, 10) & CLOUD_TRACE_IS_SAMPLED) != 0) { - traceOptions = OPTIONS_SAMPLED; - } - } - return SpanContext.create(traceId, spanId, traceOptions); - } catch (IllegalArgumentException e) { - throw new SpanContextParseException("Invalid input", e); - } - } - - // Using big-endian encoding. - private static SpanId longToSpanId(long x) { - ByteBuffer buffer = ByteBuffer.allocate(SpanId.SIZE); - buffer.putLong(x); - return SpanId.fromBytes(buffer.array()); - } - - // Using big-endian encoding. - private static long spanIdToLong(SpanId spanId) { - ByteBuffer buffer = ByteBuffer.allocate(SpanId.SIZE); - buffer.put(spanId.getBytes()); - return buffer.getLong(0); - } -} diff --git a/impl_core/src/main/java/io/opencensus/implcore/trace/propagation/PropagationComponentImpl.java b/impl_core/src/main/java/io/opencensus/implcore/trace/propagation/PropagationComponentImpl.java index 757623a3..f608543d 100644 --- a/impl_core/src/main/java/io/opencensus/implcore/trace/propagation/PropagationComponentImpl.java +++ b/impl_core/src/main/java/io/opencensus/implcore/trace/propagation/PropagationComponentImpl.java @@ -18,13 +18,20 @@ package io.opencensus.implcore.trace.propagation; import io.opencensus.trace.propagation.BinaryFormat; import io.opencensus.trace.propagation.PropagationComponent; +import io.opencensus.trace.propagation.TextFormat; /** Implementation of the {@link PropagationComponent}. */ public class PropagationComponentImpl extends PropagationComponent { private final BinaryFormat binaryFormat = new BinaryFormatImpl(); + private final B3Format b3Format = new B3Format(); @Override public BinaryFormat getBinaryFormat() { return binaryFormat; } + + @Override + public TextFormat getB3Format() { + return b3Format; + } } -- cgit v1.2.3 From fee27583a43f54b0bad105e51e3755b248fe4d4d Mon Sep 17 00:00:00 2001 From: Hailong Wen Date: Tue, 6 Feb 2018 10:57:58 -0800 Subject: Make `XxxSpanStoreImpl` abstract and add no-op implementation. (fixes #914) (#964) --- .../implcore/trace/export/ExportComponentImpl.java | 21 +- .../export/InProcessRunningSpanStoreImpl.java | 81 +++++ .../export/InProcessSampledSpanStoreImpl.java | 381 +++++++++++++++++++++ .../trace/export/RunningSpanStoreImpl.java | 79 ++--- .../trace/export/SampledSpanStoreImpl.java | 371 ++------------------ 5 files changed, 538 insertions(+), 395 deletions(-) create mode 100644 impl_core/src/main/java/io/opencensus/implcore/trace/export/InProcessRunningSpanStoreImpl.java create mode 100644 impl_core/src/main/java/io/opencensus/implcore/trace/export/InProcessSampledSpanStoreImpl.java (limited to 'impl_core/src/main/java/io/opencensus/implcore/trace') diff --git a/impl_core/src/main/java/io/opencensus/implcore/trace/export/ExportComponentImpl.java b/impl_core/src/main/java/io/opencensus/implcore/trace/export/ExportComponentImpl.java index 24042e84..e77d1f8e 100644 --- a/impl_core/src/main/java/io/opencensus/implcore/trace/export/ExportComponentImpl.java +++ b/impl_core/src/main/java/io/opencensus/implcore/trace/export/ExportComponentImpl.java @@ -21,7 +21,6 @@ import io.opencensus.implcore.internal.EventQueue; import io.opencensus.trace.export.ExportComponent; import io.opencensus.trace.export.RunningSpanStore; import io.opencensus.trace.export.SampledSpanStore; -import javax.annotation.Nullable; /** Implementation of the {@link ExportComponent}. */ public final class ExportComponentImpl extends ExportComponent { @@ -30,8 +29,8 @@ public final class ExportComponentImpl extends ExportComponent { private static final Duration EXPORTER_SCHEDULE_DELAY = Duration.create(5, 0); private final SpanExporterImpl spanExporter; - @Nullable private final RunningSpanStoreImpl runningSpanStore; - @Nullable private final SampledSpanStoreImpl sampledSpanStore; + private final RunningSpanStoreImpl runningSpanStore; + private final SampledSpanStoreImpl sampledSpanStore; @Override public SpanExporterImpl getSpanExporter() { @@ -39,17 +38,11 @@ public final class ExportComponentImpl extends ExportComponent { } @Override - // TODO(#914): This method shouldn't be nullable. - @SuppressWarnings("nullness") - @Nullable public RunningSpanStoreImpl getRunningSpanStore() { return runningSpanStore; } @Override - // TODO(#914): This method shouldn't be nullable. - @SuppressWarnings("nullness") - @Nullable public SampledSpanStoreImpl getSampledSpanStore() { return sampledSpanStore; } @@ -82,7 +75,13 @@ public final class ExportComponentImpl extends ExportComponent { */ private ExportComponentImpl(boolean supportInProcessStores, EventQueue eventQueue) { this.spanExporter = SpanExporterImpl.create(EXPORTER_BUFFER_SIZE, EXPORTER_SCHEDULE_DELAY); - this.runningSpanStore = supportInProcessStores ? new RunningSpanStoreImpl() : null; - this.sampledSpanStore = supportInProcessStores ? new SampledSpanStoreImpl(eventQueue) : null; + this.runningSpanStore = + supportInProcessStores + ? new InProcessRunningSpanStoreImpl() + : RunningSpanStoreImpl.getNoopRunningSpanStoreImpl(); + this.sampledSpanStore = + supportInProcessStores + ? new InProcessSampledSpanStoreImpl(eventQueue) + : SampledSpanStoreImpl.getNoopSampledSpanStoreImpl(); } } diff --git a/impl_core/src/main/java/io/opencensus/implcore/trace/export/InProcessRunningSpanStoreImpl.java b/impl_core/src/main/java/io/opencensus/implcore/trace/export/InProcessRunningSpanStoreImpl.java new file mode 100644 index 00000000..3d8fb9ae --- /dev/null +++ b/impl_core/src/main/java/io/opencensus/implcore/trace/export/InProcessRunningSpanStoreImpl.java @@ -0,0 +1,81 @@ +/* + * Copyright 2018, 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.export; + +import io.opencensus.implcore.trace.SpanImpl; +import io.opencensus.implcore.trace.internal.ConcurrentIntrusiveList; +import io.opencensus.trace.export.RunningSpanStore; +import io.opencensus.trace.export.SpanData; +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import javax.annotation.concurrent.ThreadSafe; + +/** In-process implementation of the {@link RunningSpanStore}. */ +@ThreadSafe +public final class InProcessRunningSpanStoreImpl extends RunningSpanStoreImpl { + private final ConcurrentIntrusiveList runningSpans; + + public InProcessRunningSpanStoreImpl() { + runningSpans = new ConcurrentIntrusiveList(); + } + + @Override + public void onStart(SpanImpl span) { + runningSpans.addElement(span); + } + + @Override + public void onEnd(SpanImpl span) { + runningSpans.removeElement(span); + } + + @Override + public Summary getSummary() { + Collection allRunningSpans = runningSpans.getAll(); + Map numSpansPerName = new HashMap(); + for (SpanImpl span : allRunningSpans) { + Integer prevValue = numSpansPerName.get(span.getName()); + numSpansPerName.put(span.getName(), prevValue != null ? prevValue + 1 : 1); + } + Map perSpanNameSummary = new HashMap(); + for (Map.Entry it : numSpansPerName.entrySet()) { + perSpanNameSummary.put(it.getKey(), PerSpanNameSummary.create(it.getValue())); + } + Summary summary = Summary.create(perSpanNameSummary); + return summary; + } + + @Override + public Collection getRunningSpans(Filter filter) { + Collection allRunningSpans = runningSpans.getAll(); + int maxSpansToReturn = + filter.getMaxSpansToReturn() == 0 ? allRunningSpans.size() : filter.getMaxSpansToReturn(); + List ret = new ArrayList(maxSpansToReturn); + for (SpanImpl span : allRunningSpans) { + if (ret.size() == maxSpansToReturn) { + break; + } + if (span.getName().equals(filter.getSpanName())) { + ret.add(span.toSpanData()); + } + } + return ret; + } +} diff --git a/impl_core/src/main/java/io/opencensus/implcore/trace/export/InProcessSampledSpanStoreImpl.java b/impl_core/src/main/java/io/opencensus/implcore/trace/export/InProcessSampledSpanStoreImpl.java new file mode 100644 index 00000000..1bdb3f41 --- /dev/null +++ b/impl_core/src/main/java/io/opencensus/implcore/trace/export/InProcessSampledSpanStoreImpl.java @@ -0,0 +1,381 @@ +/* + * Copyright 2018, 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.export; + +import com.google.common.collect.EvictingQueue; +import io.opencensus.implcore.internal.EventQueue; +import io.opencensus.implcore.trace.SpanImpl; +import io.opencensus.trace.Status; +import io.opencensus.trace.Status.CanonicalCode; +import io.opencensus.trace.export.SampledSpanStore; +import io.opencensus.trace.export.SpanData; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.EnumMap; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.concurrent.TimeUnit; +import javax.annotation.Nullable; +import javax.annotation.concurrent.GuardedBy; +import javax.annotation.concurrent.ThreadSafe; + +/** In-process implementation of the {@link SampledSpanStore}. */ +@ThreadSafe +public final class InProcessSampledSpanStoreImpl extends SampledSpanStoreImpl { + private static final int NUM_SAMPLES_PER_LATENCY_BUCKET = 10; + private static final int NUM_SAMPLES_PER_ERROR_BUCKET = 5; + private static final long TIME_BETWEEN_SAMPLES = TimeUnit.SECONDS.toNanos(1); + private static final int NUM_LATENCY_BUCKETS = LatencyBucketBoundaries.values().length; + // The total number of canonical codes - 1 (the OK code). + private static final int NUM_ERROR_BUCKETS = CanonicalCode.values().length - 1; + private static final int MAX_PER_SPAN_NAME_SAMPLES = + NUM_SAMPLES_PER_LATENCY_BUCKET * NUM_LATENCY_BUCKETS + + NUM_SAMPLES_PER_ERROR_BUCKET * NUM_ERROR_BUCKETS; + + // Used to stream the register/unregister events to the implementation to avoid lock contention + // between the main threads and the worker thread. + private final EventQueue eventQueue; + + @GuardedBy("samples") + private final Map samples; + + private static final class Bucket { + + private final EvictingQueue sampledSpansQueue; + private final EvictingQueue notSampledSpansQueue; + private long lastSampledNanoTime; + private long lastNotSampledNanoTime; + + private Bucket(int numSamples) { + sampledSpansQueue = EvictingQueue.create(numSamples); + notSampledSpansQueue = EvictingQueue.create(numSamples); + } + + private void considerForSampling(SpanImpl span) { + long spanEndNanoTime = span.getEndNanoTime(); + if (span.getContext().getTraceOptions().isSampled()) { + // Need to compare by doing the subtraction all the time because in case of an overflow, + // this may never sample again (at least for the next ~200 years). No real chance to + // overflow two times because that means the process runs for ~200 years. + if (spanEndNanoTime - lastSampledNanoTime > TIME_BETWEEN_SAMPLES) { + sampledSpansQueue.add(span); + lastSampledNanoTime = spanEndNanoTime; + } + } else { + // Need to compare by doing the subtraction all the time because in case of an overflow, + // this may never sample again (at least for the next ~200 years). No real chance to + // overflow two times because that means the process runs for ~200 years. + if (spanEndNanoTime - lastNotSampledNanoTime > TIME_BETWEEN_SAMPLES) { + notSampledSpansQueue.add(span); + lastNotSampledNanoTime = spanEndNanoTime; + } + } + } + + private void getSamples(int maxSpansToReturn, List output) { + getSamples(maxSpansToReturn, output, sampledSpansQueue); + getSamples(maxSpansToReturn, output, notSampledSpansQueue); + } + + private static void getSamples( + int maxSpansToReturn, List output, EvictingQueue queue) { + for (SpanImpl span : queue) { + if (output.size() >= maxSpansToReturn) { + break; + } + output.add(span); + } + } + + private void getSamplesFilteredByLatency( + long latencyLowerNs, long latencyUpperNs, int maxSpansToReturn, List output) { + getSamplesFilteredByLatency( + latencyLowerNs, latencyUpperNs, maxSpansToReturn, output, sampledSpansQueue); + getSamplesFilteredByLatency( + latencyLowerNs, latencyUpperNs, maxSpansToReturn, output, notSampledSpansQueue); + } + + private static void getSamplesFilteredByLatency( + long latencyLowerNs, + long latencyUpperNs, + int maxSpansToReturn, + List output, + EvictingQueue queue) { + for (SpanImpl span : queue) { + if (output.size() >= maxSpansToReturn) { + break; + } + long spanLatencyNs = span.getLatencyNs(); + if (spanLatencyNs >= latencyLowerNs && spanLatencyNs < latencyUpperNs) { + output.add(span); + } + } + } + + private int getNumSamples() { + return sampledSpansQueue.size() + notSampledSpansQueue.size(); + } + } + + /** + * Keeps samples for a given span name. Samples for all the latency buckets and for all canonical + * codes other than OK. + */ + private static final class PerSpanNameSamples { + + private final Bucket[] latencyBuckets; + private final Bucket[] errorBuckets; + + private PerSpanNameSamples() { + latencyBuckets = new Bucket[NUM_LATENCY_BUCKETS]; + for (int i = 0; i < NUM_LATENCY_BUCKETS; i++) { + latencyBuckets[i] = new Bucket(NUM_SAMPLES_PER_LATENCY_BUCKET); + } + errorBuckets = new Bucket[NUM_ERROR_BUCKETS]; + for (int i = 0; i < NUM_ERROR_BUCKETS; i++) { + errorBuckets[i] = new Bucket(NUM_SAMPLES_PER_ERROR_BUCKET); + } + } + + @Nullable + private Bucket getLatencyBucket(long latencyNs) { + for (int i = 0; i < NUM_LATENCY_BUCKETS; i++) { + LatencyBucketBoundaries boundaries = LatencyBucketBoundaries.values()[i]; + if (latencyNs >= boundaries.getLatencyLowerNs() + && latencyNs < boundaries.getLatencyUpperNs()) { + return latencyBuckets[i]; + } + } + // latencyNs is negative or Long.MAX_VALUE, so this Span can be ignored. This cannot happen + // in real production because System#nanoTime is monotonic. + return null; + } + + private Bucket getErrorBucket(CanonicalCode code) { + return errorBuckets[code.value() - 1]; + } + + private void considerForSampling(SpanImpl span) { + Status status = span.getStatus(); + // Null status means running Span, this should not happen in production, but the library + // should not crash because of this. + if (status != null) { + Bucket bucket = + status.isOk() + ? getLatencyBucket(span.getLatencyNs()) + : getErrorBucket(status.getCanonicalCode()); + // If unable to find the bucket, ignore this Span. + if (bucket != null) { + bucket.considerForSampling(span); + } + } + } + + private Map getNumbersOfLatencySampledSpans() { + Map latencyBucketSummaries = + new EnumMap(LatencyBucketBoundaries.class); + for (int i = 0; i < NUM_LATENCY_BUCKETS; i++) { + latencyBucketSummaries.put( + LatencyBucketBoundaries.values()[i], latencyBuckets[i].getNumSamples()); + } + return latencyBucketSummaries; + } + + private Map getNumbersOfErrorSampledSpans() { + Map errorBucketSummaries = + new EnumMap(CanonicalCode.class); + for (int i = 0; i < NUM_ERROR_BUCKETS; i++) { + errorBucketSummaries.put(CanonicalCode.values()[i + 1], errorBuckets[i].getNumSamples()); + } + return errorBucketSummaries; + } + + private List getErrorSamples(@Nullable CanonicalCode code, int maxSpansToReturn) { + ArrayList output = new ArrayList(maxSpansToReturn); + if (code != null) { + getErrorBucket(code).getSamples(maxSpansToReturn, output); + } else { + for (int i = 0; i < NUM_ERROR_BUCKETS; i++) { + errorBuckets[i].getSamples(maxSpansToReturn, output); + } + } + return output; + } + + private List getLatencySamples( + long latencyLowerNs, long latencyUpperNs, int maxSpansToReturn) { + ArrayList output = new ArrayList(maxSpansToReturn); + for (int i = 0; i < NUM_LATENCY_BUCKETS; i++) { + LatencyBucketBoundaries boundaries = LatencyBucketBoundaries.values()[i]; + if (latencyUpperNs >= boundaries.getLatencyLowerNs() + && latencyLowerNs < boundaries.getLatencyUpperNs()) { + latencyBuckets[i].getSamplesFilteredByLatency( + latencyLowerNs, latencyUpperNs, maxSpansToReturn, output); + } + } + return output; + } + } + + /** Constructs a new {@code InProcessSampledSpanStoreImpl}. */ + InProcessSampledSpanStoreImpl(EventQueue eventQueue) { + samples = new HashMap(); + this.eventQueue = eventQueue; + } + + @Override + public Summary getSummary() { + Map ret = new HashMap(); + synchronized (samples) { + for (Map.Entry it : samples.entrySet()) { + ret.put( + it.getKey(), + PerSpanNameSummary.create( + it.getValue().getNumbersOfLatencySampledSpans(), + it.getValue().getNumbersOfErrorSampledSpans())); + } + } + return Summary.create(ret); + } + + @Override + public void considerForSampling(SpanImpl span) { + synchronized (samples) { + String spanName = span.getName(); + if (span.getSampleToLocalSpanStore() && !samples.containsKey(spanName)) { + samples.put(spanName, new PerSpanNameSamples()); + } + PerSpanNameSamples perSpanNameSamples = samples.get(spanName); + if (perSpanNameSamples != null) { + perSpanNameSamples.considerForSampling(span); + } + } + } + + @Override + public void registerSpanNamesForCollection(Collection spanNames) { + eventQueue.enqueue(new RegisterSpanNameEvent(this, spanNames)); + } + + private void internaltRegisterSpanNamesForCollection(Collection spanNames) { + synchronized (samples) { + for (String spanName : spanNames) { + if (!samples.containsKey(spanName)) { + samples.put(spanName, new PerSpanNameSamples()); + } + } + } + } + + private static final class RegisterSpanNameEvent implements EventQueue.Entry { + private final InProcessSampledSpanStoreImpl sampledSpanStore; + private final Collection spanNames; + + private RegisterSpanNameEvent( + InProcessSampledSpanStoreImpl sampledSpanStore, Collection spanNames) { + this.sampledSpanStore = sampledSpanStore; + this.spanNames = new ArrayList(spanNames); + } + + @Override + public void process() { + sampledSpanStore.internaltRegisterSpanNamesForCollection(spanNames); + } + } + + @Override + public void unregisterSpanNamesForCollection(Collection spanNames) { + eventQueue.enqueue(new UnregisterSpanNameEvent(this, spanNames)); + } + + private void internalUnregisterSpanNamesForCollection(Collection spanNames) { + synchronized (samples) { + samples.keySet().removeAll(spanNames); + } + } + + private static final class UnregisterSpanNameEvent implements EventQueue.Entry { + private final InProcessSampledSpanStoreImpl sampledSpanStore; + private final Collection spanNames; + + private UnregisterSpanNameEvent( + InProcessSampledSpanStoreImpl sampledSpanStore, Collection spanNames) { + this.sampledSpanStore = sampledSpanStore; + this.spanNames = new ArrayList(spanNames); + } + + @Override + public void process() { + sampledSpanStore.internalUnregisterSpanNamesForCollection(spanNames); + } + } + + @Override + public Set getRegisteredSpanNamesForCollection() { + synchronized (samples) { + return Collections.unmodifiableSet(new HashSet(samples.keySet())); + } + } + + @Override + public Collection getErrorSampledSpans(ErrorFilter filter) { + int numSpansToReturn = + filter.getMaxSpansToReturn() == 0 + ? MAX_PER_SPAN_NAME_SAMPLES + : filter.getMaxSpansToReturn(); + List spans = Collections.emptyList(); + // Try to not keep the lock to much, do the SpanImpl -> SpanData conversion outside the lock. + synchronized (samples) { + PerSpanNameSamples perSpanNameSamples = samples.get(filter.getSpanName()); + if (perSpanNameSamples != null) { + spans = perSpanNameSamples.getErrorSamples(filter.getCanonicalCode(), numSpansToReturn); + } + } + List ret = new ArrayList(spans.size()); + for (SpanImpl span : spans) { + ret.add(span.toSpanData()); + } + return Collections.unmodifiableList(ret); + } + + @Override + public Collection getLatencySampledSpans(LatencyFilter filter) { + int numSpansToReturn = + filter.getMaxSpansToReturn() == 0 + ? MAX_PER_SPAN_NAME_SAMPLES + : filter.getMaxSpansToReturn(); + List spans = Collections.emptyList(); + // Try to not keep the lock to much, do the SpanImpl -> SpanData conversion outside the lock. + synchronized (samples) { + PerSpanNameSamples perSpanNameSamples = samples.get(filter.getSpanName()); + if (perSpanNameSamples != null) { + spans = + perSpanNameSamples.getLatencySamples( + filter.getLatencyLowerNs(), filter.getLatencyUpperNs(), numSpansToReturn); + } + } + List ret = new ArrayList(spans.size()); + for (SpanImpl span : spans) { + ret.add(span.toSpanData()); + } + return Collections.unmodifiableList(ret); + } +} diff --git a/impl_core/src/main/java/io/opencensus/implcore/trace/export/RunningSpanStoreImpl.java b/impl_core/src/main/java/io/opencensus/implcore/trace/export/RunningSpanStoreImpl.java index 98a51707..53147def 100644 --- a/impl_core/src/main/java/io/opencensus/implcore/trace/export/RunningSpanStoreImpl.java +++ b/impl_core/src/main/java/io/opencensus/implcore/trace/export/RunningSpanStoreImpl.java @@ -1,5 +1,5 @@ /* - * Copyright 2017, OpenCensus Authors + * Copyright 2018, OpenCensus Authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -17,23 +17,23 @@ package io.opencensus.implcore.trace.export; import io.opencensus.implcore.trace.SpanImpl; -import io.opencensus.implcore.trace.internal.ConcurrentIntrusiveList; import io.opencensus.trace.export.RunningSpanStore; +import io.opencensus.trace.export.RunningSpanStore.Filter; +import io.opencensus.trace.export.RunningSpanStore.PerSpanNameSummary; +import io.opencensus.trace.export.RunningSpanStore.Summary; import io.opencensus.trace.export.SpanData; -import java.util.ArrayList; import java.util.Collection; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import javax.annotation.concurrent.ThreadSafe; +import java.util.Collections; -/** Implementation of the {@link RunningSpanStore}. */ -@ThreadSafe -public final class RunningSpanStoreImpl extends RunningSpanStore { - private final ConcurrentIntrusiveList runningSpans; +/** Abstract implementation of the {@link RunningSpanStore}. */ +public abstract class RunningSpanStoreImpl extends RunningSpanStore { - public RunningSpanStoreImpl() { - runningSpans = new ConcurrentIntrusiveList(); + private static final RunningSpanStoreImpl NOOP_RUNNING_SPAN_STORE_IMPL = + new NoopRunningSpanStoreImpl(); + + /** Returns the no-op implementation of the {@link RunningSpanStoreImpl}. */ + static RunningSpanStoreImpl getNoopRunningSpanStoreImpl() { + return NOOP_RUNNING_SPAN_STORE_IMPL; } /** @@ -41,49 +41,34 @@ public final class RunningSpanStoreImpl extends RunningSpanStore { * * @param span the {@code Span} that started. */ - public void onStart(SpanImpl span) { - runningSpans.addElement(span); - } + public abstract void onStart(SpanImpl span); /** * Removes the {@code Span} from the running spans list when the {@code Span} ends. * * @param span the {@code Span} that ended. */ - public void onEnd(SpanImpl span) { - runningSpans.removeElement(span); - } + public abstract void onEnd(SpanImpl span); - @Override - public Summary getSummary() { - Collection allRunningSpans = runningSpans.getAll(); - Map numSpansPerName = new HashMap(); - for (SpanImpl span : allRunningSpans) { - Integer prevValue = numSpansPerName.get(span.getName()); - numSpansPerName.put(span.getName(), prevValue != null ? prevValue + 1 : 1); - } - Map perSpanNameSummary = new HashMap(); - for (Map.Entry it : numSpansPerName.entrySet()) { - perSpanNameSummary.put(it.getKey(), PerSpanNameSummary.create(it.getValue())); + private static final class NoopRunningSpanStoreImpl extends RunningSpanStoreImpl { + + private static final Summary EMPTY_SUMMARY = + RunningSpanStore.Summary.create(Collections.emptyMap()); + + @Override + public void onStart(SpanImpl span) {} + + @Override + public void onEnd(SpanImpl span) {} + + @Override + public Summary getSummary() { + return EMPTY_SUMMARY; } - Summary summary = Summary.create(perSpanNameSummary); - return summary; - } - @Override - public Collection getRunningSpans(Filter filter) { - Collection allRunningSpans = runningSpans.getAll(); - int maxSpansToReturn = - filter.getMaxSpansToReturn() == 0 ? allRunningSpans.size() : filter.getMaxSpansToReturn(); - List ret = new ArrayList(maxSpansToReturn); - for (SpanImpl span : allRunningSpans) { - if (ret.size() == maxSpansToReturn) { - break; - } - if (span.getName().equals(filter.getSpanName())) { - ret.add(span.toSpanData()); - } + @Override + public Collection getRunningSpans(Filter filter) { + return Collections.emptyList(); } - return ret; } } diff --git a/impl_core/src/main/java/io/opencensus/implcore/trace/export/SampledSpanStoreImpl.java b/impl_core/src/main/java/io/opencensus/implcore/trace/export/SampledSpanStoreImpl.java index 0fad80fb..0c83a05a 100644 --- a/impl_core/src/main/java/io/opencensus/implcore/trace/export/SampledSpanStoreImpl.java +++ b/impl_core/src/main/java/io/opencensus/implcore/trace/export/SampledSpanStoreImpl.java @@ -1,5 +1,5 @@ /* - * Copyright 2017, OpenCensus Authors + * Copyright 2018, OpenCensus Authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,244 +16,25 @@ package io.opencensus.implcore.trace.export; -import com.google.common.collect.EvictingQueue; -import io.opencensus.implcore.internal.EventQueue; import io.opencensus.implcore.trace.SpanImpl; -import io.opencensus.trace.Status; -import io.opencensus.trace.Status.CanonicalCode; import io.opencensus.trace.export.SampledSpanStore; +import io.opencensus.trace.export.SampledSpanStore.ErrorFilter; +import io.opencensus.trace.export.SampledSpanStore.LatencyFilter; +import io.opencensus.trace.export.SampledSpanStore.PerSpanNameSummary; +import io.opencensus.trace.export.SampledSpanStore.Summary; import io.opencensus.trace.export.SpanData; -import java.util.ArrayList; import java.util.Collection; import java.util.Collections; -import java.util.EnumMap; -import java.util.HashMap; -import java.util.HashSet; -import java.util.List; -import java.util.Map; import java.util.Set; -import java.util.concurrent.TimeUnit; -import javax.annotation.Nullable; -import javax.annotation.concurrent.GuardedBy; -import javax.annotation.concurrent.ThreadSafe; -/** Implementation of the {@link SampledSpanStore}. */ -@ThreadSafe -public final class SampledSpanStoreImpl extends SampledSpanStore { - private static final int NUM_SAMPLES_PER_LATENCY_BUCKET = 10; - private static final int NUM_SAMPLES_PER_ERROR_BUCKET = 5; - private static final long TIME_BETWEEN_SAMPLES = TimeUnit.SECONDS.toNanos(1); - private static final int NUM_LATENCY_BUCKETS = LatencyBucketBoundaries.values().length; - // The total number of canonical codes - 1 (the OK code). - private static final int NUM_ERROR_BUCKETS = CanonicalCode.values().length - 1; - private static final int MAX_PER_SPAN_NAME_SAMPLES = - NUM_SAMPLES_PER_LATENCY_BUCKET * NUM_LATENCY_BUCKETS - + NUM_SAMPLES_PER_ERROR_BUCKET * NUM_ERROR_BUCKETS; +/** Abstract implementation of the {@link SampledSpanStore}. */ +public abstract class SampledSpanStoreImpl extends SampledSpanStore { + private static final SampledSpanStoreImpl NOOP_SAMPLED_SPAN_STORE_IMPL = + new NoopSampledSpanStoreImpl(); - // Used to stream the register/unregister events to the implementation to avoid lock contention - // between the main threads and the worker thread. - private final EventQueue eventQueue; - - @GuardedBy("samples") - private final Map samples; - - private static final class Bucket { - - private final EvictingQueue sampledSpansQueue; - private final EvictingQueue notSampledSpansQueue; - private long lastSampledNanoTime; - private long lastNotSampledNanoTime; - - private Bucket(int numSamples) { - sampledSpansQueue = EvictingQueue.create(numSamples); - notSampledSpansQueue = EvictingQueue.create(numSamples); - } - - private void considerForSampling(SpanImpl span) { - long spanEndNanoTime = span.getEndNanoTime(); - if (span.getContext().getTraceOptions().isSampled()) { - // Need to compare by doing the subtraction all the time because in case of an overflow, - // this may never sample again (at least for the next ~200 years). No real chance to - // overflow two times because that means the process runs for ~200 years. - if (spanEndNanoTime - lastSampledNanoTime > TIME_BETWEEN_SAMPLES) { - sampledSpansQueue.add(span); - lastSampledNanoTime = spanEndNanoTime; - } - } else { - // Need to compare by doing the subtraction all the time because in case of an overflow, - // this may never sample again (at least for the next ~200 years). No real chance to - // overflow two times because that means the process runs for ~200 years. - if (spanEndNanoTime - lastNotSampledNanoTime > TIME_BETWEEN_SAMPLES) { - notSampledSpansQueue.add(span); - lastNotSampledNanoTime = spanEndNanoTime; - } - } - } - - private void getSamples(int maxSpansToReturn, List output) { - getSamples(maxSpansToReturn, output, sampledSpansQueue); - getSamples(maxSpansToReturn, output, notSampledSpansQueue); - } - - private static void getSamples( - int maxSpansToReturn, List output, EvictingQueue queue) { - for (SpanImpl span : queue) { - if (output.size() >= maxSpansToReturn) { - break; - } - output.add(span); - } - } - - private void getSamplesFilteredByLatency( - long latencyLowerNs, long latencyUpperNs, int maxSpansToReturn, List output) { - getSamplesFilteredByLatency( - latencyLowerNs, latencyUpperNs, maxSpansToReturn, output, sampledSpansQueue); - getSamplesFilteredByLatency( - latencyLowerNs, latencyUpperNs, maxSpansToReturn, output, notSampledSpansQueue); - } - - private static void getSamplesFilteredByLatency( - long latencyLowerNs, - long latencyUpperNs, - int maxSpansToReturn, - List output, - EvictingQueue queue) { - for (SpanImpl span : queue) { - if (output.size() >= maxSpansToReturn) { - break; - } - long spanLatencyNs = span.getLatencyNs(); - if (spanLatencyNs >= latencyLowerNs && spanLatencyNs < latencyUpperNs) { - output.add(span); - } - } - } - - private int getNumSamples() { - return sampledSpansQueue.size() + notSampledSpansQueue.size(); - } - } - - /** - * Keeps samples for a given span name. Samples for all the latency buckets and for all canonical - * codes other than OK. - */ - private static final class PerSpanNameSamples { - - private final Bucket[] latencyBuckets; - private final Bucket[] errorBuckets; - - private PerSpanNameSamples() { - latencyBuckets = new Bucket[NUM_LATENCY_BUCKETS]; - for (int i = 0; i < NUM_LATENCY_BUCKETS; i++) { - latencyBuckets[i] = new Bucket(NUM_SAMPLES_PER_LATENCY_BUCKET); - } - errorBuckets = new Bucket[NUM_ERROR_BUCKETS]; - for (int i = 0; i < NUM_ERROR_BUCKETS; i++) { - errorBuckets[i] = new Bucket(NUM_SAMPLES_PER_ERROR_BUCKET); - } - } - - @Nullable - private Bucket getLatencyBucket(long latencyNs) { - for (int i = 0; i < NUM_LATENCY_BUCKETS; i++) { - LatencyBucketBoundaries boundaries = LatencyBucketBoundaries.values()[i]; - if (latencyNs >= boundaries.getLatencyLowerNs() - && latencyNs < boundaries.getLatencyUpperNs()) { - return latencyBuckets[i]; - } - } - // latencyNs is negative or Long.MAX_VALUE, so this Span can be ignored. This cannot happen - // in real production because System#nanoTime is monotonic. - return null; - } - - private Bucket getErrorBucket(CanonicalCode code) { - return errorBuckets[code.value() - 1]; - } - - private void considerForSampling(SpanImpl span) { - Status status = span.getStatus(); - // Null status means running Span, this should not happen in production, but the library - // should not crash because of this. - if (status != null) { - Bucket bucket = - status.isOk() - ? getLatencyBucket(span.getLatencyNs()) - : getErrorBucket(status.getCanonicalCode()); - // If unable to find the bucket, ignore this Span. - if (bucket != null) { - bucket.considerForSampling(span); - } - } - } - - private Map getNumbersOfLatencySampledSpans() { - Map latencyBucketSummaries = - new EnumMap(LatencyBucketBoundaries.class); - for (int i = 0; i < NUM_LATENCY_BUCKETS; i++) { - latencyBucketSummaries.put( - LatencyBucketBoundaries.values()[i], latencyBuckets[i].getNumSamples()); - } - return latencyBucketSummaries; - } - - private Map getNumbersOfErrorSampledSpans() { - Map errorBucketSummaries = - new EnumMap(CanonicalCode.class); - for (int i = 0; i < NUM_ERROR_BUCKETS; i++) { - errorBucketSummaries.put(CanonicalCode.values()[i + 1], errorBuckets[i].getNumSamples()); - } - return errorBucketSummaries; - } - - private List getErrorSamples(@Nullable CanonicalCode code, int maxSpansToReturn) { - ArrayList output = new ArrayList(maxSpansToReturn); - if (code != null) { - getErrorBucket(code).getSamples(maxSpansToReturn, output); - } else { - for (int i = 0; i < NUM_ERROR_BUCKETS; i++) { - errorBuckets[i].getSamples(maxSpansToReturn, output); - } - } - return output; - } - - private List getLatencySamples( - long latencyLowerNs, long latencyUpperNs, int maxSpansToReturn) { - ArrayList output = new ArrayList(maxSpansToReturn); - for (int i = 0; i < NUM_LATENCY_BUCKETS; i++) { - LatencyBucketBoundaries boundaries = LatencyBucketBoundaries.values()[i]; - if (latencyUpperNs >= boundaries.getLatencyLowerNs() - && latencyLowerNs < boundaries.getLatencyUpperNs()) { - latencyBuckets[i].getSamplesFilteredByLatency( - latencyLowerNs, latencyUpperNs, maxSpansToReturn, output); - } - } - return output; - } - } - - /** Constructs a new {@code SampledSpanStoreImpl}. */ - SampledSpanStoreImpl(EventQueue eventQueue) { - samples = new HashMap(); - this.eventQueue = eventQueue; - } - - @Override - public Summary getSummary() { - Map ret = new HashMap(); - synchronized (samples) { - for (Map.Entry it : samples.entrySet()) { - ret.put( - it.getKey(), - PerSpanNameSummary.create( - it.getValue().getNumbersOfLatencySampledSpans(), - it.getValue().getNumbersOfErrorSampledSpans())); - } - } - return Summary.create(ret); + /** Returns the new no-op implmentation of {@link SampledSpanStoreImpl}. */ + public static SampledSpanStoreImpl getNoopSampledSpanStoreImpl() { + return NOOP_SAMPLED_SPAN_STORE_IMPL; } /** @@ -262,125 +43,41 @@ public final class SampledSpanStoreImpl extends SampledSpanStore { * * @param span the span to be consider for storing into the store buckets. */ - public void considerForSampling(SpanImpl span) { - synchronized (samples) { - String spanName = span.getName(); - if (span.getSampleToLocalSpanStore() && !samples.containsKey(spanName)) { - samples.put(spanName, new PerSpanNameSamples()); - } - PerSpanNameSamples perSpanNameSamples = samples.get(spanName); - if (perSpanNameSamples != null) { - perSpanNameSamples.considerForSampling(span); - } - } - } - - @Override - public void registerSpanNamesForCollection(Collection spanNames) { - eventQueue.enqueue(new RegisterSpanNameEvent(this, spanNames)); - } + public abstract void considerForSampling(SpanImpl span); - private void internaltRegisterSpanNamesForCollection(Collection spanNames) { - synchronized (samples) { - for (String spanName : spanNames) { - if (!samples.containsKey(spanName)) { - samples.put(spanName, new PerSpanNameSamples()); - } - } - } - } - - private static final class RegisterSpanNameEvent implements EventQueue.Entry { - private final SampledSpanStoreImpl sampledSpanStore; - private final Collection spanNames; - - private RegisterSpanNameEvent( - SampledSpanStoreImpl sampledSpanStore, Collection spanNames) { - this.sampledSpanStore = sampledSpanStore; - this.spanNames = new ArrayList(spanNames); - } + private static final class NoopSampledSpanStoreImpl extends SampledSpanStoreImpl { + private static final Summary EMPTY_SUMMARY = + Summary.create(Collections.emptyMap()); + private static final Set EMPTY_REGISTERED_SPAN_NAMES = Collections.emptySet(); + private static final Collection EMPTY_SPANDATA = Collections.emptySet(); @Override - public void process() { - sampledSpanStore.internaltRegisterSpanNamesForCollection(spanNames); + public Summary getSummary() { + return EMPTY_SUMMARY; } - } - @Override - public void unregisterSpanNamesForCollection(Collection spanNames) { - eventQueue.enqueue(new UnregisterSpanNameEvent(this, spanNames)); - } - - private void internalUnregisterSpanNamesForCollection(Collection spanNames) { - synchronized (samples) { - samples.keySet().removeAll(spanNames); - } - } - - private static final class UnregisterSpanNameEvent implements EventQueue.Entry { - private final SampledSpanStoreImpl sampledSpanStore; - private final Collection spanNames; + @Override + public void considerForSampling(SpanImpl span) {} - private UnregisterSpanNameEvent( - SampledSpanStoreImpl sampledSpanStore, Collection spanNames) { - this.sampledSpanStore = sampledSpanStore; - this.spanNames = new ArrayList(spanNames); - } + @Override + public void registerSpanNamesForCollection(Collection spanNames) {} @Override - public void process() { - sampledSpanStore.internalUnregisterSpanNamesForCollection(spanNames); - } - } + public void unregisterSpanNamesForCollection(Collection spanNames) {} - @Override - public Set getRegisteredSpanNamesForCollection() { - synchronized (samples) { - return Collections.unmodifiableSet(new HashSet(samples.keySet())); + @Override + public Set getRegisteredSpanNamesForCollection() { + return EMPTY_REGISTERED_SPAN_NAMES; } - } - @Override - public Collection getErrorSampledSpans(ErrorFilter filter) { - int numSpansToReturn = - filter.getMaxSpansToReturn() == 0 - ? MAX_PER_SPAN_NAME_SAMPLES - : filter.getMaxSpansToReturn(); - List spans = Collections.emptyList(); - // Try to not keep the lock to much, do the SpanImpl -> SpanData conversion outside the lock. - synchronized (samples) { - PerSpanNameSamples perSpanNameSamples = samples.get(filter.getSpanName()); - if (perSpanNameSamples != null) { - spans = perSpanNameSamples.getErrorSamples(filter.getCanonicalCode(), numSpansToReturn); - } - } - List ret = new ArrayList(spans.size()); - for (SpanImpl span : spans) { - ret.add(span.toSpanData()); + @Override + public Collection getErrorSampledSpans(ErrorFilter filter) { + return EMPTY_SPANDATA; } - return Collections.unmodifiableList(ret); - } - @Override - public Collection getLatencySampledSpans(LatencyFilter filter) { - int numSpansToReturn = - filter.getMaxSpansToReturn() == 0 - ? MAX_PER_SPAN_NAME_SAMPLES - : filter.getMaxSpansToReturn(); - List spans = Collections.emptyList(); - // Try to not keep the lock to much, do the SpanImpl -> SpanData conversion outside the lock. - synchronized (samples) { - PerSpanNameSamples perSpanNameSamples = samples.get(filter.getSpanName()); - if (perSpanNameSamples != null) { - spans = - perSpanNameSamples.getLatencySamples( - filter.getLatencyLowerNs(), filter.getLatencyUpperNs(), numSpansToReturn); - } - } - List ret = new ArrayList(spans.size()); - for (SpanImpl span : spans) { - ret.add(span.toSpanData()); + @Override + public Collection getLatencySampledSpans(LatencyFilter filter) { + return EMPTY_SPANDATA; } - return Collections.unmodifiableList(ret); } } -- cgit v1.2.3 From 131b6f062a68d91b4d7a06d1edc25d8e856b6a21 Mon Sep 17 00:00:00 2001 From: Hailong Wen Date: Fri, 16 Feb 2018 15:09:17 +0800 Subject: Add MessageEvent and deprecate NetworkEvent. (closes #858) (#894) --- .../java/io/opencensus/implcore/trace/SpanImpl.java | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) (limited to 'impl_core/src/main/java/io/opencensus/implcore/trace') diff --git a/impl_core/src/main/java/io/opencensus/implcore/trace/SpanImpl.java b/impl_core/src/main/java/io/opencensus/implcore/trace/SpanImpl.java index 8ce863e7..20dde75d 100644 --- a/impl_core/src/main/java/io/opencensus/implcore/trace/SpanImpl.java +++ b/impl_core/src/main/java/io/opencensus/implcore/trace/SpanImpl.java @@ -29,7 +29,6 @@ import io.opencensus.trace.Annotation; import io.opencensus.trace.AttributeValue; import io.opencensus.trace.EndSpanOptions; import io.opencensus.trace.Link; -import io.opencensus.trace.NetworkEvent; import io.opencensus.trace.Span; import io.opencensus.trace.SpanContext; import io.opencensus.trace.SpanId; @@ -50,6 +49,7 @@ import javax.annotation.Nullable; import javax.annotation.concurrent.GuardedBy; import javax.annotation.concurrent.ThreadSafe; +// TODO(hailongwen): remove the usage of `NetworkEvent` in the future. /** Implementation for the {@link Span} class. */ @ThreadSafe public final class SpanImpl extends Span implements Element { @@ -84,7 +84,8 @@ public final class SpanImpl extends Span implements Element { // List of recorded network events. @GuardedBy("this") @Nullable - private TraceEvents> networkEvents; + @SuppressWarnings("deprecation") + private TraceEvents> networkEvents; // List of recorded links to parent and child spans. @GuardedBy("this") @Nullable @@ -238,7 +239,8 @@ public final class SpanImpl extends Span implements Element { : SpanData.Attributes.create(attributes, attributes.getNumberOfDroppedAttributes()); SpanData.TimedEvents annotationsSpanData = createTimedEvents(getInitializedAnnotations(), timestampConverter); - SpanData.TimedEvents networkEventsSpanData = + @SuppressWarnings("deprecation") + SpanData.TimedEvents networkEventsSpanData = createTimedEvents(getInitializedNetworkEvents(), timestampConverter); SpanData.Links linksSpanData = links == null @@ -327,7 +329,8 @@ public final class SpanImpl extends Span implements Element { } @Override - public void addNetworkEvent(NetworkEvent networkEvent) { + @SuppressWarnings("deprecation") + public void addNetworkEvent(io.opencensus.trace.NetworkEvent networkEvent) { if (!getOptions().contains(Options.RECORD_EVENTS)) { return; } @@ -338,7 +341,7 @@ public final class SpanImpl extends Span implements Element { } getInitializedNetworkEvents() .addEvent( - new EventWithNanoTime( + new EventWithNanoTime( clock.nowNanos(), checkNotNull(networkEvent, "networkEvent"))); } } @@ -409,10 +412,12 @@ public final class SpanImpl extends Span implements Element { } @GuardedBy("this") - private TraceEvents> getInitializedNetworkEvents() { + @SuppressWarnings("deprecation") + private TraceEvents> + getInitializedNetworkEvents() { if (networkEvents == null) { networkEvents = - new TraceEvents>( + new TraceEvents>( traceParams.getMaxNumberOfNetworkEvents()); } return networkEvents; -- cgit v1.2.3 From f0e9b541d93cc3df67310aa47d12729824c31d5f Mon Sep 17 00:00:00 2001 From: Kristen Kozak Date: Wed, 21 Feb 2018 21:58:46 -0800 Subject: Add comments to boolean arguments to fix Error Prone warning (BooleanParameter). --- impl_core/src/main/java/io/opencensus/implcore/trace/SpanImpl.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'impl_core/src/main/java/io/opencensus/implcore/trace') diff --git a/impl_core/src/main/java/io/opencensus/implcore/trace/SpanImpl.java b/impl_core/src/main/java/io/opencensus/implcore/trace/SpanImpl.java index 20dde75d..f9a7f859 100644 --- a/impl_core/src/main/java/io/opencensus/implcore/trace/SpanImpl.java +++ b/impl_core/src/main/java/io/opencensus/implcore/trace/SpanImpl.java @@ -500,7 +500,7 @@ public final class SpanImpl extends Span implements Element { // Capacity of the map is capacity + 1 to avoid resizing because removeEldestEntry is invoked // by put and putAll after inserting a new entry into the map. The loadFactor is set to 1 // to avoid resizing because. The accessOrder is set to true. - super(capacity + 1, 1, true); + super(capacity + 1, 1, /*accessOrder=*/ true); this.capacity = capacity; } -- cgit v1.2.3 From 3683e6263dbbada41a9f8f72845c19222d05b4fc Mon Sep 17 00:00:00 2001 From: Hailong Wen Date: Wed, 21 Mar 2018 10:58:08 -0700 Subject: Substitute non-ascii characters in B3Format header key. (#1072) --- .../java/io/opencensus/implcore/trace/propagation/B3Format.java | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'impl_core/src/main/java/io/opencensus/implcore/trace') diff --git a/impl_core/src/main/java/io/opencensus/implcore/trace/propagation/B3Format.java b/impl_core/src/main/java/io/opencensus/implcore/trace/propagation/B3Format.java index c27234db..3a9f2420 100644 --- a/impl_core/src/main/java/io/opencensus/implcore/trace/propagation/B3Format.java +++ b/impl_core/src/main/java/io/opencensus/implcore/trace/propagation/B3Format.java @@ -34,10 +34,10 @@ import java.util.List; * href=https://github.com/openzipkin/b3-propagation>b3-propagation. */ final class B3Format extends TextFormat { - @VisibleForTesting static final String X_B3_TRACE_ID = "X─B3─TraceId"; - @VisibleForTesting static final String X_B3_SPAN_ID = "X─B3─SpanId"; - @VisibleForTesting static final String X_B3_PARENT_SPAN_ID = "X─B3─ParentSpanId"; - @VisibleForTesting static final String X_B3_SAMPLED = "X─B3─Sampled"; + @VisibleForTesting static final String X_B3_TRACE_ID = "X-B3-TraceId"; + @VisibleForTesting static final String X_B3_SPAN_ID = "X-B3-SpanId"; + @VisibleForTesting static final String X_B3_PARENT_SPAN_ID = "X-B3-ParentSpanId"; + @VisibleForTesting static final String X_B3_SAMPLED = "X-B3-Sampled"; @VisibleForTesting static final String X_B3_FLAGS = "X-B3-Flags"; private static final List FIELDS = Collections.unmodifiableList( -- cgit v1.2.3 From 1e09da2b34cce91cab3bd40290a0e16d60042afe Mon Sep 17 00:00:00 2001 From: Kristen Kozak Date: Tue, 3 Apr 2018 16:37:22 -0700 Subject: Add nullness annotations to Preconditions.checkNotNull. This commit also adds annotations to TextFormat that were required after the change in checkNotNull. --- .../io/opencensus/implcore/trace/propagation/B3Format.java | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) (limited to 'impl_core/src/main/java/io/opencensus/implcore/trace') diff --git a/impl_core/src/main/java/io/opencensus/implcore/trace/propagation/B3Format.java b/impl_core/src/main/java/io/opencensus/implcore/trace/propagation/B3Format.java index 3a9f2420..67c66ea9 100644 --- a/impl_core/src/main/java/io/opencensus/implcore/trace/propagation/B3Format.java +++ b/impl_core/src/main/java/io/opencensus/implcore/trace/propagation/B3Format.java @@ -29,6 +29,10 @@ import java.util.Arrays; import java.util.Collections; import java.util.List; +/*>>> +import org.checkerframework.checker.nullness.qual.NonNull; +*/ + /** * Implementation of the B3 propagation protocol. See b3-propagation. @@ -58,7 +62,8 @@ final class B3Format extends TextFormat { } @Override - public void inject(SpanContext spanContext, C carrier, Setter setter) { + public >> extends @NonNull Object*/> void inject( + SpanContext spanContext, C carrier, Setter setter) { checkNotNull(spanContext, "spanContext"); checkNotNull(setter, "setter"); checkNotNull(carrier, "carrier"); @@ -70,7 +75,8 @@ final class B3Format extends TextFormat { } @Override - public SpanContext extract(C carrier, Getter getter) throws SpanContextParseException { + public >> extends @NonNull Object*/> SpanContext extract(C carrier, Getter getter) + throws SpanContextParseException { checkNotNull(carrier, "carrier"); checkNotNull(getter, "getter"); try { -- cgit v1.2.3 From 04fa39bbb9c6e89218bea6634ade783795e6e450 Mon Sep 17 00:00:00 2001 From: Adrian Cole Date: Fri, 13 Apr 2018 18:31:13 +0800 Subject: Makes the trace and span ID fields mandatory in binary format (#1120) --- .../trace/propagation/BinaryFormatImpl.java | 73 +++++++++++++++------- 1 file changed, 51 insertions(+), 22 deletions(-) (limited to 'impl_core/src/main/java/io/opencensus/implcore/trace') diff --git a/impl_core/src/main/java/io/opencensus/implcore/trace/propagation/BinaryFormatImpl.java b/impl_core/src/main/java/io/opencensus/implcore/trace/propagation/BinaryFormatImpl.java index 8a4377d3..bb08222e 100644 --- a/impl_core/src/main/java/io/opencensus/implcore/trace/propagation/BinaryFormatImpl.java +++ b/impl_core/src/main/java/io/opencensus/implcore/trace/propagation/BinaryFormatImpl.java @@ -18,6 +18,7 @@ package io.opencensus.implcore.trace.propagation; import static com.google.common.base.Preconditions.checkNotNull; +import io.opencensus.internal.DefaultVisibilityForTesting; import io.opencensus.trace.SpanContext; import io.opencensus.trace.SpanId; import io.opencensus.trace.TraceId; @@ -65,21 +66,36 @@ final class BinaryFormatImpl extends BinaryFormat { // The version_id/field_id size in bytes. private static final byte ID_SIZE = 1; private static final byte TRACE_ID_FIELD_ID = 0; - private static final int TRACE_ID_FIELD_ID_OFFSET = VERSION_ID_OFFSET + ID_SIZE; + + // TODO: clarify if offsets are correct here. While the specification suggests you should stop + // parsing when you hit an unknown field, it does not suggest that fields must be declared in + // ID order. Rather it only groups by data type order, in this case Trace Context + // https://github.com/census-instrumentation/opencensus-specs/blob/master/encodings/BinaryEncoding.md#deserialization-rules + @DefaultVisibilityForTesting + static final int TRACE_ID_FIELD_ID_OFFSET = VERSION_ID_OFFSET + ID_SIZE; + private static final int TRACE_ID_OFFSET = TRACE_ID_FIELD_ID_OFFSET + ID_SIZE; private static final byte SPAN_ID_FIELD_ID = 1; - private static final int SPAN_ID_FIELD_ID_OFFSET = TRACE_ID_OFFSET + TraceId.SIZE; + + @DefaultVisibilityForTesting + static final int SPAN_ID_FIELD_ID_OFFSET = TRACE_ID_OFFSET + TraceId.SIZE; + private static final int SPAN_ID_OFFSET = SPAN_ID_FIELD_ID_OFFSET + ID_SIZE; private static final byte TRACE_OPTION_FIELD_ID = 2; - private static final int TRACE_OPTION_FIELD_ID_OFFSET = SPAN_ID_OFFSET + SpanId.SIZE; + + @DefaultVisibilityForTesting + static final int TRACE_OPTION_FIELD_ID_OFFSET = SPAN_ID_OFFSET + SpanId.SIZE; + private static final int TRACE_OPTIONS_OFFSET = TRACE_OPTION_FIELD_ID_OFFSET + ID_SIZE; - private static final int FORMAT_LENGTH = - 4 * ID_SIZE + TraceId.SIZE + SpanId.SIZE + TraceOptions.SIZE; + /** Version, Trace and Span IDs are required fields. */ + private static final int REQUIRED_FORMAT_LENGTH = 3 * ID_SIZE + TraceId.SIZE + SpanId.SIZE; + /** Use {@link TraceOptions#DEFAULT} unless its optional field is present. */ + private static final int ALL_FORMAT_LENGTH = REQUIRED_FORMAT_LENGTH + ID_SIZE + TraceOptions.SIZE; @Override public byte[] toByteArray(SpanContext spanContext) { checkNotNull(spanContext, "spanContext"); - byte[] bytes = new byte[FORMAT_LENGTH]; + byte[] bytes = new byte[ALL_FORMAT_LENGTH]; bytes[VERSION_ID_OFFSET] = VERSION_ID; bytes[TRACE_ID_FIELD_ID_OFFSET] = TRACE_ID_FIELD_ID; spanContext.getTraceId().copyBytesTo(bytes, TRACE_ID_OFFSET); @@ -96,25 +112,38 @@ final class BinaryFormatImpl extends BinaryFormat { if (bytes.length == 0 || bytes[0] != VERSION_ID) { throw new SpanContextParseException("Unsupported version."); } - TraceId traceId = TraceId.INVALID; - SpanId spanId = SpanId.INVALID; + if (bytes.length < REQUIRED_FORMAT_LENGTH) { + throw new SpanContextParseException("Invalid input: truncated"); + } + // TODO: the following logic assumes that fields are written in ID order. The spec does not say + // that. If it decides not to, this logic would need to be more like a loop + TraceId traceId; + SpanId spanId; TraceOptions traceOptions = TraceOptions.DEFAULT; int pos = 1; - try { - if (bytes.length > pos && bytes[pos] == TRACE_ID_FIELD_ID) { - traceId = TraceId.fromBytes(bytes, pos + ID_SIZE); - pos += ID_SIZE + TraceId.SIZE; - } - if (bytes.length > pos && bytes[pos] == SPAN_ID_FIELD_ID) { - spanId = SpanId.fromBytes(bytes, pos + ID_SIZE); - pos += ID_SIZE + SpanId.SIZE; - } - if (bytes.length > pos && bytes[pos] == TRACE_OPTION_FIELD_ID) { - traceOptions = TraceOptions.fromBytes(bytes, pos + ID_SIZE); + if (bytes[pos] == TRACE_ID_FIELD_ID) { + traceId = TraceId.fromBytes(bytes, pos + ID_SIZE); + pos += ID_SIZE + TraceId.SIZE; + } else { + // TODO: update the spec to suggest that the trace ID is not actually optional + throw new SpanContextParseException("Invalid input: expected trace ID at offset " + pos); + } + if (bytes[pos] == SPAN_ID_FIELD_ID) { + spanId = SpanId.fromBytes(bytes, pos + ID_SIZE); + pos += ID_SIZE + SpanId.SIZE; + } else { + // TODO: update the spec to suggest that the span ID is not actually optional. + throw new SpanContextParseException("Invalid input: expected span ID at offset " + pos); + } + // Check to see if we are long enough to include an options field, and also that the next field + // is an options field. Per spec we simply stop parsing at first unknown field instead of + // failing. + if (bytes.length > pos && bytes[pos] == TRACE_OPTION_FIELD_ID) { + if (bytes.length < ALL_FORMAT_LENGTH) { + throw new SpanContextParseException("Invalid input: truncated"); } - return SpanContext.create(traceId, spanId, traceOptions); - } catch (IndexOutOfBoundsException e) { - throw new SpanContextParseException("Invalid input.", e); + traceOptions = TraceOptions.fromBytes(bytes, pos + ID_SIZE); } + return SpanContext.create(traceId, spanId, traceOptions); } } -- cgit v1.2.3 From 3e4352b3684b4646a82eef4f2da66038531d821e Mon Sep 17 00:00:00 2001 From: Yang Song Date: Mon, 16 Apr 2018 12:13:59 -0700 Subject: Move toMillis(Duration) to Utils so that it can be reused. (#1114) * Add toMillis() method to TimeUtils. * Reuse toMillis() method in impl and exporters. * Add a note about overflow and precision loss. * Move toMillis() to Duration. --- .../java/io/opencensus/implcore/trace/export/SpanExporterImpl.java | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) (limited to 'impl_core/src/main/java/io/opencensus/implcore/trace') diff --git a/impl_core/src/main/java/io/opencensus/implcore/trace/export/SpanExporterImpl.java b/impl_core/src/main/java/io/opencensus/implcore/trace/export/SpanExporterImpl.java index e5973c0b..c8ed237d 100644 --- a/impl_core/src/main/java/io/opencensus/implcore/trace/export/SpanExporterImpl.java +++ b/impl_core/src/main/java/io/opencensus/implcore/trace/export/SpanExporterImpl.java @@ -28,7 +28,6 @@ import java.util.Collections; import java.util.List; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.TimeUnit; import java.util.logging.Level; import java.util.logging.Logger; import javax.annotation.concurrent.GuardedBy; @@ -146,9 +145,7 @@ public final class SpanExporterImpl extends SpanExporter { private Worker(int bufferSize, Duration scheduleDelay) { spans = new ArrayList(bufferSize); this.bufferSize = bufferSize; - this.scheduleDelayMillis = - TimeUnit.SECONDS.toMillis(scheduleDelay.getSeconds()) - + TimeUnit.NANOSECONDS.toMillis(scheduleDelay.getNanos()); + this.scheduleDelayMillis = Duration.toMillis(scheduleDelay); } // Returns an unmodifiable list of all buffered spans data to ensure that any registered -- cgit v1.2.3 From 74d1f5dbaad7d24282edfaa95c6780bbe8191a98 Mon Sep 17 00:00:00 2001 From: Yang Song Date: Mon, 16 Apr 2018 14:38:01 -0700 Subject: Improve Duration.toMillis() (#1132) * Improve java doc for toMillis(). * Make toMillis() non-static. --- .../main/java/io/opencensus/implcore/trace/export/SpanExporterImpl.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'impl_core/src/main/java/io/opencensus/implcore/trace') diff --git a/impl_core/src/main/java/io/opencensus/implcore/trace/export/SpanExporterImpl.java b/impl_core/src/main/java/io/opencensus/implcore/trace/export/SpanExporterImpl.java index c8ed237d..e702d38c 100644 --- a/impl_core/src/main/java/io/opencensus/implcore/trace/export/SpanExporterImpl.java +++ b/impl_core/src/main/java/io/opencensus/implcore/trace/export/SpanExporterImpl.java @@ -145,7 +145,7 @@ public final class SpanExporterImpl extends SpanExporter { private Worker(int bufferSize, Duration scheduleDelay) { spans = new ArrayList(bufferSize); this.bufferSize = bufferSize; - this.scheduleDelayMillis = Duration.toMillis(scheduleDelay); + this.scheduleDelayMillis = scheduleDelay.toMillis(); } // Returns an unmodifiable list of all buffered spans data to ensure that any registered -- cgit v1.2.3 From 7ca65408da7ac6d9f3f4ce55ee2471091365ff97 Mon Sep 17 00:00:00 2001 From: Kristen Kozak Date: Tue, 17 Apr 2018 19:57:22 -0700 Subject: Remove dependency between io.opencensus.implcore and io.opencensus.internal. io.opencensus.internal should only be accessed by the API library. --- .../implcore/trace/propagation/BinaryFormatImpl.java | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) (limited to 'impl_core/src/main/java/io/opencensus/implcore/trace') diff --git a/impl_core/src/main/java/io/opencensus/implcore/trace/propagation/BinaryFormatImpl.java b/impl_core/src/main/java/io/opencensus/implcore/trace/propagation/BinaryFormatImpl.java index bb08222e..a2438008 100644 --- a/impl_core/src/main/java/io/opencensus/implcore/trace/propagation/BinaryFormatImpl.java +++ b/impl_core/src/main/java/io/opencensus/implcore/trace/propagation/BinaryFormatImpl.java @@ -18,7 +18,7 @@ package io.opencensus.implcore.trace.propagation; import static com.google.common.base.Preconditions.checkNotNull; -import io.opencensus.internal.DefaultVisibilityForTesting; +import com.google.common.annotations.VisibleForTesting; import io.opencensus.trace.SpanContext; import io.opencensus.trace.SpanId; import io.opencensus.trace.TraceId; @@ -71,20 +71,17 @@ final class BinaryFormatImpl extends BinaryFormat { // parsing when you hit an unknown field, it does not suggest that fields must be declared in // ID order. Rather it only groups by data type order, in this case Trace Context // https://github.com/census-instrumentation/opencensus-specs/blob/master/encodings/BinaryEncoding.md#deserialization-rules - @DefaultVisibilityForTesting - static final int TRACE_ID_FIELD_ID_OFFSET = VERSION_ID_OFFSET + ID_SIZE; + @VisibleForTesting static final int TRACE_ID_FIELD_ID_OFFSET = VERSION_ID_OFFSET + ID_SIZE; private static final int TRACE_ID_OFFSET = TRACE_ID_FIELD_ID_OFFSET + ID_SIZE; private static final byte SPAN_ID_FIELD_ID = 1; - @DefaultVisibilityForTesting - static final int SPAN_ID_FIELD_ID_OFFSET = TRACE_ID_OFFSET + TraceId.SIZE; + @VisibleForTesting static final int SPAN_ID_FIELD_ID_OFFSET = TRACE_ID_OFFSET + TraceId.SIZE; private static final int SPAN_ID_OFFSET = SPAN_ID_FIELD_ID_OFFSET + ID_SIZE; private static final byte TRACE_OPTION_FIELD_ID = 2; - @DefaultVisibilityForTesting - static final int TRACE_OPTION_FIELD_ID_OFFSET = SPAN_ID_OFFSET + SpanId.SIZE; + @VisibleForTesting static final int TRACE_OPTION_FIELD_ID_OFFSET = SPAN_ID_OFFSET + SpanId.SIZE; private static final int TRACE_OPTIONS_OFFSET = TRACE_OPTION_FIELD_ID_OFFSET + ID_SIZE; /** Version, Trace and Span IDs are required fields. */ -- cgit v1.2.3 From 610ff80ebec2b831a7ea6cc73ad4614152a36ad9 Mon Sep 17 00:00:00 2001 From: dvfeinblum Date: Tue, 24 Apr 2018 21:48:51 -0400 Subject: Added null checking to Span implementations (#1150) This PR adds null checking to classes that implement Span. Specifically, - BlankSpan - NoopSpan - Span - SpanImpl For the latter, I had to use Preconditions.checkNotNull because io.opencensus.internal shouldn't be imported into ImplCore. --- .../main/java/io/opencensus/implcore/trace/SpanImpl.java | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) (limited to 'impl_core/src/main/java/io/opencensus/implcore/trace') diff --git a/impl_core/src/main/java/io/opencensus/implcore/trace/SpanImpl.java b/impl_core/src/main/java/io/opencensus/implcore/trace/SpanImpl.java index f9a7f859..81b27e32 100644 --- a/impl_core/src/main/java/io/opencensus/implcore/trace/SpanImpl.java +++ b/impl_core/src/main/java/io/opencensus/implcore/trace/SpanImpl.java @@ -20,6 +20,7 @@ import static com.google.common.base.Preconditions.checkNotNull; import static com.google.common.base.Preconditions.checkState; import com.google.common.annotations.VisibleForTesting; +import com.google.common.base.Preconditions; import com.google.common.collect.EvictingQueue; import io.opencensus.common.Clock; import io.opencensus.implcore.internal.CheckerFrameworkUtils; @@ -281,6 +282,7 @@ public final class SpanImpl extends Span implements Element { @Override public void putAttributes(Map attributes) { + Preconditions.checkNotNull(attributes, "attributes"); if (!getOptions().contains(Options.RECORD_EVENTS)) { return; } @@ -295,6 +297,8 @@ public final class SpanImpl extends Span implements Element { @Override public void addAnnotation(String description, Map attributes) { + Preconditions.checkNotNull(description, "description"); + Preconditions.checkNotNull(attributes, "attribute"); if (!getOptions().contains(Options.RECORD_EVENTS)) { return; } @@ -313,6 +317,7 @@ public final class SpanImpl extends Span implements Element { @Override public void addAnnotation(Annotation annotation) { + Preconditions.checkNotNull(annotation, "annotation"); if (!getOptions().contains(Options.RECORD_EVENTS)) { return; } @@ -322,9 +327,7 @@ public final class SpanImpl extends Span implements Element { return; } getInitializedAnnotations() - .addEvent( - new EventWithNanoTime( - clock.nowNanos(), checkNotNull(annotation, "annotation"))); + .addEvent(new EventWithNanoTime(clock.nowNanos(), annotation)); } } @@ -348,6 +351,7 @@ public final class SpanImpl extends Span implements Element { @Override public void addLink(Link link) { + Preconditions.checkNotNull(link, "link"); if (!getOptions().contains(Options.RECORD_EVENTS)) { return; } @@ -356,12 +360,13 @@ public final class SpanImpl extends Span implements Element { logger.log(Level.FINE, "Calling addLink() on an ended Span."); return; } - getInitializedLinks().addEvent(checkNotNull(link, "link")); + getInitializedLinks().addEvent(link); } } @Override public void setStatus(Status status) { + Preconditions.checkNotNull(status, "status"); if (!getOptions().contains(Options.RECORD_EVENTS)) { return; } -- cgit v1.2.3 From 05f5bdd7c1628a3e434542fa2af1ab2b5ccf20ce Mon Sep 17 00:00:00 2001 From: Kristen Kozak Date: Fri, 27 Apr 2018 13:08:48 -0700 Subject: Check for null in more public methods in Span and its subclasses. --- impl_core/src/main/java/io/opencensus/implcore/trace/SpanImpl.java | 3 +++ 1 file changed, 3 insertions(+) (limited to 'impl_core/src/main/java/io/opencensus/implcore/trace') diff --git a/impl_core/src/main/java/io/opencensus/implcore/trace/SpanImpl.java b/impl_core/src/main/java/io/opencensus/implcore/trace/SpanImpl.java index 81b27e32..59291685 100644 --- a/impl_core/src/main/java/io/opencensus/implcore/trace/SpanImpl.java +++ b/impl_core/src/main/java/io/opencensus/implcore/trace/SpanImpl.java @@ -268,6 +268,8 @@ public final class SpanImpl extends Span implements Element { @Override public void putAttribute(String key, AttributeValue value) { + Preconditions.checkNotNull(key, "key"); + Preconditions.checkNotNull(value, "value"); if (!getOptions().contains(Options.RECORD_EVENTS)) { return; } @@ -381,6 +383,7 @@ public final class SpanImpl extends Span implements Element { @Override public void end(EndSpanOptions options) { + Preconditions.checkNotNull(options, "options"); if (!getOptions().contains(Options.RECORD_EVENTS)) { return; } -- cgit v1.2.3 From 83fd63784edaed486e43be5570549143375fdefc Mon Sep 17 00:00:00 2001 From: Chris K Wensel Date: Fri, 11 May 2018 17:22:35 -0700 Subject: Adds Tracing.getExportComponent().flushAndShutdown() for use within application shutdown hooks. (#1141) Adds the ability to flush pending spans via a call to Tracing.getExportComponent().shutdown() This allows a developer to force a flush from within a shutdown hook or other means. Unfortunately the underlying Disruptor instance only provides a #shutdown() call, not a flush, or a public method for testing for backlog. Thus shutdown has propagated up to the above api call. --- .../implcore/trace/export/ExportComponentImpl.java | 6 ++++++ .../export/InProcessSampledSpanStoreImpl.java | 5 +++++ .../trace/export/SampledSpanStoreImpl.java | 2 ++ .../implcore/trace/export/SpanExporterImpl.java | 22 ++++++++++++++++++++++ 4 files changed, 35 insertions(+) (limited to 'impl_core/src/main/java/io/opencensus/implcore/trace') diff --git a/impl_core/src/main/java/io/opencensus/implcore/trace/export/ExportComponentImpl.java b/impl_core/src/main/java/io/opencensus/implcore/trace/export/ExportComponentImpl.java index e77d1f8e..19817380 100644 --- a/impl_core/src/main/java/io/opencensus/implcore/trace/export/ExportComponentImpl.java +++ b/impl_core/src/main/java/io/opencensus/implcore/trace/export/ExportComponentImpl.java @@ -47,6 +47,12 @@ public final class ExportComponentImpl extends ExportComponent { return sampledSpanStore; } + @Override + public void shutdown() { + sampledSpanStore.shutdown(); + spanExporter.shutdown(); + } + /** * Returns a new {@code ExportComponentImpl} that has valid instances for {@link RunningSpanStore} * and {@link SampledSpanStore}. diff --git a/impl_core/src/main/java/io/opencensus/implcore/trace/export/InProcessSampledSpanStoreImpl.java b/impl_core/src/main/java/io/opencensus/implcore/trace/export/InProcessSampledSpanStoreImpl.java index 1bdb3f41..fe0132d8 100644 --- a/impl_core/src/main/java/io/opencensus/implcore/trace/export/InProcessSampledSpanStoreImpl.java +++ b/impl_core/src/main/java/io/opencensus/implcore/trace/export/InProcessSampledSpanStoreImpl.java @@ -275,6 +275,11 @@ public final class InProcessSampledSpanStoreImpl extends SampledSpanStoreImpl { eventQueue.enqueue(new RegisterSpanNameEvent(this, spanNames)); } + @Override + protected void shutdown() { + eventQueue.shutdown(); + } + private void internaltRegisterSpanNamesForCollection(Collection spanNames) { synchronized (samples) { for (String spanName : spanNames) { diff --git a/impl_core/src/main/java/io/opencensus/implcore/trace/export/SampledSpanStoreImpl.java b/impl_core/src/main/java/io/opencensus/implcore/trace/export/SampledSpanStoreImpl.java index 0c83a05a..302d5cd3 100644 --- a/impl_core/src/main/java/io/opencensus/implcore/trace/export/SampledSpanStoreImpl.java +++ b/impl_core/src/main/java/io/opencensus/implcore/trace/export/SampledSpanStoreImpl.java @@ -45,6 +45,8 @@ public abstract class SampledSpanStoreImpl extends SampledSpanStore { */ public abstract void considerForSampling(SpanImpl span); + protected void shutdown() {} + private static final class NoopSampledSpanStoreImpl extends SampledSpanStoreImpl { private static final Summary EMPTY_SUMMARY = Summary.create(Collections.emptyMap()); diff --git a/impl_core/src/main/java/io/opencensus/implcore/trace/export/SpanExporterImpl.java b/impl_core/src/main/java/io/opencensus/implcore/trace/export/SpanExporterImpl.java index e702d38c..12940739 100644 --- a/impl_core/src/main/java/io/opencensus/implcore/trace/export/SpanExporterImpl.java +++ b/impl_core/src/main/java/io/opencensus/implcore/trace/export/SpanExporterImpl.java @@ -74,6 +74,15 @@ public final class SpanExporterImpl extends SpanExporter { worker.unregisterHandler(name); } + protected void flush() { + worker.flush(); + } + + protected void shutdown() { + flush(); + workerThread.interrupt(); + } + private SpanExporterImpl(Worker worker) { this.workerThread = new DaemonThreadFactory("ExportComponent.ServiceExporterThread").newThread(worker); @@ -188,5 +197,18 @@ public final class SpanExporterImpl extends SpanExporter { } } } + + void flush() { + List spansCopy; + synchronized (monitor) { + spansCopy = new ArrayList(spans); + spans.clear(); + } + + final List spanDataList = fromSpanImplToSpanData(spansCopy); + if (!spanDataList.isEmpty()) { + onBatchExport(spanDataList); + } + } } } -- cgit v1.2.3 From 55c12779e8a17e0d3d3e88480a01857f051cae55 Mon Sep 17 00:00:00 2001 From: Bogdan Drutu Date: Thu, 31 May 2018 18:56:17 -0700 Subject: Add Span.Kind to the trace API. (#1223) * Add Span.Kind to the trace API. * Add @Nullable annotation where needed. * Add changes to changelog. --- .../io/opencensus/implcore/trace/SpanBuilderImpl.java | 11 +++++++++++ .../java/io/opencensus/implcore/trace/SpanImpl.java | 17 +++++++++++++++++ 2 files changed, 28 insertions(+) (limited to 'impl_core/src/main/java/io/opencensus/implcore/trace') 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 index 45cf4261..f5d74393 100644 --- a/impl_core/src/main/java/io/opencensus/implcore/trace/SpanBuilderImpl.java +++ b/impl_core/src/main/java/io/opencensus/implcore/trace/SpanBuilderImpl.java @@ -25,6 +25,7 @@ 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; @@ -48,6 +49,7 @@ final class SpanBuilderImpl extends SpanBuilder { @Nullable private Sampler sampler; private List parentLinks = Collections.emptyList(); @Nullable private Boolean recordEvents; + @Nullable private Kind kind; private SpanImpl startSpanInternal( @Nullable SpanContext parent, @@ -56,6 +58,7 @@ final class SpanBuilderImpl extends SpanBuilder { @Nullable Sampler sampler, List parentLinks, @Nullable Boolean recordEvents, + @Nullable Kind kind, @Nullable TimestampConverter timestampConverter) { TraceParams activeTraceParams = options.traceConfig.getActiveTraceParams(); Random random = options.randomHandler.current(); @@ -95,6 +98,7 @@ final class SpanBuilderImpl extends SpanBuilder { SpanContext.create(traceId, spanId, traceOptions), spanOptions, name, + kind, parentSpanId, hasRemoteParent, activeTraceParams, @@ -196,6 +200,7 @@ final class SpanBuilderImpl extends SpanBuilder { sampler, parentLinks, recordEvents, + kind, timestampConverter); } @@ -234,4 +239,10 @@ final class SpanBuilderImpl extends SpanBuilder { this.recordEvents = recordEvents; return this; } + + @Override + public SpanBuilderImpl setSpanKind(Kind kind) { + this.kind = kind; + return this; + } } diff --git a/impl_core/src/main/java/io/opencensus/implcore/trace/SpanImpl.java b/impl_core/src/main/java/io/opencensus/implcore/trace/SpanImpl.java index 59291685..75509a7f 100644 --- a/impl_core/src/main/java/io/opencensus/implcore/trace/SpanImpl.java +++ b/impl_core/src/main/java/io/opencensus/implcore/trace/SpanImpl.java @@ -66,6 +66,8 @@ public final class SpanImpl extends Span implements Element { private final StartEndHandler startEndHandler; // The displayed name of the span. private final String name; + // The kind of the span. + @Nullable private final Kind kind; // The clock used to get the time. private final Clock clock; // The time converter used to convert nano time to Timestamp. This is needed because Java has @@ -132,6 +134,7 @@ public final class SpanImpl extends Span implements Element { SpanContext context, @Nullable EnumSet options, String name, + @Nullable Kind kind, @Nullable SpanId parentSpanId, @Nullable Boolean hasRemoteParent, TraceParams traceParams, @@ -143,6 +146,7 @@ public final class SpanImpl extends Span implements Element { context, options, name, + kind, parentSpanId, hasRemoteParent, traceParams, @@ -213,6 +217,16 @@ public final class SpanImpl extends Span implements Element { } } + /** + * Returns the kind of this {@code Span}. + * + * @return the kind of this {@code Span}. + */ + @Nullable + public Kind getKind() { + return kind; + } + /** * Returns the {@code TimestampConverter} used by this {@code Span}. * @@ -253,6 +267,7 @@ public final class SpanImpl extends Span implements Element { parentSpanId, hasRemoteParent, name, + kind, CheckerFrameworkUtils.castNonNull(timestampConverter).convertNanoTime(startNanoTime), attributesSpanData, annotationsSpanData, @@ -575,6 +590,7 @@ public final class SpanImpl extends Span implements Element { SpanContext context, @Nullable EnumSet options, String name, + @Nullable Kind kind, @Nullable SpanId parentSpanId, @Nullable Boolean hasRemoteParent, TraceParams traceParams, @@ -585,6 +601,7 @@ public final class SpanImpl extends Span implements Element { this.parentSpanId = parentSpanId; this.hasRemoteParent = hasRemoteParent; this.name = name; + this.kind = kind; this.traceParams = traceParams; this.startEndHandler = startEndHandler; this.clock = clock; -- cgit v1.2.3 From 8939d9fd639a8a7ff8b25e1a7e6c44d8b2e987db Mon Sep 17 00:00:00 2001 From: sebright Date: Wed, 1 Aug 2018 16:34:05 -0700 Subject: Fix incorrect argument to Checker Framework, and fix nullness warnings. (#1354) 709d97aa321d5729988fd63b960bbece04cfba10 modified the -AskipDefs argument to the Checker Framework (a regular expression) in a way that caused it to skip checking all files. This commit fixes the regular expression and the new Checker Framework warnings. --- .../src/main/java/io/opencensus/implcore/trace/SpanBuilderImpl.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'impl_core/src/main/java/io/opencensus/implcore/trace') 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 index f5d74393..3c5f20c6 100644 --- a/impl_core/src/main/java/io/opencensus/implcore/trace/SpanBuilderImpl.java +++ b/impl_core/src/main/java/io/opencensus/implcore/trace/SpanBuilderImpl.java @@ -241,7 +241,7 @@ final class SpanBuilderImpl extends SpanBuilder { } @Override - public SpanBuilderImpl setSpanKind(Kind kind) { + public SpanBuilderImpl setSpanKind(@Nullable Kind kind) { this.kind = kind; return this; } -- cgit v1.2.3 From a77396ddb5dcc2ea48d1b2eb90890f59e8e4d9f4 Mon Sep 17 00:00:00 2001 From: Bogdan Drutu Date: Wed, 8 Aug 2018 01:58:30 +0300 Subject: Remove protected method from final class. (#1363) --- .../java/io/opencensus/implcore/trace/export/SpanExporterImpl.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'impl_core/src/main/java/io/opencensus/implcore/trace') diff --git a/impl_core/src/main/java/io/opencensus/implcore/trace/export/SpanExporterImpl.java b/impl_core/src/main/java/io/opencensus/implcore/trace/export/SpanExporterImpl.java index 12940739..b9b1e98c 100644 --- a/impl_core/src/main/java/io/opencensus/implcore/trace/export/SpanExporterImpl.java +++ b/impl_core/src/main/java/io/opencensus/implcore/trace/export/SpanExporterImpl.java @@ -74,11 +74,11 @@ public final class SpanExporterImpl extends SpanExporter { worker.unregisterHandler(name); } - protected void flush() { + void flush() { worker.flush(); } - protected void shutdown() { + void shutdown() { flush(); workerThread.interrupt(); } -- cgit v1.2.3 From 52f38e48e2ac6cb65e28dcd97b4f7e9650357bba Mon Sep 17 00:00:00 2001 From: Bogdan Drutu Date: Thu, 9 Aug 2018 10:09:28 -0700 Subject: Add Tracestate into SpanContext. (#1359) * Add Tracestate into SpanContext. * Remove empty constructor from Tracestate.Builder * Add info in the changelog. --- .../main/java/io/opencensus/implcore/trace/SpanBuilderImpl.java | 9 +++++++-- .../java/io/opencensus/implcore/trace/propagation/B3Format.java | 4 +++- .../opencensus/implcore/trace/propagation/BinaryFormatImpl.java | 4 +++- 3 files changed, 13 insertions(+), 4 deletions(-) (limited to 'impl_core/src/main/java/io/opencensus/implcore/trace') 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 index 3c5f20c6..d4f7c347 100644 --- a/impl_core/src/main/java/io/opencensus/implcore/trace/SpanBuilderImpl.java +++ b/impl_core/src/main/java/io/opencensus/implcore/trace/SpanBuilderImpl.java @@ -31,6 +31,7 @@ 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; @@ -41,8 +42,9 @@ import javax.annotation.Nullable; /** Implementation of the {@link SpanBuilder}. */ final class SpanBuilderImpl extends SpanBuilder { - private final Options options; + private static final Tracestate TRACESTATE_DEFAULT = Tracestate.builder().build(); + private final Options options; private final String name; @Nullable private final Span parent; @Nullable private final SpanContext remoteParentSpanContext; @@ -66,6 +68,8 @@ final class SpanBuilderImpl extends SpanBuilder { SpanId spanId = SpanId.generateRandomId(random); SpanId parentSpanId = null; TraceOptions.Builder traceOptionsBuilder; + // TODO(bdrutu): Handle tracestate correctly not just propagate. + Tracestate tracestate = TRACESTATE_DEFAULT; if (parent == null || !parent.isValid()) { // New root span. traceId = TraceId.generateRandomId(random); @@ -77,6 +81,7 @@ final class SpanBuilderImpl extends SpanBuilder { traceId = parent.getTraceId(); parentSpanId = parent.getSpanId(); traceOptionsBuilder = TraceOptions.builder(parent.getTraceOptions()); + tracestate = parent.getTracestate(); } traceOptionsBuilder.setIsSampled( makeSamplingDecision( @@ -95,7 +100,7 @@ final class SpanBuilderImpl extends SpanBuilder { } SpanImpl span = SpanImpl.startSpan( - SpanContext.create(traceId, spanId, traceOptions), + SpanContext.create(traceId, spanId, traceOptions, tracestate), spanOptions, name, kind, diff --git a/impl_core/src/main/java/io/opencensus/implcore/trace/propagation/B3Format.java b/impl_core/src/main/java/io/opencensus/implcore/trace/propagation/B3Format.java index 67c66ea9..d928d93c 100644 --- a/impl_core/src/main/java/io/opencensus/implcore/trace/propagation/B3Format.java +++ b/impl_core/src/main/java/io/opencensus/implcore/trace/propagation/B3Format.java @@ -23,6 +23,7 @@ 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.propagation.SpanContextParseException; import io.opencensus.trace.propagation.TextFormat; import java.util.Arrays; @@ -38,6 +39,7 @@ import org.checkerframework.checker.nullness.qual.NonNull; * href=https://github.com/openzipkin/b3-propagation>b3-propagation. */ final class B3Format extends TextFormat { + private static final Tracestate TRACESTATE_DEFAULT = Tracestate.builder().build(); @VisibleForTesting static final String X_B3_TRACE_ID = "X-B3-TraceId"; @VisibleForTesting static final String X_B3_SPAN_ID = "X-B3-SpanId"; @VisibleForTesting static final String X_B3_PARENT_SPAN_ID = "X-B3-ParentSpanId"; @@ -103,7 +105,7 @@ final class B3Format extends TextFormat { || FLAGS_VALUE.equals(getter.get(carrier, X_B3_FLAGS))) { traceOptions = TraceOptions.builder().setIsSampled(true).build(); } - return SpanContext.create(traceId, spanId, traceOptions); + return SpanContext.create(traceId, spanId, traceOptions, TRACESTATE_DEFAULT); } catch (IllegalArgumentException e) { throw new SpanContextParseException("Invalid input.", e); } diff --git a/impl_core/src/main/java/io/opencensus/implcore/trace/propagation/BinaryFormatImpl.java b/impl_core/src/main/java/io/opencensus/implcore/trace/propagation/BinaryFormatImpl.java index a2438008..1af24854 100644 --- a/impl_core/src/main/java/io/opencensus/implcore/trace/propagation/BinaryFormatImpl.java +++ b/impl_core/src/main/java/io/opencensus/implcore/trace/propagation/BinaryFormatImpl.java @@ -23,6 +23,7 @@ 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.propagation.BinaryFormat; import io.opencensus.trace.propagation.SpanContextParseException; @@ -61,6 +62,7 @@ import io.opencensus.trace.propagation.SpanContextParseException; * */ final class BinaryFormatImpl extends BinaryFormat { + private static final Tracestate TRACESTATE_DEFAULT = Tracestate.builder().build(); private static final byte VERSION_ID = 0; private static final int VERSION_ID_OFFSET = 0; // The version_id/field_id size in bytes. @@ -141,6 +143,6 @@ final class BinaryFormatImpl extends BinaryFormat { } traceOptions = TraceOptions.fromBytes(bytes, pos + ID_SIZE); } - return SpanContext.create(traceId, spanId, traceOptions); + return SpanContext.create(traceId, spanId, traceOptions, TRACESTATE_DEFAULT); } } -- cgit v1.2.3 From 8901e4eb583785efaa2c3adea882d850662d93fc Mon Sep 17 00:00:00 2001 From: Bogdan Drutu Date: Mon, 27 Aug 2018 15:40:12 -0700 Subject: Add get/from{Byte} methods on TraceOptions and deprecate get/from{Bytes}. (#1392) * Add get/from{Byte} methods on TraceOptions and deprecate get/from{Bytes}. * Update changelog. --- .../java/io/opencensus/implcore/trace/propagation/BinaryFormatImpl.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'impl_core/src/main/java/io/opencensus/implcore/trace') diff --git a/impl_core/src/main/java/io/opencensus/implcore/trace/propagation/BinaryFormatImpl.java b/impl_core/src/main/java/io/opencensus/implcore/trace/propagation/BinaryFormatImpl.java index 1af24854..233fbd31 100644 --- a/impl_core/src/main/java/io/opencensus/implcore/trace/propagation/BinaryFormatImpl.java +++ b/impl_core/src/main/java/io/opencensus/implcore/trace/propagation/BinaryFormatImpl.java @@ -141,7 +141,7 @@ final class BinaryFormatImpl extends BinaryFormat { if (bytes.length < ALL_FORMAT_LENGTH) { throw new SpanContextParseException("Invalid input: truncated"); } - traceOptions = TraceOptions.fromBytes(bytes, pos + ID_SIZE); + traceOptions = TraceOptions.fromByte(bytes[pos + ID_SIZE]); } return SpanContext.create(traceId, spanId, traceOptions, TRACESTATE_DEFAULT); } -- cgit v1.2.3 From 0c988a28144199450fa21ef55ddcac8c2c9323bc Mon Sep 17 00:00:00 2001 From: Bogdan Drutu Date: Fri, 21 Sep 2018 09:31:20 -0700 Subject: Avoid 3 allocs, one builders and two objects when startSpan. (#1466) --- .../opencensus/implcore/trace/SpanBuilderImpl.java | 42 +++++++++++++--------- 1 file changed, 25 insertions(+), 17 deletions(-) (limited to 'impl_core/src/main/java/io/opencensus/implcore/trace') 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 index d4f7c347..3ea0ce33 100644 --- a/impl_core/src/main/java/io/opencensus/implcore/trace/SpanBuilderImpl.java +++ b/impl_core/src/main/java/io/opencensus/implcore/trace/SpanBuilderImpl.java @@ -44,6 +44,16 @@ import javax.annotation.Nullable; 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 static final EnumSet NOT_RECORD_EVENTS_SPAN_OPTIONS = + EnumSet.noneOf(Span.Options.class); + private static final EnumSet RECORD_EVENTS_SPAN_OPTIONS = + EnumSet.of(Span.Options.RECORD_EVENTS); + private final Options options; private final String name; @Nullable private final Span parent; @@ -67,37 +77,35 @@ final class SpanBuilderImpl extends SpanBuilder { TraceId traceId; SpanId spanId = SpanId.generateRandomId(random); SpanId parentSpanId = null; - TraceOptions.Builder traceOptionsBuilder; // TODO(bdrutu): Handle tracestate correctly not just propagate. Tracestate tracestate = TRACESTATE_DEFAULT; if (parent == null || !parent.isValid()) { // New root span. traceId = TraceId.generateRandomId(random); - traceOptionsBuilder = TraceOptions.builder(); // This is a root span so no remote or local parent. hasRemoteParent = null; } else { // New child span. traceId = parent.getTraceId(); parentSpanId = parent.getSpanId(); - traceOptionsBuilder = TraceOptions.builder(parent.getTraceOptions()); tracestate = parent.getTracestate(); } - traceOptionsBuilder.setIsSampled( + TraceOptions traceOptions = makeSamplingDecision( - parent, - hasRemoteParent, - name, - sampler, - parentLinks, - traceId, - spanId, - activeTraceParams)); - TraceOptions traceOptions = traceOptionsBuilder.build(); - EnumSet spanOptions = EnumSet.noneOf(Span.Options.class); - if (traceOptions.isSampled() || Boolean.TRUE.equals(recordEvents)) { - spanOptions.add(Span.Options.RECORD_EVENTS); - } + parent, + hasRemoteParent, + name, + sampler, + parentLinks, + traceId, + spanId, + activeTraceParams) + ? SAMPLED_TRACE_OPTIONS + : NOT_SAMPLED_TRACE_OPTIONS; + EnumSet spanOptions = + (traceOptions.isSampled() || Boolean.TRUE.equals(recordEvents)) + ? RECORD_EVENTS_SPAN_OPTIONS + : NOT_RECORD_EVENTS_SPAN_OPTIONS; SpanImpl span = SpanImpl.startSpan( SpanContext.create(traceId, spanId, traceOptions, tracestate), -- cgit v1.2.3 From f0e78ba5a10165cce2b63809bfdfe3e34b1eb456 Mon Sep 17 00:00:00 2001 From: Bogdan Drutu Date: Sat, 22 Sep 2018 09:37:29 -0700 Subject: Split SpanImpl into record/notrecord span impl to avoid checks of recording all time. (#1468) * Split SpanImpl into record/notrecord span impl to avoid checks of recording all time. * Remove one extra SuppressWarnings. --- .../implcore/trace/NoRecordEventsSpanImpl.java | 85 +++ .../implcore/trace/RecordEventsSpanImpl.java | 579 +++++++++++++++++++ .../opencensus/implcore/trace/SpanBuilderImpl.java | 46 +- .../io/opencensus/implcore/trace/SpanImpl.java | 619 --------------------- .../implcore/trace/StartEndHandlerImpl.java | 14 +- .../implcore/trace/TraceComponentImplBase.java | 2 +- .../io/opencensus/implcore/trace/TracerImpl.java | 4 +- .../export/InProcessRunningSpanStoreImpl.java | 18 +- .../export/InProcessSampledSpanStoreImpl.java | 56 +- .../trace/export/RunningSpanStoreImpl.java | 13 +- .../trace/export/SampledSpanStoreImpl.java | 10 +- .../implcore/trace/export/SpanExporterImpl.java | 22 +- 12 files changed, 754 insertions(+), 714 deletions(-) create mode 100644 impl_core/src/main/java/io/opencensus/implcore/trace/NoRecordEventsSpanImpl.java create mode 100644 impl_core/src/main/java/io/opencensus/implcore/trace/RecordEventsSpanImpl.java delete mode 100644 impl_core/src/main/java/io/opencensus/implcore/trace/SpanImpl.java (limited to 'impl_core/src/main/java/io/opencensus/implcore/trace') diff --git a/impl_core/src/main/java/io/opencensus/implcore/trace/NoRecordEventsSpanImpl.java b/impl_core/src/main/java/io/opencensus/implcore/trace/NoRecordEventsSpanImpl.java new file mode 100644 index 00000000..8a5f8e05 --- /dev/null +++ b/impl_core/src/main/java/io/opencensus/implcore/trace/NoRecordEventsSpanImpl.java @@ -0,0 +1,85 @@ +/* + * Copyright 2018, 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 com.google.common.base.Preconditions; +import io.opencensus.trace.Annotation; +import io.opencensus.trace.AttributeValue; +import io.opencensus.trace.EndSpanOptions; +import io.opencensus.trace.Link; +import io.opencensus.trace.Span; +import io.opencensus.trace.SpanContext; +import io.opencensus.trace.Status; +import java.util.EnumSet; +import java.util.Map; + +/** Implementation for the {@link Span} class that does not record trace events. */ +final class NoRecordEventsSpanImpl extends Span { + + private static final EnumSet NOT_RECORD_EVENTS_SPAN_OPTIONS = + EnumSet.noneOf(Span.Options.class); + + static NoRecordEventsSpanImpl create(SpanContext context) { + return new NoRecordEventsSpanImpl(context); + } + + @Override + public void addAnnotation(String description, Map attributes) { + Preconditions.checkNotNull(description, "description"); + Preconditions.checkNotNull(attributes, "attribute"); + } + + @Override + public void addAnnotation(Annotation annotation) { + Preconditions.checkNotNull(annotation, "annotation"); + } + + @Override + public void putAttribute(String key, AttributeValue value) { + Preconditions.checkNotNull(key, "key"); + Preconditions.checkNotNull(value, "value"); + } + + @Override + public void putAttributes(Map attributes) { + Preconditions.checkNotNull(attributes, "attributes"); + } + + @Override + public void addMessageEvent(io.opencensus.trace.MessageEvent messageEvent) { + Preconditions.checkNotNull(messageEvent, "messageEvent"); + } + + @Override + public void addLink(Link link) { + Preconditions.checkNotNull(link, "link"); + } + + @Override + public void setStatus(Status status) { + Preconditions.checkNotNull(status, "status"); + } + + @Override + public void end(EndSpanOptions options) { + Preconditions.checkNotNull(options, "options"); + } + + private NoRecordEventsSpanImpl(SpanContext context) { + super(context, NOT_RECORD_EVENTS_SPAN_OPTIONS); + } +} diff --git a/impl_core/src/main/java/io/opencensus/implcore/trace/RecordEventsSpanImpl.java b/impl_core/src/main/java/io/opencensus/implcore/trace/RecordEventsSpanImpl.java new file mode 100644 index 00000000..af3545bc --- /dev/null +++ b/impl_core/src/main/java/io/opencensus/implcore/trace/RecordEventsSpanImpl.java @@ -0,0 +1,579 @@ +/* + * 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 static com.google.common.base.Preconditions.checkState; + +import com.google.common.annotations.VisibleForTesting; +import com.google.common.base.Preconditions; +import com.google.common.collect.EvictingQueue; +import io.opencensus.common.Clock; +import io.opencensus.implcore.internal.CheckerFrameworkUtils; +import io.opencensus.implcore.internal.TimestampConverter; +import io.opencensus.implcore.trace.internal.ConcurrentIntrusiveList.Element; +import io.opencensus.trace.Annotation; +import io.opencensus.trace.AttributeValue; +import io.opencensus.trace.EndSpanOptions; +import io.opencensus.trace.Link; +import io.opencensus.trace.Span; +import io.opencensus.trace.SpanContext; +import io.opencensus.trace.SpanId; +import io.opencensus.trace.Status; +import io.opencensus.trace.Tracer; +import io.opencensus.trace.config.TraceParams; +import io.opencensus.trace.export.SpanData; +import io.opencensus.trace.export.SpanData.TimedEvent; +import java.util.ArrayList; +import java.util.Collections; +import java.util.EnumSet; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; +import java.util.logging.Level; +import java.util.logging.Logger; +import javax.annotation.Nullable; +import javax.annotation.concurrent.GuardedBy; +import javax.annotation.concurrent.ThreadSafe; + +// TODO(hailongwen): remove the usage of `NetworkEvent` in the future. +/** Implementation for the {@link Span} class that records trace events. */ +@ThreadSafe +public final class RecordEventsSpanImpl extends Span implements Element { + private static final Logger logger = Logger.getLogger(Tracer.class.getName()); + + private static final EnumSet RECORD_EVENTS_SPAN_OPTIONS = + EnumSet.of(Span.Options.RECORD_EVENTS); + + // The parent SpanId of this span. Null if this is a root span. + @Nullable private final SpanId parentSpanId; + // True if the parent is on a different process. + @Nullable private final Boolean hasRemoteParent; + // Active trace params when the Span was created. + private final TraceParams traceParams; + // Handler called when the span starts and ends. + private final StartEndHandler startEndHandler; + // The displayed name of the span. + private final String name; + // The kind of the span. + @Nullable private final Kind kind; + // The clock used to get the time. + private final Clock clock; + // The time converter used to convert nano time to Timestamp. This is needed because Java has + // millisecond granularity for Timestamp and tracing events are recorded more often. + @Nullable private final TimestampConverter timestampConverter; + // The start time of the span. + private final long startNanoTime; + // Set of recorded attributes. DO NOT CALL any other method that changes the ordering of events. + @GuardedBy("this") + @Nullable + private AttributesWithCapacity attributes; + // List of recorded annotations. + @GuardedBy("this") + @Nullable + private TraceEvents> annotations; + // List of recorded network events. + @GuardedBy("this") + @Nullable + private TraceEvents> messageEvents; + // List of recorded links to parent and child spans. + @GuardedBy("this") + @Nullable + private TraceEvents links; + // The status of the span. + @GuardedBy("this") + @Nullable + private Status status; + // The end time of the span. + @GuardedBy("this") + private long endNanoTime; + // True if the span is ended. + @GuardedBy("this") + private boolean hasBeenEnded; + + @GuardedBy("this") + private boolean sampleToLocalSpanStore; + + // Pointers for the ConcurrentIntrusiveList$Element. Guarded by the ConcurrentIntrusiveList. + @Nullable private RecordEventsSpanImpl next = null; + @Nullable private RecordEventsSpanImpl prev = null; + + /** + * Creates and starts a span with the given configuration. + * + * @param context supplies the trace_id and span_id for the newly started span. + * @param name the displayed name for the new span. + * @param parentSpanId the span_id of the parent span, or null if the new span is a root span. + * @param hasRemoteParent {@code true} if the parentContext is remote. {@code null} if this is a + * root span. + * @param traceParams trace parameters like sampler and probability. + * @param startEndHandler handler called when the span starts and ends. + * @param timestampConverter null if the span is a root span or the parent is not sampled. If the + * parent is sampled, we should use the same converter to ensure ordering between tracing + * events. + * @param clock the clock used to get the time. + * @return a new and started span. + */ + @VisibleForTesting + public static RecordEventsSpanImpl startSpan( + SpanContext context, + String name, + @Nullable Kind kind, + @Nullable SpanId parentSpanId, + @Nullable Boolean hasRemoteParent, + TraceParams traceParams, + StartEndHandler startEndHandler, + @Nullable TimestampConverter timestampConverter, + Clock clock) { + RecordEventsSpanImpl span = + new RecordEventsSpanImpl( + context, + name, + kind, + parentSpanId, + hasRemoteParent, + traceParams, + startEndHandler, + timestampConverter, + clock); + // Call onStart here instead of calling in the constructor to make sure the span is completely + // initialized. + startEndHandler.onStart(span); + return span; + } + + /** + * Returns the name of the {@code Span}. + * + * @return the name of the {@code Span}. + */ + public String getName() { + return name; + } + + /** + * Returns the status of the {@code Span}. If not set defaults to {@link Status#OK}. + * + * @return the status of the {@code Span}. + */ + public Status getStatus() { + synchronized (this) { + return getStatusWithDefault(); + } + } + + /** + * Returns the end nano time (see {@link System#nanoTime()}). If the current {@code Span} is not + * ended then returns {@link Clock#nowNanos()}. + * + * @return the end nano time. + */ + public long getEndNanoTime() { + synchronized (this) { + return hasBeenEnded ? endNanoTime : clock.nowNanos(); + } + } + + /** + * Returns the latency of the {@code Span} in nanos. If still active then returns now() - start + * time. + * + * @return the latency of the {@code Span} in nanos. + */ + public long getLatencyNs() { + synchronized (this) { + return hasBeenEnded ? endNanoTime - startNanoTime : clock.nowNanos() - startNanoTime; + } + } + + /** + * Returns if the name of this {@code Span} must be register to the {@code SampledSpanStore}. + * + * @return if the name of this {@code Span} must be register to the {@code SampledSpanStore}. + */ + public boolean getSampleToLocalSpanStore() { + synchronized (this) { + checkState(hasBeenEnded, "Running span does not have the SampleToLocalSpanStore set."); + return sampleToLocalSpanStore; + } + } + + /** + * Returns the kind of this {@code Span}. + * + * @return the kind of this {@code Span}. + */ + @Nullable + public Kind getKind() { + return kind; + } + + /** + * Returns the {@code TimestampConverter} used by this {@code Span}. + * + * @return the {@code TimestampConverter} used by this {@code Span}. + */ + @Nullable + TimestampConverter getTimestampConverter() { + return timestampConverter; + } + + /** + * Returns an immutable representation of all the data from this {@code Span}. + * + * @return an immutable representation of all the data from this {@code Span}. + * @throws IllegalStateException if the Span doesn't have RECORD_EVENTS option. + */ + public SpanData toSpanData() { + synchronized (this) { + SpanData.Attributes attributesSpanData = + attributes == null + ? SpanData.Attributes.create(Collections.emptyMap(), 0) + : SpanData.Attributes.create(attributes, attributes.getNumberOfDroppedAttributes()); + SpanData.TimedEvents annotationsSpanData = + createTimedEvents(getInitializedAnnotations(), timestampConverter); + SpanData.TimedEvents messageEventsSpanData = + createTimedEvents(getInitializedNetworkEvents(), timestampConverter); + SpanData.Links linksSpanData = + links == null + ? SpanData.Links.create(Collections.emptyList(), 0) + : SpanData.Links.create( + new ArrayList(links.events), links.getNumberOfDroppedEvents()); + return SpanData.create( + getContext(), + parentSpanId, + hasRemoteParent, + name, + kind, + CheckerFrameworkUtils.castNonNull(timestampConverter).convertNanoTime(startNanoTime), + attributesSpanData, + annotationsSpanData, + messageEventsSpanData, + linksSpanData, + null, // Not supported yet. + hasBeenEnded ? getStatusWithDefault() : null, + hasBeenEnded + ? CheckerFrameworkUtils.castNonNull(timestampConverter).convertNanoTime(endNanoTime) + : null); + } + } + + @Override + public void putAttribute(String key, AttributeValue value) { + Preconditions.checkNotNull(key, "key"); + Preconditions.checkNotNull(value, "value"); + synchronized (this) { + if (hasBeenEnded) { + logger.log(Level.FINE, "Calling putAttributes() on an ended Span."); + return; + } + getInitializedAttributes().putAttribute(key, value); + } + } + + @Override + public void putAttributes(Map attributes) { + Preconditions.checkNotNull(attributes, "attributes"); + synchronized (this) { + if (hasBeenEnded) { + logger.log(Level.FINE, "Calling putAttributes() on an ended Span."); + return; + } + getInitializedAttributes().putAttributes(attributes); + } + } + + @Override + public void addAnnotation(String description, Map attributes) { + Preconditions.checkNotNull(description, "description"); + Preconditions.checkNotNull(attributes, "attribute"); + synchronized (this) { + if (hasBeenEnded) { + logger.log(Level.FINE, "Calling addAnnotation() on an ended Span."); + return; + } + getInitializedAnnotations() + .addEvent( + new EventWithNanoTime( + clock.nowNanos(), + Annotation.fromDescriptionAndAttributes(description, attributes))); + } + } + + @Override + public void addAnnotation(Annotation annotation) { + Preconditions.checkNotNull(annotation, "annotation"); + synchronized (this) { + if (hasBeenEnded) { + logger.log(Level.FINE, "Calling addAnnotation() on an ended Span."); + return; + } + getInitializedAnnotations() + .addEvent(new EventWithNanoTime(clock.nowNanos(), annotation)); + } + } + + @Override + public void addMessageEvent(io.opencensus.trace.MessageEvent messageEvent) { + Preconditions.checkNotNull(messageEvent, "messageEvent"); + synchronized (this) { + if (hasBeenEnded) { + logger.log(Level.FINE, "Calling addNetworkEvent() on an ended Span."); + return; + } + getInitializedNetworkEvents() + .addEvent( + new EventWithNanoTime( + clock.nowNanos(), checkNotNull(messageEvent, "networkEvent"))); + } + } + + @Override + public void addLink(Link link) { + Preconditions.checkNotNull(link, "link"); + synchronized (this) { + if (hasBeenEnded) { + logger.log(Level.FINE, "Calling addLink() on an ended Span."); + return; + } + getInitializedLinks().addEvent(link); + } + } + + @Override + public void setStatus(Status status) { + Preconditions.checkNotNull(status, "status"); + synchronized (this) { + if (hasBeenEnded) { + logger.log(Level.FINE, "Calling setStatus() on an ended Span."); + return; + } + this.status = status; + } + } + + @Override + public void end(EndSpanOptions options) { + Preconditions.checkNotNull(options, "options"); + synchronized (this) { + if (hasBeenEnded) { + logger.log(Level.FINE, "Calling end() on an ended Span."); + return; + } + if (options.getStatus() != null) { + status = options.getStatus(); + } + sampleToLocalSpanStore = options.getSampleToLocalSpanStore(); + endNanoTime = clock.nowNanos(); + hasBeenEnded = true; + } + startEndHandler.onEnd(this); + } + + @GuardedBy("this") + private AttributesWithCapacity getInitializedAttributes() { + if (attributes == null) { + attributes = new AttributesWithCapacity(traceParams.getMaxNumberOfAttributes()); + } + return attributes; + } + + @GuardedBy("this") + private TraceEvents> getInitializedAnnotations() { + if (annotations == null) { + annotations = + new TraceEvents>(traceParams.getMaxNumberOfAnnotations()); + } + return annotations; + } + + @GuardedBy("this") + private TraceEvents> + getInitializedNetworkEvents() { + if (messageEvents == null) { + messageEvents = + new TraceEvents>( + traceParams.getMaxNumberOfMessageEvents()); + } + return messageEvents; + } + + @GuardedBy("this") + private TraceEvents getInitializedLinks() { + if (links == null) { + links = new TraceEvents(traceParams.getMaxNumberOfLinks()); + } + return links; + } + + @GuardedBy("this") + private Status getStatusWithDefault() { + return status == null ? Status.OK : status; + } + + private static SpanData.TimedEvents createTimedEvents( + TraceEvents> events, @Nullable TimestampConverter timestampConverter) { + if (events == null) { + return SpanData.TimedEvents.create(Collections.>emptyList(), 0); + } + List> eventsList = new ArrayList>(events.events.size()); + for (EventWithNanoTime networkEvent : events.events) { + eventsList.add( + networkEvent.toSpanDataTimedEvent(CheckerFrameworkUtils.castNonNull(timestampConverter))); + } + return SpanData.TimedEvents.create(eventsList, events.getNumberOfDroppedEvents()); + } + + @Override + @Nullable + public RecordEventsSpanImpl getNext() { + return next; + } + + @Override + public void setNext(@Nullable RecordEventsSpanImpl element) { + next = element; + } + + @Override + @Nullable + public RecordEventsSpanImpl getPrev() { + return prev; + } + + @Override + public void setPrev(@Nullable RecordEventsSpanImpl element) { + prev = element; + } + + /** + * Interface to handle the start and end operations for a {@link Span} only when the {@code Span} + * has {@link Options#RECORD_EVENTS} option. + * + *

Implementation must avoid high overhead work in any of the methods because the code is + * executed on the critical path. + * + *

One instance can be called by multiple threads in the same time, so the implementation must + * be thread-safe. + */ + public interface StartEndHandler { + void onStart(RecordEventsSpanImpl span); + + void onEnd(RecordEventsSpanImpl span); + } + + // A map implementation with a fixed capacity that drops events when the map gets full. Eviction + // is based on the access order. + private static final class AttributesWithCapacity extends LinkedHashMap { + private final int capacity; + private int totalRecordedAttributes = 0; + // Here because -Werror complains about this: [serial] serializable class AttributesWithCapacity + // has no definition of serialVersionUID. This class shouldn't be serialized. + private static final long serialVersionUID = 42L; + + private AttributesWithCapacity(int capacity) { + // Capacity of the map is capacity + 1 to avoid resizing because removeEldestEntry is invoked + // by put and putAll after inserting a new entry into the map. The loadFactor is set to 1 + // to avoid resizing because. The accessOrder is set to true. + super(capacity + 1, 1, /*accessOrder=*/ true); + this.capacity = capacity; + } + + // Users must call this method instead of put to keep count of the total number of entries + // inserted. + private void putAttribute(String key, AttributeValue value) { + totalRecordedAttributes += 1; + put(key, value); + } + + // Users must call this method instead of putAll to keep count of the total number of entries + // inserted. + private void putAttributes(Map attributes) { + totalRecordedAttributes += attributes.size(); + putAll(attributes); + } + + private int getNumberOfDroppedAttributes() { + return totalRecordedAttributes - size(); + } + + // It is called after each put or putAll call in order to determine if the eldest inserted + // entry should be removed or not. + @Override + protected boolean removeEldestEntry(Map.Entry eldest) { + return size() > this.capacity; + } + } + + private static final class TraceEvents { + private int totalRecordedEvents = 0; + private final EvictingQueue events; + + private int getNumberOfDroppedEvents() { + return totalRecordedEvents - events.size(); + } + + TraceEvents(int maxNumEvents) { + events = EvictingQueue.create(maxNumEvents); + } + + void addEvent(T event) { + totalRecordedEvents++; + events.add(event); + } + } + + // Timed event that uses nanoTime to represent the Timestamp. + private static final class EventWithNanoTime { + private final long nanoTime; + private final T event; + + private EventWithNanoTime(long nanoTime, T event) { + this.nanoTime = nanoTime; + this.event = event; + } + + private TimedEvent toSpanDataTimedEvent(TimestampConverter timestampConverter) { + return TimedEvent.create(timestampConverter.convertNanoTime(nanoTime), event); + } + } + + private RecordEventsSpanImpl( + SpanContext context, + String name, + @Nullable Kind kind, + @Nullable SpanId parentSpanId, + @Nullable Boolean hasRemoteParent, + TraceParams traceParams, + StartEndHandler startEndHandler, + @Nullable TimestampConverter timestampConverter, + Clock clock) { + super(context, RECORD_EVENTS_SPAN_OPTIONS); + this.parentSpanId = parentSpanId; + this.hasRemoteParent = hasRemoteParent; + this.name = name; + this.kind = kind; + this.traceParams = traceParams; + this.startEndHandler = startEndHandler; + this.clock = clock; + this.hasBeenEnded = false; + this.sampleToLocalSpanStore = false; + this.timestampConverter = + timestampConverter != null ? timestampConverter : TimestampConverter.now(clock); + startNanoTime = clock.nowNanos(); + } +} 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 index 3ea0ce33..5565e9de 100644 --- a/impl_core/src/main/java/io/opencensus/implcore/trace/SpanBuilderImpl.java +++ b/impl_core/src/main/java/io/opencensus/implcore/trace/SpanBuilderImpl.java @@ -35,7 +35,6 @@ import io.opencensus.trace.Tracestate; import io.opencensus.trace.config.TraceConfig; import io.opencensus.trace.config.TraceParams; import java.util.Collections; -import java.util.EnumSet; import java.util.List; import java.util.Random; import javax.annotation.Nullable; @@ -49,11 +48,6 @@ final class SpanBuilderImpl extends SpanBuilder { private static final TraceOptions NOT_SAMPLED_TRACE_OPTIONS = TraceOptions.builder().setIsSampled(false).build(); - private static final EnumSet NOT_RECORD_EVENTS_SPAN_OPTIONS = - EnumSet.noneOf(Span.Options.class); - private static final EnumSet RECORD_EVENTS_SPAN_OPTIONS = - EnumSet.of(Span.Options.RECORD_EVENTS); - private final Options options; private final String name; @Nullable private final Span parent; @@ -63,7 +57,7 @@ final class SpanBuilderImpl extends SpanBuilder { @Nullable private Boolean recordEvents; @Nullable private Kind kind; - private SpanImpl startSpanInternal( + private Span startSpanInternal( @Nullable SpanContext parent, @Nullable Boolean hasRemoteParent, String name, @@ -102,22 +96,20 @@ final class SpanBuilderImpl extends SpanBuilder { activeTraceParams) ? SAMPLED_TRACE_OPTIONS : NOT_SAMPLED_TRACE_OPTIONS; - EnumSet spanOptions = + Span span = (traceOptions.isSampled() || Boolean.TRUE.equals(recordEvents)) - ? RECORD_EVENTS_SPAN_OPTIONS - : NOT_RECORD_EVENTS_SPAN_OPTIONS; - SpanImpl span = - SpanImpl.startSpan( - SpanContext.create(traceId, spanId, traceOptions, tracestate), - spanOptions, - name, - kind, - parentSpanId, - hasRemoteParent, - activeTraceParams, - options.startEndHandler, - timestampConverter, - options.clock); + ? 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; } @@ -186,7 +178,7 @@ final class SpanBuilderImpl extends SpanBuilder { } @Override - public SpanImpl startSpan() { + public Span startSpan() { SpanContext parentContext = remoteParentSpanContext; Boolean hasRemoteParent = Boolean.TRUE; TimestampConverter timestampConverter = null; @@ -199,8 +191,8 @@ final class SpanBuilderImpl extends SpanBuilder { 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 SpanImpl) { - timestampConverter = ((SpanImpl) parent).getTimestampConverter(); + if (parent instanceof RecordEventsSpanImpl) { + timestampConverter = ((RecordEventsSpanImpl) parent).getTimestampConverter(); } } else { hasRemoteParent = null; @@ -219,13 +211,13 @@ final class SpanBuilderImpl extends SpanBuilder { static final class Options { private final RandomHandler randomHandler; - private final SpanImpl.StartEndHandler startEndHandler; + private final RecordEventsSpanImpl.StartEndHandler startEndHandler; private final Clock clock; private final TraceConfig traceConfig; Options( RandomHandler randomHandler, - SpanImpl.StartEndHandler startEndHandler, + RecordEventsSpanImpl.StartEndHandler startEndHandler, Clock clock, TraceConfig traceConfig) { this.randomHandler = checkNotNull(randomHandler, "randomHandler"); diff --git a/impl_core/src/main/java/io/opencensus/implcore/trace/SpanImpl.java b/impl_core/src/main/java/io/opencensus/implcore/trace/SpanImpl.java deleted file mode 100644 index 75509a7f..00000000 --- a/impl_core/src/main/java/io/opencensus/implcore/trace/SpanImpl.java +++ /dev/null @@ -1,619 +0,0 @@ -/* - * 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 static com.google.common.base.Preconditions.checkState; - -import com.google.common.annotations.VisibleForTesting; -import com.google.common.base.Preconditions; -import com.google.common.collect.EvictingQueue; -import io.opencensus.common.Clock; -import io.opencensus.implcore.internal.CheckerFrameworkUtils; -import io.opencensus.implcore.internal.TimestampConverter; -import io.opencensus.implcore.trace.internal.ConcurrentIntrusiveList.Element; -import io.opencensus.trace.Annotation; -import io.opencensus.trace.AttributeValue; -import io.opencensus.trace.EndSpanOptions; -import io.opencensus.trace.Link; -import io.opencensus.trace.Span; -import io.opencensus.trace.SpanContext; -import io.opencensus.trace.SpanId; -import io.opencensus.trace.Status; -import io.opencensus.trace.Tracer; -import io.opencensus.trace.config.TraceParams; -import io.opencensus.trace.export.SpanData; -import io.opencensus.trace.export.SpanData.TimedEvent; -import java.util.ArrayList; -import java.util.Collections; -import java.util.EnumSet; -import java.util.LinkedHashMap; -import java.util.List; -import java.util.Map; -import java.util.logging.Level; -import java.util.logging.Logger; -import javax.annotation.Nullable; -import javax.annotation.concurrent.GuardedBy; -import javax.annotation.concurrent.ThreadSafe; - -// TODO(hailongwen): remove the usage of `NetworkEvent` in the future. -/** Implementation for the {@link Span} class. */ -@ThreadSafe -public final class SpanImpl extends Span implements Element { - private static final Logger logger = Logger.getLogger(Tracer.class.getName()); - - // The parent SpanId of this span. Null if this is a root span. - @Nullable private final SpanId parentSpanId; - // True if the parent is on a different process. - @Nullable private final Boolean hasRemoteParent; - // Active trace params when the Span was created. - private final TraceParams traceParams; - // Handler called when the span starts and ends. - private final StartEndHandler startEndHandler; - // The displayed name of the span. - private final String name; - // The kind of the span. - @Nullable private final Kind kind; - // The clock used to get the time. - private final Clock clock; - // The time converter used to convert nano time to Timestamp. This is needed because Java has - // millisecond granularity for Timestamp and tracing events are recorded more often. - @Nullable private final TimestampConverter timestampConverter; - // The start time of the span. Set when the span is created iff the RECORD_EVENTS options is - // set, otherwise 0. - private final long startNanoTime; - // Set of recorded attributes. DO NOT CALL any other method that changes the ordering of events. - @GuardedBy("this") - @Nullable - private AttributesWithCapacity attributes; - // List of recorded annotations. - @GuardedBy("this") - @Nullable - private TraceEvents> annotations; - // List of recorded network events. - @GuardedBy("this") - @Nullable - @SuppressWarnings("deprecation") - private TraceEvents> networkEvents; - // List of recorded links to parent and child spans. - @GuardedBy("this") - @Nullable - private TraceEvents links; - // The status of the span. Set when the span is ended iff the RECORD_EVENTS options is set. - @GuardedBy("this") - @Nullable - private Status status; - // The end time of the span. Set when the span is ended iff the RECORD_EVENTS options is set, - // otherwise 0. - @GuardedBy("this") - private long endNanoTime; - // True if the span is ended. - @GuardedBy("this") - private boolean hasBeenEnded; - - @GuardedBy("this") - private boolean sampleToLocalSpanStore; - - // Pointers for the ConcurrentIntrusiveList$Element. Guarded by the ConcurrentIntrusiveList. - @Nullable private SpanImpl next = null; - @Nullable private SpanImpl prev = null; - - /** - * Creates and starts a span with the given configuration. - * - * @param context supplies the trace_id and span_id for the newly started span. - * @param options the options for the new span, importantly Options.RECORD_EVENTS. - * @param name the displayed name for the new span. - * @param parentSpanId the span_id of the parent span, or null if the new span is a root span. - * @param hasRemoteParent {@code true} if the parentContext is remote. {@code null} if this is a - * root span. - * @param traceParams trace parameters like sampler and probability. - * @param startEndHandler handler called when the span starts and ends. - * @param timestampConverter null if the span is a root span or the parent is not sampled. If the - * parent is sampled, we should use the same converter to ensure ordering between tracing - * events. - * @param clock the clock used to get the time. - * @return a new and started span. - */ - @VisibleForTesting - public static SpanImpl startSpan( - SpanContext context, - @Nullable EnumSet options, - String name, - @Nullable Kind kind, - @Nullable SpanId parentSpanId, - @Nullable Boolean hasRemoteParent, - TraceParams traceParams, - StartEndHandler startEndHandler, - @Nullable TimestampConverter timestampConverter, - Clock clock) { - SpanImpl span = - new SpanImpl( - context, - options, - name, - kind, - parentSpanId, - hasRemoteParent, - traceParams, - startEndHandler, - timestampConverter, - clock); - // Call onStart here instead of calling in the constructor to make sure the span is completely - // initialized. - if (span.getOptions().contains(Options.RECORD_EVENTS)) { - startEndHandler.onStart(span); - } - return span; - } - - /** - * Returns the name of the {@code Span}. - * - * @return the name of the {@code Span}. - */ - public String getName() { - return name; - } - - /** - * Returns the status of the {@code Span}. If not set defaults to {@link Status#OK}. - * - * @return the status of the {@code Span}. - */ - public Status getStatus() { - synchronized (this) { - return getStatusWithDefault(); - } - } - - /** - * Returns the end nano time (see {@link System#nanoTime()}). If the current {@code Span} is not - * ended then returns {@link Clock#nowNanos()}. - * - * @return the end nano time. - */ - public long getEndNanoTime() { - synchronized (this) { - return hasBeenEnded ? endNanoTime : clock.nowNanos(); - } - } - - /** - * Returns the latency of the {@code Span} in nanos. If still active then returns now() - start - * time. - * - * @return the latency of the {@code Span} in nanos. - */ - public long getLatencyNs() { - synchronized (this) { - return hasBeenEnded ? endNanoTime - startNanoTime : clock.nowNanos() - startNanoTime; - } - } - - /** - * Returns if the name of this {@code Span} must be register to the {@code SampledSpanStore}. - * - * @return if the name of this {@code Span} must be register to the {@code SampledSpanStore}. - */ - public boolean getSampleToLocalSpanStore() { - synchronized (this) { - checkState(hasBeenEnded, "Running span does not have the SampleToLocalSpanStore set."); - return sampleToLocalSpanStore; - } - } - - /** - * Returns the kind of this {@code Span}. - * - * @return the kind of this {@code Span}. - */ - @Nullable - public Kind getKind() { - return kind; - } - - /** - * Returns the {@code TimestampConverter} used by this {@code Span}. - * - * @return the {@code TimestampConverter} used by this {@code Span}. - */ - @Nullable - TimestampConverter getTimestampConverter() { - return timestampConverter; - } - - /** - * Returns an immutable representation of all the data from this {@code Span}. - * - * @return an immutable representation of all the data from this {@code Span}. - * @throws IllegalStateException if the Span doesn't have RECORD_EVENTS option. - */ - public SpanData toSpanData() { - checkState( - getOptions().contains(Options.RECORD_EVENTS), - "Getting SpanData for a Span without RECORD_EVENTS option."); - synchronized (this) { - SpanData.Attributes attributesSpanData = - attributes == null - ? SpanData.Attributes.create(Collections.emptyMap(), 0) - : SpanData.Attributes.create(attributes, attributes.getNumberOfDroppedAttributes()); - SpanData.TimedEvents annotationsSpanData = - createTimedEvents(getInitializedAnnotations(), timestampConverter); - @SuppressWarnings("deprecation") - SpanData.TimedEvents networkEventsSpanData = - createTimedEvents(getInitializedNetworkEvents(), timestampConverter); - SpanData.Links linksSpanData = - links == null - ? SpanData.Links.create(Collections.emptyList(), 0) - : SpanData.Links.create( - new ArrayList(links.events), links.getNumberOfDroppedEvents()); - return SpanData.create( - getContext(), - parentSpanId, - hasRemoteParent, - name, - kind, - CheckerFrameworkUtils.castNonNull(timestampConverter).convertNanoTime(startNanoTime), - attributesSpanData, - annotationsSpanData, - networkEventsSpanData, - linksSpanData, - null, // Not supported yet. - hasBeenEnded ? getStatusWithDefault() : null, - hasBeenEnded - ? CheckerFrameworkUtils.castNonNull(timestampConverter).convertNanoTime(endNanoTime) - : null); - } - } - - @Override - public void putAttribute(String key, AttributeValue value) { - Preconditions.checkNotNull(key, "key"); - Preconditions.checkNotNull(value, "value"); - if (!getOptions().contains(Options.RECORD_EVENTS)) { - return; - } - synchronized (this) { - if (hasBeenEnded) { - logger.log(Level.FINE, "Calling putAttributes() on an ended Span."); - return; - } - getInitializedAttributes().putAttribute(key, value); - } - } - - @Override - public void putAttributes(Map attributes) { - Preconditions.checkNotNull(attributes, "attributes"); - if (!getOptions().contains(Options.RECORD_EVENTS)) { - return; - } - synchronized (this) { - if (hasBeenEnded) { - logger.log(Level.FINE, "Calling putAttributes() on an ended Span."); - return; - } - getInitializedAttributes().putAttributes(attributes); - } - } - - @Override - public void addAnnotation(String description, Map attributes) { - Preconditions.checkNotNull(description, "description"); - Preconditions.checkNotNull(attributes, "attribute"); - if (!getOptions().contains(Options.RECORD_EVENTS)) { - return; - } - synchronized (this) { - if (hasBeenEnded) { - logger.log(Level.FINE, "Calling addAnnotation() on an ended Span."); - return; - } - getInitializedAnnotations() - .addEvent( - new EventWithNanoTime( - clock.nowNanos(), - Annotation.fromDescriptionAndAttributes(description, attributes))); - } - } - - @Override - public void addAnnotation(Annotation annotation) { - Preconditions.checkNotNull(annotation, "annotation"); - if (!getOptions().contains(Options.RECORD_EVENTS)) { - return; - } - synchronized (this) { - if (hasBeenEnded) { - logger.log(Level.FINE, "Calling addAnnotation() on an ended Span."); - return; - } - getInitializedAnnotations() - .addEvent(new EventWithNanoTime(clock.nowNanos(), annotation)); - } - } - - @Override - @SuppressWarnings("deprecation") - public void addNetworkEvent(io.opencensus.trace.NetworkEvent networkEvent) { - if (!getOptions().contains(Options.RECORD_EVENTS)) { - return; - } - synchronized (this) { - if (hasBeenEnded) { - logger.log(Level.FINE, "Calling addNetworkEvent() on an ended Span."); - return; - } - getInitializedNetworkEvents() - .addEvent( - new EventWithNanoTime( - clock.nowNanos(), checkNotNull(networkEvent, "networkEvent"))); - } - } - - @Override - public void addLink(Link link) { - Preconditions.checkNotNull(link, "link"); - if (!getOptions().contains(Options.RECORD_EVENTS)) { - return; - } - synchronized (this) { - if (hasBeenEnded) { - logger.log(Level.FINE, "Calling addLink() on an ended Span."); - return; - } - getInitializedLinks().addEvent(link); - } - } - - @Override - public void setStatus(Status status) { - Preconditions.checkNotNull(status, "status"); - if (!getOptions().contains(Options.RECORD_EVENTS)) { - return; - } - synchronized (this) { - if (hasBeenEnded) { - logger.log(Level.FINE, "Calling setStatus() on an ended Span."); - return; - } - this.status = status; - } - } - - @Override - public void end(EndSpanOptions options) { - Preconditions.checkNotNull(options, "options"); - if (!getOptions().contains(Options.RECORD_EVENTS)) { - return; - } - synchronized (this) { - if (hasBeenEnded) { - logger.log(Level.FINE, "Calling end() on an ended Span."); - return; - } - if (options.getStatus() != null) { - status = options.getStatus(); - } - sampleToLocalSpanStore = options.getSampleToLocalSpanStore(); - endNanoTime = clock.nowNanos(); - hasBeenEnded = true; - } - startEndHandler.onEnd(this); - } - - @GuardedBy("this") - private AttributesWithCapacity getInitializedAttributes() { - if (attributes == null) { - attributes = new AttributesWithCapacity(traceParams.getMaxNumberOfAttributes()); - } - return attributes; - } - - @GuardedBy("this") - private TraceEvents> getInitializedAnnotations() { - if (annotations == null) { - annotations = - new TraceEvents>(traceParams.getMaxNumberOfAnnotations()); - } - return annotations; - } - - @GuardedBy("this") - @SuppressWarnings("deprecation") - private TraceEvents> - getInitializedNetworkEvents() { - if (networkEvents == null) { - networkEvents = - new TraceEvents>( - traceParams.getMaxNumberOfNetworkEvents()); - } - return networkEvents; - } - - @GuardedBy("this") - private TraceEvents getInitializedLinks() { - if (links == null) { - links = new TraceEvents(traceParams.getMaxNumberOfLinks()); - } - return links; - } - - @GuardedBy("this") - private Status getStatusWithDefault() { - return status == null ? Status.OK : status; - } - - private static SpanData.TimedEvents createTimedEvents( - TraceEvents> events, @Nullable TimestampConverter timestampConverter) { - if (events == null) { - return SpanData.TimedEvents.create(Collections.>emptyList(), 0); - } - List> eventsList = new ArrayList>(events.events.size()); - for (EventWithNanoTime networkEvent : events.events) { - eventsList.add( - networkEvent.toSpanDataTimedEvent(CheckerFrameworkUtils.castNonNull(timestampConverter))); - } - return SpanData.TimedEvents.create(eventsList, events.getNumberOfDroppedEvents()); - } - - @Override - @Nullable - public SpanImpl getNext() { - return next; - } - - @Override - public void setNext(@Nullable SpanImpl element) { - next = element; - } - - @Override - @Nullable - public SpanImpl getPrev() { - return prev; - } - - @Override - public void setPrev(@Nullable SpanImpl element) { - prev = element; - } - - /** - * Interface to handle the start and end operations for a {@link Span} only when the {@code Span} - * has {@link Options#RECORD_EVENTS} option. - * - *

Implementation must avoid high overhead work in any of the methods because the code is - * executed on the critical path. - * - *

One instance can be called by multiple threads in the same time, so the implementation must - * be thread-safe. - */ - public interface StartEndHandler { - void onStart(SpanImpl span); - - void onEnd(SpanImpl span); - } - - // A map implementation with a fixed capacity that drops events when the map gets full. Eviction - // is based on the access order. - private static final class AttributesWithCapacity extends LinkedHashMap { - private final int capacity; - private int totalRecordedAttributes = 0; - // Here because -Werror complains about this: [serial] serializable class AttributesWithCapacity - // has no definition of serialVersionUID. This class shouldn't be serialized. - private static final long serialVersionUID = 42L; - - private AttributesWithCapacity(int capacity) { - // Capacity of the map is capacity + 1 to avoid resizing because removeEldestEntry is invoked - // by put and putAll after inserting a new entry into the map. The loadFactor is set to 1 - // to avoid resizing because. The accessOrder is set to true. - super(capacity + 1, 1, /*accessOrder=*/ true); - this.capacity = capacity; - } - - // Users must call this method instead of put to keep count of the total number of entries - // inserted. - private void putAttribute(String key, AttributeValue value) { - totalRecordedAttributes += 1; - put(key, value); - } - - // Users must call this method instead of putAll to keep count of the total number of entries - // inserted. - private void putAttributes(Map attributes) { - totalRecordedAttributes += attributes.size(); - putAll(attributes); - } - - private int getNumberOfDroppedAttributes() { - return totalRecordedAttributes - size(); - } - - // It is called after each put or putAll call in order to determine if the eldest inserted - // entry should be removed or not. - @Override - protected boolean removeEldestEntry(Map.Entry eldest) { - return size() > this.capacity; - } - } - - private static final class TraceEvents { - private int totalRecordedEvents = 0; - private final EvictingQueue events; - - private int getNumberOfDroppedEvents() { - return totalRecordedEvents - events.size(); - } - - TraceEvents(int maxNumEvents) { - events = EvictingQueue.create(maxNumEvents); - } - - void addEvent(T event) { - totalRecordedEvents++; - events.add(event); - } - } - - // Timed event that uses nanoTime to represent the Timestamp. - private static final class EventWithNanoTime { - private final long nanoTime; - private final T event; - - private EventWithNanoTime(long nanoTime, T event) { - this.nanoTime = nanoTime; - this.event = event; - } - - private TimedEvent toSpanDataTimedEvent(TimestampConverter timestampConverter) { - return TimedEvent.create(timestampConverter.convertNanoTime(nanoTime), event); - } - } - - private SpanImpl( - SpanContext context, - @Nullable EnumSet options, - String name, - @Nullable Kind kind, - @Nullable SpanId parentSpanId, - @Nullable Boolean hasRemoteParent, - TraceParams traceParams, - StartEndHandler startEndHandler, - @Nullable TimestampConverter timestampConverter, - Clock clock) { - super(context, options); - this.parentSpanId = parentSpanId; - this.hasRemoteParent = hasRemoteParent; - this.name = name; - this.kind = kind; - this.traceParams = traceParams; - this.startEndHandler = startEndHandler; - this.clock = clock; - this.hasBeenEnded = false; - this.sampleToLocalSpanStore = false; - if (options != null && options.contains(Options.RECORD_EVENTS)) { - this.timestampConverter = - timestampConverter != null ? timestampConverter : TimestampConverter.now(clock); - startNanoTime = clock.nowNanos(); - } else { - this.startNanoTime = 0; - this.timestampConverter = timestampConverter; - } - } -} diff --git a/impl_core/src/main/java/io/opencensus/implcore/trace/StartEndHandlerImpl.java b/impl_core/src/main/java/io/opencensus/implcore/trace/StartEndHandlerImpl.java index e22a86bd..6adaa200 100644 --- a/impl_core/src/main/java/io/opencensus/implcore/trace/StartEndHandlerImpl.java +++ b/impl_core/src/main/java/io/opencensus/implcore/trace/StartEndHandlerImpl.java @@ -17,7 +17,7 @@ package io.opencensus.implcore.trace; import io.opencensus.implcore.internal.EventQueue; -import io.opencensus.implcore.trace.SpanImpl.StartEndHandler; +import io.opencensus.implcore.trace.RecordEventsSpanImpl.StartEndHandler; import io.opencensus.implcore.trace.export.RunningSpanStoreImpl; import io.opencensus.implcore.trace.export.SampledSpanStoreImpl; import io.opencensus.implcore.trace.export.SpanExporterImpl; @@ -61,14 +61,14 @@ public final class StartEndHandlerImpl implements StartEndHandler { } @Override - public void onStart(SpanImpl span) { + public void onStart(RecordEventsSpanImpl span) { if (span.getOptions().contains(Options.RECORD_EVENTS) && enqueueEventForNonSampledSpans) { eventQueue.enqueue(new SpanStartEvent(span, runningSpanStore)); } } @Override - public void onEnd(SpanImpl span) { + public void onEnd(RecordEventsSpanImpl span) { if ((span.getOptions().contains(Options.RECORD_EVENTS) && enqueueEventForNonSampledSpans) || span.getContext().getTraceOptions().isSampled()) { eventQueue.enqueue(new SpanEndEvent(span, spanExporter, runningSpanStore, sampledSpanStore)); @@ -77,10 +77,10 @@ public final class StartEndHandlerImpl implements StartEndHandler { // An EventQueue entry that records the start of the span event. private static final class SpanStartEvent implements EventQueue.Entry { - private final SpanImpl span; + private final RecordEventsSpanImpl span; @Nullable private final RunningSpanStoreImpl activeSpansExporter; - SpanStartEvent(SpanImpl span, @Nullable RunningSpanStoreImpl activeSpansExporter) { + SpanStartEvent(RecordEventsSpanImpl span, @Nullable RunningSpanStoreImpl activeSpansExporter) { this.span = span; this.activeSpansExporter = activeSpansExporter; } @@ -95,13 +95,13 @@ public final class StartEndHandlerImpl implements StartEndHandler { // An EventQueue entry that records the end of the span event. private static final class SpanEndEvent implements EventQueue.Entry { - private final SpanImpl span; + private final RecordEventsSpanImpl span; @Nullable private final RunningSpanStoreImpl runningSpanStore; private final SpanExporterImpl spanExporter; @Nullable private final SampledSpanStoreImpl sampledSpanStore; SpanEndEvent( - SpanImpl span, + RecordEventsSpanImpl span, SpanExporterImpl spanExporter, @Nullable RunningSpanStoreImpl runningSpanStore, @Nullable SampledSpanStoreImpl sampledSpanStore) { diff --git a/impl_core/src/main/java/io/opencensus/implcore/trace/TraceComponentImplBase.java b/impl_core/src/main/java/io/opencensus/implcore/trace/TraceComponentImplBase.java index f4c5ef76..c1432432 100644 --- a/impl_core/src/main/java/io/opencensus/implcore/trace/TraceComponentImplBase.java +++ b/impl_core/src/main/java/io/opencensus/implcore/trace/TraceComponentImplBase.java @@ -19,7 +19,7 @@ package io.opencensus.implcore.trace; import io.opencensus.common.Clock; import io.opencensus.implcore.internal.EventQueue; import io.opencensus.implcore.internal.SimpleEventQueue; -import io.opencensus.implcore.trace.SpanImpl.StartEndHandler; +import io.opencensus.implcore.trace.RecordEventsSpanImpl.StartEndHandler; import io.opencensus.implcore.trace.config.TraceConfigImpl; import io.opencensus.implcore.trace.export.ExportComponentImpl; import io.opencensus.implcore.trace.internal.RandomHandler; diff --git a/impl_core/src/main/java/io/opencensus/implcore/trace/TracerImpl.java b/impl_core/src/main/java/io/opencensus/implcore/trace/TracerImpl.java index fcf30ff0..48df8055 100644 --- a/impl_core/src/main/java/io/opencensus/implcore/trace/TracerImpl.java +++ b/impl_core/src/main/java/io/opencensus/implcore/trace/TracerImpl.java @@ -29,9 +29,9 @@ import javax.annotation.Nullable; public final class TracerImpl extends Tracer { private final SpanBuilderImpl.Options spanBuilderOptions; - public TracerImpl( + TracerImpl( RandomHandler randomHandler, - SpanImpl.StartEndHandler startEndHandler, + RecordEventsSpanImpl.StartEndHandler startEndHandler, Clock clock, TraceConfig traceConfig) { spanBuilderOptions = diff --git a/impl_core/src/main/java/io/opencensus/implcore/trace/export/InProcessRunningSpanStoreImpl.java b/impl_core/src/main/java/io/opencensus/implcore/trace/export/InProcessRunningSpanStoreImpl.java index 3d8fb9ae..f7aeac71 100644 --- a/impl_core/src/main/java/io/opencensus/implcore/trace/export/InProcessRunningSpanStoreImpl.java +++ b/impl_core/src/main/java/io/opencensus/implcore/trace/export/InProcessRunningSpanStoreImpl.java @@ -16,7 +16,7 @@ package io.opencensus.implcore.trace.export; -import io.opencensus.implcore.trace.SpanImpl; +import io.opencensus.implcore.trace.RecordEventsSpanImpl; import io.opencensus.implcore.trace.internal.ConcurrentIntrusiveList; import io.opencensus.trace.export.RunningSpanStore; import io.opencensus.trace.export.SpanData; @@ -30,27 +30,27 @@ import javax.annotation.concurrent.ThreadSafe; /** In-process implementation of the {@link RunningSpanStore}. */ @ThreadSafe public final class InProcessRunningSpanStoreImpl extends RunningSpanStoreImpl { - private final ConcurrentIntrusiveList runningSpans; + private final ConcurrentIntrusiveList runningSpans; public InProcessRunningSpanStoreImpl() { - runningSpans = new ConcurrentIntrusiveList(); + runningSpans = new ConcurrentIntrusiveList(); } @Override - public void onStart(SpanImpl span) { + public void onStart(RecordEventsSpanImpl span) { runningSpans.addElement(span); } @Override - public void onEnd(SpanImpl span) { + public void onEnd(RecordEventsSpanImpl span) { runningSpans.removeElement(span); } @Override public Summary getSummary() { - Collection allRunningSpans = runningSpans.getAll(); + Collection allRunningSpans = runningSpans.getAll(); Map numSpansPerName = new HashMap(); - for (SpanImpl span : allRunningSpans) { + for (RecordEventsSpanImpl span : allRunningSpans) { Integer prevValue = numSpansPerName.get(span.getName()); numSpansPerName.put(span.getName(), prevValue != null ? prevValue + 1 : 1); } @@ -64,11 +64,11 @@ public final class InProcessRunningSpanStoreImpl extends RunningSpanStoreImpl { @Override public Collection getRunningSpans(Filter filter) { - Collection allRunningSpans = runningSpans.getAll(); + Collection allRunningSpans = runningSpans.getAll(); int maxSpansToReturn = filter.getMaxSpansToReturn() == 0 ? allRunningSpans.size() : filter.getMaxSpansToReturn(); List ret = new ArrayList(maxSpansToReturn); - for (SpanImpl span : allRunningSpans) { + for (RecordEventsSpanImpl span : allRunningSpans) { if (ret.size() == maxSpansToReturn) { break; } diff --git a/impl_core/src/main/java/io/opencensus/implcore/trace/export/InProcessSampledSpanStoreImpl.java b/impl_core/src/main/java/io/opencensus/implcore/trace/export/InProcessSampledSpanStoreImpl.java index fe0132d8..0d8e493b 100644 --- a/impl_core/src/main/java/io/opencensus/implcore/trace/export/InProcessSampledSpanStoreImpl.java +++ b/impl_core/src/main/java/io/opencensus/implcore/trace/export/InProcessSampledSpanStoreImpl.java @@ -18,7 +18,7 @@ package io.opencensus.implcore.trace.export; import com.google.common.collect.EvictingQueue; import io.opencensus.implcore.internal.EventQueue; -import io.opencensus.implcore.trace.SpanImpl; +import io.opencensus.implcore.trace.RecordEventsSpanImpl; import io.opencensus.trace.Status; import io.opencensus.trace.Status.CanonicalCode; import io.opencensus.trace.export.SampledSpanStore; @@ -59,8 +59,8 @@ public final class InProcessSampledSpanStoreImpl extends SampledSpanStoreImpl { private static final class Bucket { - private final EvictingQueue sampledSpansQueue; - private final EvictingQueue notSampledSpansQueue; + private final EvictingQueue sampledSpansQueue; + private final EvictingQueue notSampledSpansQueue; private long lastSampledNanoTime; private long lastNotSampledNanoTime; @@ -69,7 +69,7 @@ public final class InProcessSampledSpanStoreImpl extends SampledSpanStoreImpl { notSampledSpansQueue = EvictingQueue.create(numSamples); } - private void considerForSampling(SpanImpl span) { + private void considerForSampling(RecordEventsSpanImpl span) { long spanEndNanoTime = span.getEndNanoTime(); if (span.getContext().getTraceOptions().isSampled()) { // Need to compare by doing the subtraction all the time because in case of an overflow, @@ -90,14 +90,16 @@ public final class InProcessSampledSpanStoreImpl extends SampledSpanStoreImpl { } } - private void getSamples(int maxSpansToReturn, List output) { + private void getSamples(int maxSpansToReturn, List output) { getSamples(maxSpansToReturn, output, sampledSpansQueue); getSamples(maxSpansToReturn, output, notSampledSpansQueue); } private static void getSamples( - int maxSpansToReturn, List output, EvictingQueue queue) { - for (SpanImpl span : queue) { + int maxSpansToReturn, + List output, + EvictingQueue queue) { + for (RecordEventsSpanImpl span : queue) { if (output.size() >= maxSpansToReturn) { break; } @@ -106,7 +108,10 @@ public final class InProcessSampledSpanStoreImpl extends SampledSpanStoreImpl { } private void getSamplesFilteredByLatency( - long latencyLowerNs, long latencyUpperNs, int maxSpansToReturn, List output) { + long latencyLowerNs, + long latencyUpperNs, + int maxSpansToReturn, + List output) { getSamplesFilteredByLatency( latencyLowerNs, latencyUpperNs, maxSpansToReturn, output, sampledSpansQueue); getSamplesFilteredByLatency( @@ -117,9 +122,9 @@ public final class InProcessSampledSpanStoreImpl extends SampledSpanStoreImpl { long latencyLowerNs, long latencyUpperNs, int maxSpansToReturn, - List output, - EvictingQueue queue) { - for (SpanImpl span : queue) { + List output, + EvictingQueue queue) { + for (RecordEventsSpanImpl span : queue) { if (output.size() >= maxSpansToReturn) { break; } @@ -173,7 +178,7 @@ public final class InProcessSampledSpanStoreImpl extends SampledSpanStoreImpl { return errorBuckets[code.value() - 1]; } - private void considerForSampling(SpanImpl span) { + private void considerForSampling(RecordEventsSpanImpl span) { Status status = span.getStatus(); // Null status means running Span, this should not happen in production, but the library // should not crash because of this. @@ -208,8 +213,10 @@ public final class InProcessSampledSpanStoreImpl extends SampledSpanStoreImpl { return errorBucketSummaries; } - private List getErrorSamples(@Nullable CanonicalCode code, int maxSpansToReturn) { - ArrayList output = new ArrayList(maxSpansToReturn); + private List getErrorSamples( + @Nullable CanonicalCode code, int maxSpansToReturn) { + ArrayList output = + new ArrayList(maxSpansToReturn); if (code != null) { getErrorBucket(code).getSamples(maxSpansToReturn, output); } else { @@ -220,9 +227,10 @@ public final class InProcessSampledSpanStoreImpl extends SampledSpanStoreImpl { return output; } - private List getLatencySamples( + private List getLatencySamples( long latencyLowerNs, long latencyUpperNs, int maxSpansToReturn) { - ArrayList output = new ArrayList(maxSpansToReturn); + ArrayList output = + new ArrayList(maxSpansToReturn); for (int i = 0; i < NUM_LATENCY_BUCKETS; i++) { LatencyBucketBoundaries boundaries = LatencyBucketBoundaries.values()[i]; if (latencyUpperNs >= boundaries.getLatencyLowerNs() @@ -257,7 +265,7 @@ public final class InProcessSampledSpanStoreImpl extends SampledSpanStoreImpl { } @Override - public void considerForSampling(SpanImpl span) { + public void considerForSampling(RecordEventsSpanImpl span) { synchronized (samples) { String spanName = span.getName(); if (span.getSampleToLocalSpanStore() && !samples.containsKey(spanName)) { @@ -346,8 +354,9 @@ public final class InProcessSampledSpanStoreImpl extends SampledSpanStoreImpl { filter.getMaxSpansToReturn() == 0 ? MAX_PER_SPAN_NAME_SAMPLES : filter.getMaxSpansToReturn(); - List spans = Collections.emptyList(); - // Try to not keep the lock to much, do the SpanImpl -> SpanData conversion outside the lock. + List spans = Collections.emptyList(); + // Try to not keep the lock to much, do the RecordEventsSpanImpl -> SpanData conversion outside + // the lock. synchronized (samples) { PerSpanNameSamples perSpanNameSamples = samples.get(filter.getSpanName()); if (perSpanNameSamples != null) { @@ -355,7 +364,7 @@ public final class InProcessSampledSpanStoreImpl extends SampledSpanStoreImpl { } } List ret = new ArrayList(spans.size()); - for (SpanImpl span : spans) { + for (RecordEventsSpanImpl span : spans) { ret.add(span.toSpanData()); } return Collections.unmodifiableList(ret); @@ -367,8 +376,9 @@ public final class InProcessSampledSpanStoreImpl extends SampledSpanStoreImpl { filter.getMaxSpansToReturn() == 0 ? MAX_PER_SPAN_NAME_SAMPLES : filter.getMaxSpansToReturn(); - List spans = Collections.emptyList(); - // Try to not keep the lock to much, do the SpanImpl -> SpanData conversion outside the lock. + List spans = Collections.emptyList(); + // Try to not keep the lock to much, do the RecordEventsSpanImpl -> SpanData conversion outside + // the lock. synchronized (samples) { PerSpanNameSamples perSpanNameSamples = samples.get(filter.getSpanName()); if (perSpanNameSamples != null) { @@ -378,7 +388,7 @@ public final class InProcessSampledSpanStoreImpl extends SampledSpanStoreImpl { } } List ret = new ArrayList(spans.size()); - for (SpanImpl span : spans) { + for (RecordEventsSpanImpl span : spans) { ret.add(span.toSpanData()); } return Collections.unmodifiableList(ret); diff --git a/impl_core/src/main/java/io/opencensus/implcore/trace/export/RunningSpanStoreImpl.java b/impl_core/src/main/java/io/opencensus/implcore/trace/export/RunningSpanStoreImpl.java index 53147def..962f5b01 100644 --- a/impl_core/src/main/java/io/opencensus/implcore/trace/export/RunningSpanStoreImpl.java +++ b/impl_core/src/main/java/io/opencensus/implcore/trace/export/RunningSpanStoreImpl.java @@ -16,11 +16,8 @@ package io.opencensus.implcore.trace.export; -import io.opencensus.implcore.trace.SpanImpl; +import io.opencensus.implcore.trace.RecordEventsSpanImpl; import io.opencensus.trace.export.RunningSpanStore; -import io.opencensus.trace.export.RunningSpanStore.Filter; -import io.opencensus.trace.export.RunningSpanStore.PerSpanNameSummary; -import io.opencensus.trace.export.RunningSpanStore.Summary; import io.opencensus.trace.export.SpanData; import java.util.Collection; import java.util.Collections; @@ -41,14 +38,14 @@ public abstract class RunningSpanStoreImpl extends RunningSpanStore { * * @param span the {@code Span} that started. */ - public abstract void onStart(SpanImpl span); + public abstract void onStart(RecordEventsSpanImpl span); /** * Removes the {@code Span} from the running spans list when the {@code Span} ends. * * @param span the {@code Span} that ended. */ - public abstract void onEnd(SpanImpl span); + public abstract void onEnd(RecordEventsSpanImpl span); private static final class NoopRunningSpanStoreImpl extends RunningSpanStoreImpl { @@ -56,10 +53,10 @@ public abstract class RunningSpanStoreImpl extends RunningSpanStore { RunningSpanStore.Summary.create(Collections.emptyMap()); @Override - public void onStart(SpanImpl span) {} + public void onStart(RecordEventsSpanImpl span) {} @Override - public void onEnd(SpanImpl span) {} + public void onEnd(RecordEventsSpanImpl span) {} @Override public Summary getSummary() { diff --git a/impl_core/src/main/java/io/opencensus/implcore/trace/export/SampledSpanStoreImpl.java b/impl_core/src/main/java/io/opencensus/implcore/trace/export/SampledSpanStoreImpl.java index 302d5cd3..e67c2f8e 100644 --- a/impl_core/src/main/java/io/opencensus/implcore/trace/export/SampledSpanStoreImpl.java +++ b/impl_core/src/main/java/io/opencensus/implcore/trace/export/SampledSpanStoreImpl.java @@ -16,12 +16,8 @@ package io.opencensus.implcore.trace.export; -import io.opencensus.implcore.trace.SpanImpl; +import io.opencensus.implcore.trace.RecordEventsSpanImpl; import io.opencensus.trace.export.SampledSpanStore; -import io.opencensus.trace.export.SampledSpanStore.ErrorFilter; -import io.opencensus.trace.export.SampledSpanStore.LatencyFilter; -import io.opencensus.trace.export.SampledSpanStore.PerSpanNameSummary; -import io.opencensus.trace.export.SampledSpanStore.Summary; import io.opencensus.trace.export.SpanData; import java.util.Collection; import java.util.Collections; @@ -43,7 +39,7 @@ public abstract class SampledSpanStoreImpl extends SampledSpanStore { * * @param span the span to be consider for storing into the store buckets. */ - public abstract void considerForSampling(SpanImpl span); + public abstract void considerForSampling(RecordEventsSpanImpl span); protected void shutdown() {} @@ -59,7 +55,7 @@ public abstract class SampledSpanStoreImpl extends SampledSpanStore { } @Override - public void considerForSampling(SpanImpl span) {} + public void considerForSampling(RecordEventsSpanImpl span) {} @Override public void registerSpanNamesForCollection(Collection spanNames) {} diff --git a/impl_core/src/main/java/io/opencensus/implcore/trace/export/SpanExporterImpl.java b/impl_core/src/main/java/io/opencensus/implcore/trace/export/SpanExporterImpl.java index b9b1e98c..51a7b05c 100644 --- a/impl_core/src/main/java/io/opencensus/implcore/trace/export/SpanExporterImpl.java +++ b/impl_core/src/main/java/io/opencensus/implcore/trace/export/SpanExporterImpl.java @@ -19,7 +19,7 @@ package io.opencensus.implcore.trace.export; import com.google.common.annotations.VisibleForTesting; import io.opencensus.common.Duration; import io.opencensus.implcore.internal.DaemonThreadFactory; -import io.opencensus.implcore.trace.SpanImpl; +import io.opencensus.implcore.trace.RecordEventsSpanImpl; import io.opencensus.trace.export.ExportComponent; import io.opencensus.trace.export.SpanData; import io.opencensus.trace.export.SpanExporter; @@ -60,7 +60,7 @@ public final class SpanExporterImpl extends SpanExporter { * * @param span the {@code Span} to be added. */ - public void addSpan(SpanImpl span) { + public void addSpan(RecordEventsSpanImpl span) { worker.addSpan(span); } @@ -108,14 +108,14 @@ public final class SpanExporterImpl extends SpanExporter { private final Object monitor = new Object(); @GuardedBy("monitor") - private final List spans; + private final List spans; private final Map serviceHandlers = new ConcurrentHashMap(); private final int bufferSize; private final long scheduleDelayMillis; // See SpanExporterImpl#addSpan. - private void addSpan(SpanImpl span) { + private void addSpan(RecordEventsSpanImpl span) { synchronized (monitor) { this.spans.add(span); if (spans.size() > bufferSize) { @@ -152,16 +152,16 @@ public final class SpanExporterImpl extends SpanExporter { } private Worker(int bufferSize, Duration scheduleDelay) { - spans = new ArrayList(bufferSize); + spans = new ArrayList(bufferSize); this.bufferSize = bufferSize; this.scheduleDelayMillis = scheduleDelay.toMillis(); } // Returns an unmodifiable list of all buffered spans data to ensure that any registered // service handler cannot modify the list. - private static List fromSpanImplToSpanData(List spans) { + private static List fromSpanImplToSpanData(List spans) { List spanDatas = new ArrayList(spans.size()); - for (SpanImpl span : spans) { + for (RecordEventsSpanImpl span : spans) { spanDatas.add(span.toSpanData()); } return Collections.unmodifiableList(spanDatas); @@ -172,7 +172,7 @@ public final class SpanExporterImpl extends SpanExporter { while (true) { // Copy all the batched spans in a separate list to release the monitor lock asap to // avoid blocking the producer thread. - List spansCopy; + List spansCopy; synchronized (monitor) { if (spans.size() < bufferSize) { do { @@ -187,7 +187,7 @@ public final class SpanExporterImpl extends SpanExporter { } } while (spans.isEmpty()); } - spansCopy = new ArrayList(spans); + spansCopy = new ArrayList(spans); spans.clear(); } // Execute the batch export outside the synchronized to not block all producers. @@ -199,9 +199,9 @@ public final class SpanExporterImpl extends SpanExporter { } void flush() { - List spansCopy; + List spansCopy; synchronized (monitor) { - spansCopy = new ArrayList(spans); + spansCopy = new ArrayList(spans); spans.clear(); } -- cgit v1.2.3