1 /*
2  * Copyright 2016-17, OpenCensus Authors
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *     http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package io.opencensus.trace;
18 
19 import io.opencensus.internal.Utils;
20 import io.opencensus.trace.internal.BaseMessageEventUtils;
21 import java.util.Collections;
22 import java.util.EnumSet;
23 import java.util.Map;
24 import java.util.Set;
25 import javax.annotation.Nullable;
26 
27 /**
28  * An abstract class that represents a span. It has an associated {@link SpanContext} and a set of
29  * {@link Options}.
30  *
31  * <p>Spans are created by the {@link SpanBuilder#startSpan} method.
32  *
33  * <p>{@code Span} <b>must</b> be ended by calling {@link #end()} or {@link #end(EndSpanOptions)}
34  *
35  * @since 0.5
36  */
37 public abstract class Span {
38   private static final Map<String, AttributeValue> EMPTY_ATTRIBUTES = Collections.emptyMap();
39 
40   // Contains the identifiers associated with this Span.
41   private final SpanContext context;
42 
43   // Contains the options associated with this Span. This object is immutable.
44   private final Set<Options> options;
45 
46   /**
47    * {@code Span} options. These options are NOT propagated to child spans. These options determine
48    * features such as whether a {@code Span} should record any annotations or events.
49    *
50    * @since 0.5
51    */
52   public enum Options {
53     /**
54      * This option is set if the Span is part of a sampled distributed trace OR {@link
55      * SpanBuilder#setRecordEvents(boolean)} was called with true.
56      *
57      * @since 0.5
58      */
59     RECORD_EVENTS;
60   }
61 
62   private static final Set<Options> DEFAULT_OPTIONS =
63       Collections.unmodifiableSet(EnumSet.noneOf(Options.class));
64 
65   /**
66    * Creates a new {@code Span}.
67    *
68    * @param context the context associated with this {@code Span}.
69    * @param options the options associated with this {@code Span}. If {@code null} then default
70    *     options will be set.
71    * @throws NullPointerException if context is {@code null}.
72    * @throws IllegalArgumentException if the {@code SpanContext} is sampled but no RECORD_EVENTS
73    *     options.
74    * @since 0.5
75    */
Span(SpanContext context, @Nullable EnumSet<Options> options)76   protected Span(SpanContext context, @Nullable EnumSet<Options> options) {
77     this.context = Utils.checkNotNull(context, "context");
78     this.options =
79         options == null
80             ? DEFAULT_OPTIONS
81             : Collections.<Options>unmodifiableSet(EnumSet.copyOf(options));
82     Utils.checkArgument(
83         !context.getTraceOptions().isSampled() || (this.options.contains(Options.RECORD_EVENTS)),
84         "Span is sampled, but does not have RECORD_EVENTS set.");
85   }
86 
87   /**
88    * Sets an attribute to the {@code Span}. If the {@code Span} previously contained a mapping for
89    * the key, the old value is replaced by the specified value.
90    *
91    * @param key the key for this attribute.
92    * @param value the value for this attribute.
93    * @since 0.6
94    */
putAttribute(String key, AttributeValue value)95   public void putAttribute(String key, AttributeValue value) {
96     // Not final because for performance reasons we want to override this in the implementation.
97     // Also a default implementation is needed to not break the compatibility (users may extend this
98     // for testing).
99     Utils.checkNotNull(key, "key");
100     Utils.checkNotNull(value, "value");
101     putAttributes(Collections.singletonMap(key, value));
102   }
103 
104   /**
105    * Sets a set of attributes to the {@code Span}. The effect of this call is equivalent to that of
106    * calling {@link #putAttribute(String, AttributeValue)} once for each element in the specified
107    * map.
108    *
109    * @param attributes the attributes that will be added and associated with the {@code Span}.
110    * @since 0.6
111    */
putAttributes(Map<String, AttributeValue> attributes)112   public void putAttributes(Map<String, AttributeValue> attributes) {
113     // Not final because we want to start overriding this method from the beginning, this will
114     // allow us to remove the addAttributes faster. All implementations MUST override this method.
115     Utils.checkNotNull(attributes, "attributes");
116     addAttributes(attributes);
117   }
118 
119   /**
120    * Sets a set of attributes to the {@code Span}. The effect of this call is equivalent to that of
121    * calling {@link #putAttribute(String, AttributeValue)} once for each element in the specified
122    * map.
123    *
124    * @deprecated Use {@link #putAttributes(Map)}
125    * @param attributes the attributes that will be added and associated with the {@code Span}.
126    * @since 0.5
127    */
128   @Deprecated
addAttributes(Map<String, AttributeValue> attributes)129   public void addAttributes(Map<String, AttributeValue> attributes) {
130     putAttributes(attributes);
131   }
132 
133   /**
134    * Adds an annotation to the {@code Span}.
135    *
136    * @param description the description of the annotation time event.
137    * @since 0.5
138    */
addAnnotation(String description)139   public final void addAnnotation(String description) {
140     Utils.checkNotNull(description, "description");
141     addAnnotation(description, EMPTY_ATTRIBUTES);
142   }
143 
144   /**
145    * Adds an annotation to the {@code Span}.
146    *
147    * @param description the description of the annotation time event.
148    * @param attributes the attributes that will be added; these are associated with this annotation,
149    *     not the {@code Span} as for {@link #putAttributes(Map)}.
150    * @since 0.5
151    */
addAnnotation(String description, Map<String, AttributeValue> attributes)152   public abstract void addAnnotation(String description, Map<String, AttributeValue> attributes);
153 
154   /**
155    * Adds an annotation to the {@code Span}.
156    *
157    * @param annotation the annotations to add.
158    * @since 0.5
159    */
addAnnotation(Annotation annotation)160   public abstract void addAnnotation(Annotation annotation);
161 
162   /**
163    * Adds a NetworkEvent to the {@code Span}.
164    *
165    * <p>This function is only intended to be used by RPC systems (either client or server), not by
166    * higher level applications.
167    *
168    * @param networkEvent the network event to add.
169    * @deprecated Use {@link #addMessageEvent}.
170    * @since 0.5
171    */
172   @Deprecated
addNetworkEvent(NetworkEvent networkEvent)173   public void addNetworkEvent(NetworkEvent networkEvent) {
174     addMessageEvent(BaseMessageEventUtils.asMessageEvent(networkEvent));
175   }
176 
177   /**
178    * Adds a MessageEvent to the {@code Span}.
179    *
180    * <p>This function can be used by higher level applications to record messaging event.
181    *
182    * <p>This method should always be overridden by users whose API versions are larger or equal to
183    * {@code 0.12}.
184    *
185    * @param messageEvent the message to add.
186    * @since 0.12
187    */
addMessageEvent(MessageEvent messageEvent)188   public void addMessageEvent(MessageEvent messageEvent) {
189     // Default implementation by invoking addNetworkEvent() so that any existing derived classes,
190     // including implementation and the mocked ones, do not need to override this method explicitly.
191     Utils.checkNotNull(messageEvent, "messageEvent");
192     addNetworkEvent(BaseMessageEventUtils.asNetworkEvent(messageEvent));
193   }
194 
195   /**
196    * Adds a {@link Link} to the {@code Span}.
197    *
198    * <p>Used (for example) in batching operations, where a single batch handler processes multiple
199    * requests from different traces.
200    *
201    * @param link the link to add.
202    * @since 0.5
203    */
addLink(Link link)204   public abstract void addLink(Link link);
205 
206   /**
207    * Sets the {@link Status} to the {@code Span}.
208    *
209    * <p>If used, this will override the default {@code Span} status. Default is {@link Status#OK}.
210    *
211    * <p>Only the value of the last call will be recorded, and implementations are free to ignore
212    * previous calls. If the status is set via {@link EndSpanOptions.Builder#setStatus(Status)} that
213    * will always be the last call.
214    *
215    * @param status the {@link Status} to set.
216    * @since 0.9
217    */
setStatus(Status status)218   public void setStatus(Status status) {
219     // Implemented as no-op for backwards compatibility (for example gRPC extends Span in tests).
220     // Implementation must override this method.
221     Utils.checkNotNull(status, "status");
222   }
223 
224   /**
225    * Marks the end of {@code Span} execution with the given options.
226    *
227    * <p>Only the timing of the first end call for a given {@code Span} will be recorded, and
228    * implementations are free to ignore all further calls.
229    *
230    * @param options the options to be used for the end of the {@code Span}.
231    * @since 0.5
232    */
end(EndSpanOptions options)233   public abstract void end(EndSpanOptions options);
234 
235   /**
236    * Marks the end of {@code Span} execution with the default options.
237    *
238    * <p>Only the timing of the first end call for a given {@code Span} will be recorded, and
239    * implementations are free to ignore all further calls.
240    *
241    * @since 0.5
242    */
end()243   public final void end() {
244     end(EndSpanOptions.DEFAULT);
245   }
246 
247   /**
248    * Returns the {@code SpanContext} associated with this {@code Span}.
249    *
250    * @return the {@code SpanContext} associated with this {@code Span}.
251    * @since 0.5
252    */
getContext()253   public final SpanContext getContext() {
254     return context;
255   }
256 
257   /**
258    * Returns the options associated with this {@code Span}.
259    *
260    * @return the options associated with this {@code Span}.
261    * @since 0.5
262    */
getOptions()263   public final Set<Options> getOptions() {
264     return options;
265   }
266 
267   /**
268    * Type of span. Can be used to specify additional relationships between spans in addition to a
269    * parent/child relationship.
270    *
271    * @since 0.14
272    */
273   public enum Kind {
274     /**
275      * Indicates that the span covers server-side handling of an RPC or other remote request.
276      *
277      * @since 0.14
278      */
279     SERVER,
280 
281     /**
282      * Indicates that the span covers the client-side wrapper around an RPC or other remote request.
283      *
284      * @since 0.14
285      */
286     CLIENT
287   }
288 }
289