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 com.google.errorprone.annotations.MustBeClosed;
20 import io.opencensus.common.Scope;
21 import io.opencensus.internal.Utils;
22 import io.opencensus.trace.SpanBuilder.NoopSpanBuilder;
23 import java.util.concurrent.Callable;
24 import javax.annotation.Nullable;
25 
26 /**
27  * Tracer is a simple, thin class for {@link Span} creation and in-process context interaction.
28  *
29  * <p>Users may choose to use manual or automatic Context propagation. Because of that this class
30  * offers APIs to facilitate both usages.
31  *
32  * <p>The automatic context propagation is done using {@link io.grpc.Context} which is a gRPC
33  * independent implementation for in-process Context propagation mechanism which can carry
34  * scoped-values across API boundaries and between threads. Users of the library must propagate the
35  * {@link io.grpc.Context} between different threads.
36  *
37  * <p>Example usage with automatic context propagation:
38  *
39  * <pre>{@code
40  * class MyClass {
41  *   private static final Tracer tracer = Tracing.getTracer();
42  *   void doWork() {
43  *     try(Scope ss = tracer.spanBuilder("MyClass.DoWork").startScopedSpan()) {
44  *       tracer.getCurrentSpan().addAnnotation("Starting the work.");
45  *       doWorkInternal();
46  *       tracer.getCurrentSpan().addAnnotation("Finished working.");
47  *     }
48  *   }
49  * }
50  * }</pre>
51  *
52  * <p>Example usage with manual context propagation:
53  *
54  * <pre>{@code
55  * class MyClass {
56  *   private static final Tracer tracer = Tracing.getTracer();
57  *   void doWork(Span parent) {
58  *     Span childSpan = tracer.spanBuilderWithExplicitParent("MyChildSpan", parent).startSpan();
59  *     childSpan.addAnnotation("Starting the work.");
60  *     try {
61  *       doSomeWork(childSpan); // Manually propagate the new span down the stack.
62  *     } finally {
63  *       // To make sure we end the span even in case of an exception.
64  *       childSpan.end();  // Manually end the span.
65  *     }
66  *   }
67  * }
68  * }</pre>
69  *
70  * @since 0.5
71  */
72 public abstract class Tracer {
73   private static final NoopTracer noopTracer = new NoopTracer();
74 
75   /**
76    * Returns the no-op implementation of the {@code Tracer}.
77    *
78    * @return the no-op implementation of the {@code Tracer}.
79    */
getNoopTracer()80   static Tracer getNoopTracer() {
81     return noopTracer;
82   }
83 
84   /**
85    * Gets the current Span from the current Context.
86    *
87    * <p>To install a {@link Span} to the current Context use {@link #withSpan(Span)} OR use {@link
88    * SpanBuilder#startScopedSpan} methods to start a new {@code Span}.
89    *
90    * <p>startSpan methods do NOT modify the current Context {@code Span}.
91    *
92    * @return a default {@code Span} that does nothing and has an invalid {@link SpanContext} if no
93    *     {@code Span} is associated with the current Context, otherwise the current {@code Span}
94    *     from the Context.
95    * @since 0.5
96    */
getCurrentSpan()97   public final Span getCurrentSpan() {
98     Span currentSpan = CurrentSpanUtils.getCurrentSpan();
99     return currentSpan != null ? currentSpan : BlankSpan.INSTANCE;
100   }
101 
102   /**
103    * Enters the scope of code where the given {@link Span} is in the current Context, and returns an
104    * object that represents that scope. The scope is exited when the returned object is closed.
105    *
106    * <p>Supports try-with-resource idiom.
107    *
108    * <p>Can be called with {@link BlankSpan} to enter a scope of code where tracing is stopped.
109    *
110    * <p>Example of usage:
111    *
112    * <pre>{@code
113    * private static Tracer tracer = Tracing.getTracer();
114    * void doWork() {
115    *   // Create a Span as a child of the current Span.
116    *   Span span = tracer.spanBuilder("my span").startSpan();
117    *   try (Scope ws = tracer.withSpan(span)) {
118    *     tracer.getCurrentSpan().addAnnotation("my annotation");
119    *     doSomeOtherWork();  // Here "span" is the current Span.
120    *   }
121    *   span.end();
122    * }
123    * }</pre>
124    *
125    * <p>Prior to Java SE 7, you can use a finally block to ensure that a resource is closed
126    * regardless of whether the try statement completes normally or abruptly.
127    *
128    * <p>Example of usage prior to Java SE7:
129    *
130    * <pre>{@code
131    * private static Tracer tracer = Tracing.getTracer();
132    * void doWork() {
133    *   // Create a Span as a child of the current Span.
134    *   Span span = tracer.spanBuilder("my span").startSpan();
135    *   Scope ws = tracer.withSpan(span);
136    *   try {
137    *     tracer.getCurrentSpan().addAnnotation("my annotation");
138    *     doSomeOtherWork();  // Here "span" is the current Span.
139    *   } finally {
140    *     ws.close();
141    *   }
142    *   span.end();
143    * }
144    * }</pre>
145    *
146    * @param span The {@link Span} to be set to the current Context.
147    * @return an object that defines a scope where the given {@link Span} will be set to the current
148    *     Context.
149    * @throws NullPointerException if {@code span} is {@code null}.
150    * @since 0.5
151    */
152   @MustBeClosed
withSpan(Span span)153   public final Scope withSpan(Span span) {
154     return CurrentSpanUtils.withSpan(Utils.checkNotNull(span, "span"), /* endSpan= */ false);
155   }
156 
157   /**
158    * Returns a {@link Runnable} that runs the given task with the given {@code Span} in the current
159    * context.
160    *
161    * <p>Users may consider to use {@link SpanBuilder#startSpanAndRun(Runnable)}.
162    *
163    * <p>Any error will end up as a {@link Status#UNKNOWN}.
164    *
165    * <p>IMPORTANT: Caller must manually propagate the entire {@code io.grpc.Context} when wraps a
166    * {@code Runnable}, see the examples.
167    *
168    * <p>IMPORTANT: Caller must manually end the {@code Span} within the {@code Runnable}, or after
169    * the {@code Runnable} is executed.
170    *
171    * <p>Example with Executor wrapped with {@link io.grpc.Context#currentContextExecutor}:
172    *
173    * <pre><code>
174    * class MyClass {
175    *   private static Tracer tracer = Tracing.getTracer();
176    *   void handleRequest(Executor executor) {
177    *     Span span = tracer.spanBuilder("MyRunnableSpan").startSpan();
178    *     executor.execute(tracer.withSpan(span, new Runnable() {
179    *      {@literal @}Override
180    *       public void run() {
181    *         try {
182    *           sendResult();
183    *         } finally {
184    *           span.end();
185    *         }
186    *       }
187    *     }));
188    *   }
189    * }
190    * </code></pre>
191    *
192    * <p>Example without Executor wrapped with {@link io.grpc.Context#currentContextExecutor}:
193    *
194    * <pre><code>
195    * class MyClass {
196    *   private static Tracer tracer = Tracing.getTracer();
197    *   void handleRequest(Executor executor) {
198    *     Span span = tracer.spanBuilder("MyRunnableSpan").startSpan();
199    *     executor.execute(Context.wrap(tracer.withSpan(span, new Runnable() {
200    *      {@literal @}Override
201    *       public void run() {
202    *         try {
203    *           sendResult();
204    *         } finally {
205    *           span.end();
206    *         }
207    *       }
208    *     })));
209    *   }
210    * }
211    * </code></pre>
212    *
213    * @param span the {@code Span} to be set as current.
214    * @param runnable the {@code Runnable} to withSpan in the {@code Span}.
215    * @return the {@code Runnable}.
216    * @since 0.11.0
217    */
withSpan(Span span, Runnable runnable)218   public final Runnable withSpan(Span span, Runnable runnable) {
219     return CurrentSpanUtils.withSpan(span, /* endSpan= */ false, runnable);
220   }
221 
222   /**
223    * Returns a {@link Callable} that runs the given task with the given {@code Span} in the current
224    * context.
225    *
226    * <p>Users may consider to use {@link SpanBuilder#startSpanAndCall(Callable)}.
227    *
228    * <p>Any error will end up as a {@link Status#UNKNOWN}.
229    *
230    * <p>IMPORTANT: Caller must manually propagate the entire {@code io.grpc.Context} when wraps a
231    * {@code Callable}, see the examples.
232    *
233    * <p>IMPORTANT: Caller must manually end the {@code Span} within the {@code Callable}, or after
234    * the {@code Callable} is executed.
235    *
236    * <p>Example with Executor wrapped with {@link io.grpc.Context#currentContextExecutor}:
237    *
238    * <pre><code>
239    * class MyClass {
240    *   private static Tracer tracer = Tracing.getTracer();
241    *   void handleRequest(Executor executor) {
242    *     Span span = tracer.spanBuilder("MyRunnableSpan").startSpan();
243    *     executor.execute(tracer.withSpan(span, {@code new Callable<MyResult>()} {
244    *      {@literal @}Override
245    *       public MyResult call() throws Exception {
246    *         try {
247    *           return sendResult();
248    *         } finally {
249    *           span.end();
250    *         }
251    *       }
252    *     }));
253    *   }
254    * }
255    * </code></pre>
256    *
257    * <p>Example without Executor wrapped with {@link io.grpc.Context#currentContextExecutor}:
258    *
259    * <pre><code>
260    * class MyClass {
261    *   private static Tracer tracer = Tracing.getTracer();
262    *   void handleRequest(Executor executor) {
263    *     Span span = tracer.spanBuilder("MyRunnableSpan").startSpan();
264    *     executor.execute(Context.wrap(tracer.withSpan(span, {@code new Callable<MyResult>()} {
265    *      {@literal @}Override
266    *       public MyResult call() throws Exception {
267    *         try {
268    *           return sendResult();
269    *         } finally {
270    *           span.end();
271    *         }
272    *       }
273    *     })));
274    *   }
275    * }
276    * </code></pre>
277    *
278    * @param span the {@code Span} to be set as current.
279    * @param callable the {@code Callable} to run in the {@code Span}.
280    * @return the {@code Callable}.
281    * @since 0.11.0
282    */
withSpan(Span span, final Callable<C> callable)283   public final <C> Callable<C> withSpan(Span span, final Callable<C> callable) {
284     return CurrentSpanUtils.withSpan(span, /* endSpan= */ false, callable);
285   }
286 
287   /**
288    * Returns a {@link SpanBuilder} to create and start a new child {@link Span} as a child of to the
289    * current {@code Span} if any, otherwise creates a root {@code Span}.
290    *
291    * <p>See {@link SpanBuilder} for usage examples.
292    *
293    * <p>This <b>must</b> be used to create a {@code Span} when automatic Context propagation is
294    * used.
295    *
296    * <p>This is equivalent with:
297    *
298    * <pre>{@code
299    * tracer.spanBuilderWithExplicitParent("MySpanName",tracer.getCurrentSpan());
300    * }</pre>
301    *
302    * @param spanName The name of the returned Span.
303    * @return a {@code SpanBuilder} to create and start a new {@code Span}.
304    * @throws NullPointerException if {@code spanName} is {@code null}.
305    * @since 0.5
306    */
spanBuilder(String spanName)307   public final SpanBuilder spanBuilder(String spanName) {
308     return spanBuilderWithExplicitParent(spanName, CurrentSpanUtils.getCurrentSpan());
309   }
310 
311   /**
312    * Returns a {@link SpanBuilder} to create and start a new child {@link Span} (or root if parent
313    * is {@code null} or has an invalid {@link SpanContext}), with parent being the designated {@code
314    * Span}.
315    *
316    * <p>See {@link SpanBuilder} for usage examples.
317    *
318    * <p>This <b>must</b> be used to create a {@code Span} when manual Context propagation is used OR
319    * when creating a root {@code Span} with a {@code null} parent.
320    *
321    * @param spanName The name of the returned Span.
322    * @param parent The parent of the returned Span. If {@code null} the {@code SpanBuilder} will
323    *     build a root {@code Span}.
324    * @return a {@code SpanBuilder} to create and start a new {@code Span}.
325    * @throws NullPointerException if {@code spanName} is {@code null}.
326    * @since 0.5
327    */
spanBuilderWithExplicitParent(String spanName, @Nullable Span parent)328   public abstract SpanBuilder spanBuilderWithExplicitParent(String spanName, @Nullable Span parent);
329 
330   /**
331    * Returns a {@link SpanBuilder} to create and start a new child {@link Span} (or root if parent
332    * is {@link SpanContext#INVALID} or {@code null}), with parent being the remote {@link Span}
333    * designated by the {@link SpanContext}.
334    *
335    * <p>See {@link SpanBuilder} for usage examples.
336    *
337    * <p>This <b>must</b> be used to create a {@code Span} when the parent is in a different process.
338    * This is only intended for use by RPC systems or similar.
339    *
340    * <p>If no {@link SpanContext} OR fail to parse the {@link SpanContext} on the server side, users
341    * must call this method with a {@code null} remote parent {@code SpanContext}.
342    *
343    * @param spanName The name of the returned Span.
344    * @param remoteParentSpanContext The remote parent of the returned Span.
345    * @return a {@code SpanBuilder} to create and start a new {@code Span}.
346    * @throws NullPointerException if {@code spanName} is {@code null}.
347    * @since 0.5
348    */
spanBuilderWithRemoteParent( String spanName, @Nullable SpanContext remoteParentSpanContext)349   public abstract SpanBuilder spanBuilderWithRemoteParent(
350       String spanName, @Nullable SpanContext remoteParentSpanContext);
351 
352   // No-Op implementation of the Tracer.
353   private static final class NoopTracer extends Tracer {
354 
355     @Override
spanBuilderWithExplicitParent(String spanName, @Nullable Span parent)356     public SpanBuilder spanBuilderWithExplicitParent(String spanName, @Nullable Span parent) {
357       return NoopSpanBuilder.createWithParent(spanName, parent);
358     }
359 
360     @Override
spanBuilderWithRemoteParent( String spanName, @Nullable SpanContext remoteParentSpanContext)361     public SpanBuilder spanBuilderWithRemoteParent(
362         String spanName, @Nullable SpanContext remoteParentSpanContext) {
363       return NoopSpanBuilder.createWithRemoteParent(spanName, remoteParentSpanContext);
364     }
365 
NoopTracer()366     private NoopTracer() {}
367   }
368 
Tracer()369   protected Tracer() {}
370 }
371