/* * Copyright 2016-17, 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.trace; import io.opencensus.internal.Utils; import io.opencensus.trace.internal.BaseMessageEventUtils; import java.util.Collections; import java.util.EnumSet; import java.util.Map; import java.util.Set; import javax.annotation.Nullable; /** * An abstract class that represents a span. It has an associated {@link SpanContext} and a set of * {@link Options}. * *

Spans are created by the {@link SpanBuilder#startSpan} method. * *

{@code Span} must be ended by calling {@link #end()} or {@link #end(EndSpanOptions)} * * @since 0.5 */ public abstract class Span { private static final Map EMPTY_ATTRIBUTES = Collections.emptyMap(); // Contains the identifiers associated with this Span. private final SpanContext context; // Contains the options associated with this Span. This object is immutable. private final Set options; /** * {@code Span} options. These options are NOT propagated to child spans. These options determine * features such as whether a {@code Span} should record any annotations or events. * * @since 0.5 */ public enum Options { /** * This option is set if the Span is part of a sampled distributed trace OR {@link * SpanBuilder#setRecordEvents(boolean)} was called with true. * * @since 0.5 */ RECORD_EVENTS; } private static final Set DEFAULT_OPTIONS = Collections.unmodifiableSet(EnumSet.noneOf(Options.class)); /** * Creates a new {@code Span}. * * @param context the context associated with this {@code Span}. * @param options the options associated with this {@code Span}. If {@code null} then default * options will be set. * @throws NullPointerException if context is {@code null}. * @throws IllegalArgumentException if the {@code SpanContext} is sampled but no RECORD_EVENTS * options. * @since 0.5 */ protected Span(SpanContext context, @Nullable EnumSet options) { this.context = Utils.checkNotNull(context, "context"); this.options = options == null ? DEFAULT_OPTIONS : Collections.unmodifiableSet(EnumSet.copyOf(options)); Utils.checkArgument( !context.getTraceOptions().isSampled() || (this.options.contains(Options.RECORD_EVENTS)), "Span is sampled, but does not have RECORD_EVENTS set."); } /** * Sets an attribute to the {@code Span}. If the {@code Span} previously contained a mapping for * the key, the old value is replaced by the specified value. * * @param key the key for this attribute. * @param value the value for this attribute. * @since 0.6 */ public void putAttribute(String key, AttributeValue value) { // Not final because for performance reasons we want to override this in the implementation. // Also a default implementation is needed to not break the compatibility (users may extend this // for testing). Utils.checkNotNull(key, "key"); Utils.checkNotNull(value, "value"); putAttributes(Collections.singletonMap(key, value)); } /** * Sets a set of attributes to the {@code Span}. The effect of this call is equivalent to that of * calling {@link #putAttribute(String, AttributeValue)} once for each element in the specified * map. * * @param attributes the attributes that will be added and associated with the {@code Span}. * @since 0.6 */ public void putAttributes(Map attributes) { // Not final because we want to start overriding this method from the beginning, this will // allow us to remove the addAttributes faster. All implementations MUST override this method. Utils.checkNotNull(attributes, "attributes"); addAttributes(attributes); } /** * Sets a set of attributes to the {@code Span}. The effect of this call is equivalent to that of * calling {@link #putAttribute(String, AttributeValue)} once for each element in the specified * map. * * @deprecated Use {@link #putAttributes(Map)} * @param attributes the attributes that will be added and associated with the {@code Span}. * @since 0.5 */ @Deprecated public void addAttributes(Map attributes) { putAttributes(attributes); } /** * Adds an annotation to the {@code Span}. * * @param description the description of the annotation time event. * @since 0.5 */ public final void addAnnotation(String description) { Utils.checkNotNull(description, "description"); addAnnotation(description, EMPTY_ATTRIBUTES); } /** * Adds an annotation to the {@code Span}. * * @param description the description of the annotation time event. * @param attributes the attributes that will be added; these are associated with this annotation, * not the {@code Span} as for {@link #putAttributes(Map)}. * @since 0.5 */ public abstract void addAnnotation(String description, Map attributes); /** * Adds an annotation to the {@code Span}. * * @param annotation the annotations to add. * @since 0.5 */ public abstract void addAnnotation(Annotation annotation); /** * Adds a NetworkEvent to the {@code Span}. * *

This function is only intended to be used by RPC systems (either client or server), not by * higher level applications. * * @param networkEvent the network event to add. * @deprecated Use {@link #addMessageEvent}. * @since 0.5 */ @Deprecated public void addNetworkEvent(NetworkEvent networkEvent) { addMessageEvent(BaseMessageEventUtils.asMessageEvent(networkEvent)); } /** * Adds a MessageEvent to the {@code Span}. * *

This function can be used by higher level applications to record messaging event. * *

This method should always be overridden by users whose API versions are larger or equal to * {@code 0.12}. * * @param messageEvent the message to add. * @since 0.12 */ public void addMessageEvent(MessageEvent messageEvent) { // Default implementation by invoking addNetworkEvent() so that any existing derived classes, // including implementation and the mocked ones, do not need to override this method explicitly. Utils.checkNotNull(messageEvent, "messageEvent"); addNetworkEvent(BaseMessageEventUtils.asNetworkEvent(messageEvent)); } /** * Adds a {@link Link} to the {@code Span}. * *

Used (for example) in batching operations, where a single batch handler processes multiple * requests from different traces. * * @param link the link to add. * @since 0.5 */ public abstract void addLink(Link link); /** * Sets the {@link Status} to the {@code Span}. * *

If used, this will override the default {@code Span} status. Default is {@link Status#OK}. * *

Only the value of the last call will be recorded, and implementations are free to ignore * previous calls. If the status is set via {@link EndSpanOptions.Builder#setStatus(Status)} that * will always be the last call. * * @param status the {@link Status} to set. * @since 0.9 */ public void setStatus(Status status) { // Implemented as no-op for backwards compatibility (for example gRPC extends Span in tests). // Implementation must override this method. Utils.checkNotNull(status, "status"); } /** * Marks the end of {@code Span} execution with the given options. * *

Only the timing of the first end call for a given {@code Span} will be recorded, and * implementations are free to ignore all further calls. * * @param options the options to be used for the end of the {@code Span}. * @since 0.5 */ public abstract void end(EndSpanOptions options); /** * Marks the end of {@code Span} execution with the default options. * *

Only the timing of the first end call for a given {@code Span} will be recorded, and * implementations are free to ignore all further calls. * * @since 0.5 */ public final void end() { end(EndSpanOptions.DEFAULT); } /** * Returns the {@code SpanContext} associated with this {@code Span}. * * @return the {@code SpanContext} associated with this {@code Span}. * @since 0.5 */ public final SpanContext getContext() { return context; } /** * Returns the options associated with this {@code Span}. * * @return the options associated with this {@code Span}. * @since 0.5 */ public final Set getOptions() { return options; } /** * Type of span. Can be used to specify additional relationships between spans in addition to a * parent/child relationship. * * @since 0.14 */ public enum Kind { /** * Indicates that the span covers server-side handling of an RPC or other remote request. * * @since 0.14 */ SERVER, /** * Indicates that the span covers the client-side wrapper around an RPC or other remote request. * * @since 0.14 */ CLIENT } }