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