From a6f664abb28bbb2560c61a4517e1b558ea640b05 Mon Sep 17 00:00:00 2001 From: Carlos Alberto Cortez Date: Wed, 13 Sep 2017 22:03:33 +0200 Subject: [PATCH 1/5] Implement a simpler Span propagation without lifetime handling. --- .../main/java/io/opentracing/ActiveSpan.java | 109 ------------- .../java/io/opentracing/ActiveSpanSource.java | 50 ------ .../main/java/io/opentracing/BaseSpan.java | 143 ----------------- .../src/main/java/io/opentracing/Scope.java | 43 +++++ .../java/io/opentracing/ScopeManager.java | 47 ++++++ .../src/main/java/io/opentracing/Span.java | 130 ++++++++++++++- .../src/main/java/io/opentracing/Tracer.java | 54 ++++--- .../java/io/opentracing/tag/AbstractTag.java | 4 +- .../java/io/opentracing/tag/BooleanTag.java | 4 +- .../main/java/io/opentracing/tag/IntTag.java | 4 +- .../java/io/opentracing/tag/StringTag.java | 6 +- .../io/opentracing/tag/AbstractTagTest.java | 16 +- .../java/io/opentracing/mock/MockTracer.java | 70 ++++---- .../noop/NoopActiveSpanSource.java | 120 -------------- .../io/opentracing/noop/NoopScopeManager.java | 56 +++++++ .../java/io/opentracing/noop/NoopSpan.java | 2 +- .../io/opentracing/noop/NoopSpanBuilder.java | 20 ++- .../java/io/opentracing/noop/NoopTracer.java | 18 +-- .../io/opentracing/util/GlobalTracer.java | 18 +-- .../util/ThreadLocalActiveSpan.java | 149 ------------------ .../io/opentracing/util/ThreadLocalScope.java | 57 +++++++ ...urce.java => ThreadLocalScopeManager.java} | 28 ++-- ....java => ThreadLocalScopeManagerTest.java} | 36 +++-- ...panTest.java => ThreadLocalScopeTest.java} | 58 ++----- 24 files changed, 468 insertions(+), 774 deletions(-) delete mode 100644 opentracing-api/src/main/java/io/opentracing/ActiveSpan.java delete mode 100644 opentracing-api/src/main/java/io/opentracing/ActiveSpanSource.java delete mode 100644 opentracing-api/src/main/java/io/opentracing/BaseSpan.java create mode 100644 opentracing-api/src/main/java/io/opentracing/Scope.java create mode 100644 opentracing-api/src/main/java/io/opentracing/ScopeManager.java delete mode 100644 opentracing-noop/src/main/java/io/opentracing/noop/NoopActiveSpanSource.java create mode 100644 opentracing-noop/src/main/java/io/opentracing/noop/NoopScopeManager.java delete mode 100644 opentracing-util/src/main/java/io/opentracing/util/ThreadLocalActiveSpan.java create mode 100644 opentracing-util/src/main/java/io/opentracing/util/ThreadLocalScope.java rename opentracing-util/src/main/java/io/opentracing/util/{ThreadLocalActiveSpanSource.java => ThreadLocalScopeManager.java} (50%) rename opentracing-util/src/test/java/io/opentracing/util/{ThreadLocalActiveSpanSourceTest.java => ThreadLocalScopeManagerTest.java} (61%) rename opentracing-util/src/test/java/io/opentracing/util/{ThreadLocalActiveSpanTest.java => ThreadLocalScopeTest.java} (56%) diff --git a/opentracing-api/src/main/java/io/opentracing/ActiveSpan.java b/opentracing-api/src/main/java/io/opentracing/ActiveSpan.java deleted file mode 100644 index 46e09d08..00000000 --- a/opentracing-api/src/main/java/io/opentracing/ActiveSpan.java +++ /dev/null @@ -1,109 +0,0 @@ -/* - * Copyright 2016-2017 The OpenTracing 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.opentracing; - -import java.io.Closeable; - -/** - * {@link ActiveSpan} inherits all of the OpenTracing functionality in {@link BaseSpan} and layers on in-process - * propagation capabilities. - * - *

- * In any given thread there is at most one {@link ActiveSpan "active" span} primarily responsible for the work - * accomplished by the surrounding application code. That {@link ActiveSpan} may be accessed via the - * {@link ActiveSpanSource#activeSpan()} method. If the application needs to defer work that should be part of - * the same Span, the Source provides a {@link ActiveSpan#capture} method that returns a {@link Continuation}; - * this continuation may be used to re-activate and continue the {@link Span} in that other asynchronous executor - * and/or thread. - * - *

- * {@link ActiveSpan}s are created via {@link Tracer.SpanBuilder#startActive()} or, less commonly, - * {@link ActiveSpanSource#makeActive}. Per the above, they can be {@link ActiveSpan#capture()}ed as - * {@link ActiveSpan.Continuation}s, then re-{@link Continuation#activate()}d later. - * - *

- * NOTE: {@link ActiveSpan} extends {@link Closeable} rather than {@code AutoCloseable} in order to preserve support - * for JDK1.6. - * - * @see Tracer.SpanBuilder#startActive() - * @see Continuation#activate() - * @see ActiveSpanSource - * @see BaseSpan - * @see Span - */ -public interface ActiveSpan extends Closeable, BaseSpan { - /** - * Mark the end of the active period for the current thread and {@link ActiveSpan}. When the last - * {@link ActiveSpan} is deactivated for a given {@link Span}, it is automatically {@link Span#finish()}ed. - * - *

- * NOTE: Calling {@link #deactivate} more than once on a single {@link ActiveSpan} instance leads to undefined - * behavior. - * - * @see Closeable#close() {@link ActiveSpan}s are auto-closeable and may be used in try-with-resources blocks - */ - void deactivate(); - - /** - * A synonym for {@link #deactivate()} that can be used in try-with-resources blocks. - */ - @Override - void close(); - - /** - * "Capture" a new {@link Continuation} associated with this {@link ActiveSpan} and {@link Span}, as well as any - * 3rd-party execution context of interest. The {@link Continuation} may be used as data in a closure or callback - * function where the {@link ActiveSpan} may be resumed and reactivated. - * - *

- * IMPORTANT: the caller MUST {@link Continuation#activate()} and {@link ActiveSpan#deactivate()} the - * returned {@link Continuation} or the associated {@link Span} will never automatically {@link Span#finish()}. - * That is, calling {@link #capture()} increments a refcount that must be decremented somewhere else. - * - *

- * The associated {@link Span} will not {@link Span#finish()} while a {@link Continuation} is outstanding; in - * this way, it provides a reference/pin just like an {@link ActiveSpan} does. - * - * @return a new {@link Continuation} to {@link Continuation#activate()} at the appropriate time. - */ - Continuation capture(); - - /** - * A {@link Continuation} can be used once to activate a Span along with any non-OpenTracing execution - * context (e.g., MDC), then deactivate when processing activity moves on to another Span. (In practice, this - * active period typically extends for the length of a deferred async closure invocation.) - * - *

- * Most users do not directly interact with {@link Continuation}, {@link Continuation#activate()} or - * {@link ActiveSpan#deactivate()}, but rather use {@link ActiveSpanSource}-aware Runnables/Callables/Executors. - * Those higher-level primitives do not need to be defined within the OpenTracing core API, and so - * they are not. - * - * @see ActiveSpanSource#makeActive(Span) - */ - interface Continuation { - /** - * Make the Span (and other execution context) encapsulated by this {@link Continuation} active and - * return it. - * - *

- * NOTE: It is an error to call activate() more than once on a single Continuation instance. - * - * @see ActiveSpanSource#makeActive(Span) - * @return a handle to the newly-activated {@link ActiveSpan} - */ - ActiveSpan activate(); - } - -} diff --git a/opentracing-api/src/main/java/io/opentracing/ActiveSpanSource.java b/opentracing-api/src/main/java/io/opentracing/ActiveSpanSource.java deleted file mode 100644 index 334d00e8..00000000 --- a/opentracing-api/src/main/java/io/opentracing/ActiveSpanSource.java +++ /dev/null @@ -1,50 +0,0 @@ -/* - * Copyright 2016-2017 The OpenTracing 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.opentracing; - -/** - * {@link ActiveSpanSource} allows an existing (possibly thread-local-aware) execution context provider to act as a - * source for an actively-scheduled OpenTracing Span. - * - *

- * {@link ActiveSpanSource} is a super-interface to {@link Tracer}, so note that all {@link Tracer}s fulfill the - * {@link ActiveSpanSource} contract. - * - * @see ActiveSpan - */ -public interface ActiveSpanSource { - - /** - * Return the {@link ActiveSpan active span}. This does not affect the internal reference count for the - * {@link ActiveSpan}. - * - *

- * If there is an {@link ActiveSpan active span}, it becomes an implicit parent of any newly-created - * {@link BaseSpan span} at {@link Tracer.SpanBuilder#startActive()} time (rather than at - * {@link Tracer#buildSpan(String)} time). - * - * @return the {@link ActiveSpan active span}, or null if none could be found. - */ - ActiveSpan activeSpan(); - - /** - * Wrap and "make active" a {@link Span} by encapsulating it – and any active state (e.g., MDC state) in the - * current thread – in a new {@link ActiveSpan}. - * - * @param span the Span to wrap in an {@link ActiveSpan} - * @return an {@link ActiveSpan} that encapsulates the given {@link Span} and any other - * {@link ActiveSpanSource}-specific context (e.g., the MDC context map) - */ - ActiveSpan makeActive(Span span); -} diff --git a/opentracing-api/src/main/java/io/opentracing/BaseSpan.java b/opentracing-api/src/main/java/io/opentracing/BaseSpan.java deleted file mode 100644 index b83bc190..00000000 --- a/opentracing-api/src/main/java/io/opentracing/BaseSpan.java +++ /dev/null @@ -1,143 +0,0 @@ -/* - * Copyright 2016-2017 The OpenTracing 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.opentracing; - -import java.util.Map; - -/** - * {@link BaseSpan} represents the OpenTracing specification's span contract with the exception of methods to finish - * said span. For those, either use {@link Span#finish()} or {@link ActiveSpan#deactivate()} depending on the - * programming model. - * - * @see Span - * @see ActiveSpan - * @see Tracer.SpanBuilder#startManual() - * @see Tracer.SpanBuilder#startActive() - */ -public interface BaseSpan { - /** - * Retrieve the associated SpanContext. - * - * This may be called at any time, including after calls to finish(). - * - * @return the SpanContext that encapsulates Span state that should propagate across process boundaries. - */ - SpanContext context(); - - /** - * Set a key:value tag on the Span. - */ - S setTag(String key, String value); - - /** Same as {@link #setTag(String, String)}, but for boolean values. */ - S setTag(String key, boolean value); - - /** Same as {@link #setTag(String, String)}, but for numeric values. */ - S setTag(String key, Number value); - - /** - * Log key:value pairs to the Span with the current walltime timestamp. - * - *

CAUTIONARY NOTE: not all Tracer implementations support key:value log fields end-to-end. - * Caveat emptor. - * - *

A contrived example (using Guava, which is not required): - *


-     span.log(
-     ImmutableMap.Builder()
-     .put("event", "soft error")
-     .put("type", "cache timeout")
-     .put("waited.millis", 1500)
-     .build());
-     
- * - * @param fields key:value log fields. Tracer implementations should support String, numeric, and boolean values; - * some may also support arbitrary Objects. - * @return the Span, for chaining - * @see Span#log(String) - */ - S log(Map fields); - - /** - * Like log(Map<String, Object>), but with an explicit timestamp. - * - *

CAUTIONARY NOTE: not all Tracer implementations support key:value log fields end-to-end. - * Caveat emptor. - * - * @param timestampMicroseconds The explicit timestamp for the log record. Must be greater than or equal to the - * Span's start timestamp. - * @param fields key:value log fields. Tracer implementations should support String, numeric, and boolean values; - * some may also support arbitrary Objects. - * @return the Span, for chaining - * @see Span#log(long, String) - */ - S log(long timestampMicroseconds, Map fields); - - /** - * Record an event at the current walltime timestamp. - * - * Shorthand for - * - *


-     span.log(Collections.singletonMap("event", event));
-     
- * - * @param event the event value; often a stable identifier for a moment in the Span lifecycle - * @return the Span, for chaining - */ - S log(String event); - - /** - * Record an event at a specific timestamp. - * - * Shorthand for - * - *

-     span.log(timestampMicroseconds, Collections.singletonMap("event", event));
-     
- * - * @param timestampMicroseconds The explicit timestamp for the log record. Must be greater than or equal to the - * Span's start timestamp. - * @param event the event value; often a stable identifier for a moment in the Span lifecycle - * @return the Span, for chaining - */ - S log(long timestampMicroseconds, String event); - - /** - * Sets a baggage item in the Span (and its SpanContext) as a key/value pair. - * - * Baggage enables powerful distributed context propagation functionality where arbitrary application data can be - * carried along the full path of request execution throughout the system. - * - * Note 1: Baggage is only propagated to the future (recursive) children of this SpanContext. - * - * Note 2: Baggage is sent in-band with every subsequent local and remote calls, so this feature must be used with - * care. - * - * @return this Span instance, for chaining - */ - S setBaggageItem(String key, String value); - - /** - * @return the value of the baggage item identified by the given key, or null if no such item could be found - */ - String getBaggageItem(String key); - - /** - * Sets the string name for the logical operation this span represents. - * - * @return this Span instance, for chaining - */ - S setOperationName(String operationName); -} diff --git a/opentracing-api/src/main/java/io/opentracing/Scope.java b/opentracing-api/src/main/java/io/opentracing/Scope.java new file mode 100644 index 00000000..dd997647 --- /dev/null +++ b/opentracing-api/src/main/java/io/opentracing/Scope.java @@ -0,0 +1,43 @@ +/* + * Copyright 2016-2017 The OpenTracing 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.opentracing; + +import java.io.Closeable; + +/** + * A {@link Scope} formalizes the activation and deactivation of a {@link Span}, usually from a CPU standpoint. + * + *

+ * Many times a {@link Span} will be extant (in that {@link Span#finish()} has not been called) despite being in a + * non-runnable state from a CPU/scheduler standpoint. For instance, a {@link Span} representing the client side of an + * RPC will be unfinished but blocked on IO while the RPC is still outstanding. A {@link Scope} defines when a given + * {@link Span} is scheduled and on the path. + */ +public interface Scope extends Closeable { + /** + * Mark the end of the active period for the current thread and {@link Scope}, + * updating the {@link ScopeManager#active()} in the process. + * + *

+ * NOTE: Calling {@link #close} more than once on a single {@link Scope} instance leads to undefined + * behavior. + */ + @Override + void close(); + + /** + * @return the {@link Span} that's been scoped by this {@link Scope} + */ + Span span(); +} diff --git a/opentracing-api/src/main/java/io/opentracing/ScopeManager.java b/opentracing-api/src/main/java/io/opentracing/ScopeManager.java new file mode 100644 index 00000000..b37f634f --- /dev/null +++ b/opentracing-api/src/main/java/io/opentracing/ScopeManager.java @@ -0,0 +1,47 @@ +/* + * Copyright 2016-2017 The OpenTracing 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.opentracing; + +/** + * The {@link ScopeManager} interface abstracts both the activation of {@link Span} instances (via + * {@link ScopeManager#activate(Span)}) and access to an active {@link Span}/{@link Scope} + * (via {@link ScopeManager#active()}). + * + * @see Scope + * @see Tracer#scopeManager() + */ +public interface ScopeManager { + /** + * Make a {@link Span} instance active. + * + * @param span the {@link Span} that should become the {@link #active()} + * @return a {@link Scope} instance to control the end of the active period for the {@link Span}. It is a + * programming error to neglect to call {@link Scope#close()} on the returned instance. + */ + Scope activate(Span span); + Scope activate(Span span, boolean finishOnClose); + + /** + * Return the currently active {@link Scope} which can be used to access the currently active + * {@link Scope#span()}. + * + *

+ * If there is an {@link Scope non-null scope}, its wrapped {@link Span} becomes an implicit parent of any + * newly-created {@link Span} at {@link Tracer.SpanBuilder#startActive()} time (rather than at + * {@link Tracer#buildSpan(String)} time). + * + * @return the {@link Scope active scope}, or null if none could be found. + */ + Scope active(); +} diff --git a/opentracing-api/src/main/java/io/opentracing/Span.java b/opentracing-api/src/main/java/io/opentracing/Span.java index 026c4ce5..548ac4f8 100644 --- a/opentracing-api/src/main/java/io/opentracing/Span.java +++ b/opentracing-api/src/main/java/io/opentracing/Span.java @@ -13,16 +13,132 @@ */ package io.opentracing; +import java.util.Map; + /** - * Represents an in-flight Span that's manually propagated within the given process. Most of - * the API lives in {@link BaseSpan}. - * - *

{@link Span}s are created by the {@link Tracer.SpanBuilder#startManual} method; see {@link ActiveSpan} for - * a {@link BaseSpan} extension designed for automatic in-process propagation. + * {@link Span} represents the OpenTracing specification's Span contract. * - * @see ActiveSpan for automatic propagation (recommended for most intstrumentation!) + * @see Scope + * @see ScopeManager + * @see Tracer.SpanBuilder#startManual() + * @see Tracer.SpanBuilder#startActive() */ -public interface Span extends BaseSpan { +public interface Span { + /** + * Retrieve the associated SpanContext. + * + * This may be called at any time, including after calls to finish(). + * + * @return the SpanContext that encapsulates Span state that should propagate across process boundaries. + */ + SpanContext context(); + + /** + * Set a key:value tag on the Span. + */ + Span setTag(String key, String value); + + /** Same as {@link #setTag(String, String)}, but for boolean values. */ + Span setTag(String key, boolean value); + + /** Same as {@link #setTag(String, String)}, but for numeric values. */ + Span setTag(String key, Number value); + + /** + * Log key:value pairs to the Span with the current walltime timestamp. + * + *

CAUTIONARY NOTE: not all Tracer implementations support key:value log fields end-to-end. + * Caveat emptor. + * + *

A contrived example (using Guava, which is not required): + *


+     span.log(
+     ImmutableMap.Builder()
+     .put("event", "soft error")
+     .put("type", "cache timeout")
+     .put("waited.millis", 1500)
+     .build());
+     
+ * + * @param fields key:value log fields. Tracer implementations should support String, numeric, and boolean values; + * some may also support arbitrary Objects. + * @return the Span, for chaining + * @see Span#log(String) + */ + Span log(Map fields); + + /** + * Like log(Map<String, Object>), but with an explicit timestamp. + * + *

CAUTIONARY NOTE: not all Tracer implementations support key:value log fields end-to-end. + * Caveat emptor. + * + * @param timestampMicroseconds The explicit timestamp for the log record. Must be greater than or equal to the + * Span's start timestamp. + * @param fields key:value log fields. Tracer implementations should support String, numeric, and boolean values; + * some may also support arbitrary Objects. + * @return the Span, for chaining + * @see Span#log(long, String) + */ + Span log(long timestampMicroseconds, Map fields); + + /** + * Record an event at the current walltime timestamp. + * + * Shorthand for + * + *


+     span.log(Collections.singletonMap("event", event));
+     
+ * + * @param event the event value; often a stable identifier for a moment in the Span lifecycle + * @return the Span, for chaining + */ + Span log(String event); + + /** + * Record an event at a specific timestamp. + * + * Shorthand for + * + *

+     span.log(timestampMicroseconds, Collections.singletonMap("event", event));
+     
+ * + * @param timestampMicroseconds The explicit timestamp for the log record. Must be greater than or equal to the + * Span's start timestamp. + * @param event the event value; often a stable identifier for a moment in the Span lifecycle + * @return the Span, for chaining + */ + Span log(long timestampMicroseconds, String event); + + /** + * Sets a baggage item in the Span (and its SpanContext) as a key/value pair. + * + * Baggage enables powerful distributed context propagation functionality where arbitrary application data can be + * carried along the full path of request execution throughout the system. + * + * Note 1: Baggage is only propagated to the future (recursive) children of this SpanContext. + * + * Note 2: Baggage is sent in-band with every subsequent local and remote calls, so this feature must be used with + * care. + * + * @return this Span instance, for chaining + */ + Span setBaggageItem(String key, String value); + + /** + * @return the value of the baggage item identified by the given key, or null if no such item could be found + */ + String getBaggageItem(String key); + + /** + * Sets the string name for the logical operation this span represents. + * + * @return this Span instance, for chaining + */ + Span setOperationName(String operationName); + /** * Sets the end timestamp to now and records the span. * diff --git a/opentracing-api/src/main/java/io/opentracing/Tracer.java b/opentracing-api/src/main/java/io/opentracing/Tracer.java index 25d3d321..ab6da828 100644 --- a/opentracing-api/src/main/java/io/opentracing/Tracer.java +++ b/opentracing-api/src/main/java/io/opentracing/Tracer.java @@ -18,7 +18,12 @@ /** * Tracer is a simple, thin interface for Span creation and propagation across arbitrary transports. */ -public interface Tracer extends ActiveSpanSource { +public interface Tracer { + + /** + * @return the current {@link ScopeManager}, which may be a noop but may not be null. + */ + ScopeManager scopeManager(); /** * Return a new SpanBuilder for a Span with the given `operationName`. @@ -29,14 +34,14 @@ public interface Tracer extends ActiveSpanSource { *

      *   Tracer tracer = ...
      *
-     *   // Note: if there is a `tracer.activeSpan()`, it will be used as the target of an implicit CHILD_OF
-     *   // Reference for "workSpan" when `startActive()` is invoked.
-     *   try (ActiveSpan workSpan = tracer.buildSpan("DoWork").startActive()) {
-     *       workSpan.setTag("...", "...");
+     *   // Note: if there is a `tracer.active()` Scope, its `span()` will be used as the target
+     *   // of an implicit CHILD_OF Reference for "workScope.span()" when `startActive()` is invoked.
+     *   try (Scope workScope = tracer.buildSpan("DoWork").startActive()) {
+     *       workScope.span().setTag("...", "...");
      *       // etc, etc
      *   }
      *
-     *   // It's also possible to create Spans manually, bypassing the ActiveSpanSource activation.
+     *   // It's also possible to create Spans manually, bypassing the ScopeManager activation.
      *   Span http = tracer.buildSpan("HandleHTTPRequest")
      *                     .asChildOf(rpcSpanContext)  // an explicit parent
      *                     .withTag("user_agent", req.UserAgent)
@@ -111,7 +116,7 @@ interface SpanBuilder {
          * 

* If parent==null, this is a noop. */ - SpanBuilder asChildOf(BaseSpan parent); + SpanBuilder asChildOf(Span parent); /** * Add a reference from the Span being built to a distinct (usually parent) Span. May be called multiple times @@ -120,12 +125,12 @@ interface SpanBuilder { *

* If *

    - *
  • the {@link Tracer}'s {@link ActiveSpanSource#activeSpan()} is not null, and + *
  • the {@link Tracer}'s {@link ScopeManager#active()} is not null, and *
  • no explicit references are added via {@link SpanBuilder#addReference}, and *
  • {@link SpanBuilder#ignoreActiveSpan()} is not invoked, *
* ... then an inferred {@link References#CHILD_OF} reference is created to the - * {@link ActiveSpanSource#activeSpan()} {@link SpanContext} when either {@link SpanBuilder#startActive()} or + * {@link ScopeManager#active()} {@link SpanContext} when either {@link SpanBuilder#startActive()} or * {@link SpanBuilder#startManual} is invoked. * * @param referenceType the reference type, typically one of the constants defined in References @@ -138,7 +143,7 @@ interface SpanBuilder { SpanBuilder addReference(String referenceType, SpanContext referencedContext); /** - * Do not create an implicit {@link References#CHILD_OF} reference to the {@link ActiveSpanSource#activeSpan}). + * Do not create an implicit {@link References#CHILD_OF} reference to the {@link ScopeManager#active()}). */ SpanBuilder ignoreActiveSpan(); @@ -155,46 +160,47 @@ interface SpanBuilder { SpanBuilder withStartTimestamp(long microseconds); /** - * Returns a newly started and activated {@link ActiveSpan}. + * Returns a newly started and activated {@link Scope}. * *

- * The returned {@link ActiveSpan} supports try-with-resources. For example: + * The returned {@link Scope} supports try-with-resources. For example: *


-         *     try (ActiveSpan span = tracer.buildSpan("...").startActive()) {
+         *     try (Scope scope = tracer.buildSpan("...").startActive()) {
          *         // (Do work)
-         *         span.setTag( ... );  // etc, etc
-         *     }  // Span finishes automatically unless deferred via {@link ActiveSpan#capture}
+         *         scope.span().setTag( ... );  // etc, etc
+         *     }  // XXX Span finishes automatically
          * 
* *

* If *

    - *
  • the {@link Tracer}'s {@link ActiveSpanSource#activeSpan()} is not null, and + *
  • the {@link Tracer}'s {@link ScopeManager#active()} is not null, and *
  • no explicit references are added via {@link SpanBuilder#addReference}, and *
  • {@link SpanBuilder#ignoreActiveSpan()} is not invoked, *
* ... then an inferred {@link References#CHILD_OF} reference is created to the - * {@link ActiveSpanSource#activeSpan()}'s {@link SpanContext} when either + * {@link ScopeManager#active()}'s {@link SpanContext} when either * {@link SpanBuilder#startManual()} or {@link SpanBuilder#startActive} is invoked. * *

* Note: {@link SpanBuilder#startActive()} is a shorthand for - * {@code tracer.makeActive(spanBuilder.startManual())}. + * {@code tracer.scopeManager().activate(spanBuilder.startManual())}. * - * @return an {@link ActiveSpan}, already registered via the {@link ActiveSpanSource} + * @return an {@link Scope}, already registered via the {@link ScopeManager} * - * @see ActiveSpanSource - * @see ActiveSpan + * @see ScopeManager + * @see Scope */ - ActiveSpan startActive(); + Scope startActive(); + Scope startActive(boolean finishOnClose); /** * Like {@link #startActive()}, but the returned {@link Span} has not been registered via the - * {@link ActiveSpanSource}. + * {@link ScopeManager}. * * @see SpanBuilder#startActive() * @return the newly-started Span instance, which has *not* been automatically registered - * via the {@link ActiveSpanSource} + * via the {@link ScopeManager} */ Span startManual(); diff --git a/opentracing-api/src/main/java/io/opentracing/tag/AbstractTag.java b/opentracing-api/src/main/java/io/opentracing/tag/AbstractTag.java index 4fed5c18..792ca636 100644 --- a/opentracing-api/src/main/java/io/opentracing/tag/AbstractTag.java +++ b/opentracing-api/src/main/java/io/opentracing/tag/AbstractTag.java @@ -13,7 +13,7 @@ */ package io.opentracing.tag; -import io.opentracing.BaseSpan; +import io.opentracing.Span; public abstract class AbstractTag { protected final String key; @@ -26,5 +26,5 @@ public String getKey() { return key; } - protected abstract void set(BaseSpan span, T tagValue); + protected abstract void set(Span span, T tagValue); } diff --git a/opentracing-api/src/main/java/io/opentracing/tag/BooleanTag.java b/opentracing-api/src/main/java/io/opentracing/tag/BooleanTag.java index f9be1ee3..8168d422 100644 --- a/opentracing-api/src/main/java/io/opentracing/tag/BooleanTag.java +++ b/opentracing-api/src/main/java/io/opentracing/tag/BooleanTag.java @@ -13,7 +13,7 @@ */ package io.opentracing.tag; -import io.opentracing.BaseSpan; +import io.opentracing.Span; public class BooleanTag extends AbstractTag { public BooleanTag(String key) { @@ -21,7 +21,7 @@ public BooleanTag(String key) { } @Override - public void set(BaseSpan span, Boolean tagValue) { + public void set(Span span, Boolean tagValue) { span.setTag(super.key, tagValue); } } diff --git a/opentracing-api/src/main/java/io/opentracing/tag/IntTag.java b/opentracing-api/src/main/java/io/opentracing/tag/IntTag.java index 48f4ae71..cb126492 100644 --- a/opentracing-api/src/main/java/io/opentracing/tag/IntTag.java +++ b/opentracing-api/src/main/java/io/opentracing/tag/IntTag.java @@ -13,7 +13,7 @@ */ package io.opentracing.tag; -import io.opentracing.BaseSpan; +import io.opentracing.Span; public class IntTag extends AbstractTag { public IntTag(String key) { @@ -21,7 +21,7 @@ public IntTag(String key) { } @Override - public void set(BaseSpan span, Integer tagValue) { + public void set(Span span, Integer tagValue) { span.setTag(super.key, tagValue); } } diff --git a/opentracing-api/src/main/java/io/opentracing/tag/StringTag.java b/opentracing-api/src/main/java/io/opentracing/tag/StringTag.java index 1fdba21a..65cfd59e 100644 --- a/opentracing-api/src/main/java/io/opentracing/tag/StringTag.java +++ b/opentracing-api/src/main/java/io/opentracing/tag/StringTag.java @@ -13,7 +13,7 @@ */ package io.opentracing.tag; -import io.opentracing.BaseSpan; +import io.opentracing.Span; public class StringTag extends AbstractTag { public StringTag(String key) { @@ -21,11 +21,11 @@ public StringTag(String key) { } @Override - public void set(BaseSpan span, String tagValue) { + public void set(Span span, String tagValue) { span.setTag(super.key, tagValue); } - public void set(BaseSpan span, StringTag tag) { + public void set(Span span, StringTag tag) { span.setTag(super.key, tag.key); } } diff --git a/opentracing-api/src/test/java/io/opentracing/tag/AbstractTagTest.java b/opentracing-api/src/test/java/io/opentracing/tag/AbstractTagTest.java index 816e259f..f327851e 100644 --- a/opentracing-api/src/test/java/io/opentracing/tag/AbstractTagTest.java +++ b/opentracing-api/src/test/java/io/opentracing/tag/AbstractTagTest.java @@ -17,10 +17,8 @@ import static org.mockito.Mockito.mock; import static org.mockito.Mockito.verify; -import org.junit.Test; - -import io.opentracing.ActiveSpan; import io.opentracing.Span; +import org.junit.Test; /** * @author Pavol Loffay @@ -45,16 +43,4 @@ public void testSetTagOnSpan() { verify(activeSpan).setTag(key, value); } - - @Test - public void testSetTagOnActiveSpan() { - String value = "foo"; - String key = "bar"; - - ActiveSpan activeSpan = mock(ActiveSpan.class); - StringTag tag = new StringTag(key); - tag.set(activeSpan, value); - - verify(activeSpan).setTag(key, value); - } } diff --git a/opentracing-mock/src/main/java/io/opentracing/mock/MockTracer.java b/opentracing-mock/src/main/java/io/opentracing/mock/MockTracer.java index 8d01144e..b0546f46 100644 --- a/opentracing-mock/src/main/java/io/opentracing/mock/MockTracer.java +++ b/opentracing-mock/src/main/java/io/opentracing/mock/MockTracer.java @@ -13,17 +13,16 @@ */ package io.opentracing.mock; -import io.opentracing.ActiveSpan; -import io.opentracing.ActiveSpanSource; -import io.opentracing.BaseSpan; -import io.opentracing.noop.NoopActiveSpanSource; -import io.opentracing.References; +import io.opentracing.Scope; +import io.opentracing.ScopeManager; import io.opentracing.Span; +import io.opentracing.noop.NoopScopeManager; +import io.opentracing.References; import io.opentracing.SpanContext; import io.opentracing.Tracer; import io.opentracing.propagation.Format; import io.opentracing.propagation.TextMap; -import io.opentracing.util.ThreadLocalActiveSpanSource; +import io.opentracing.util.ThreadLocalScopeManager; import java.util.ArrayList; import java.util.HashMap; @@ -41,26 +40,26 @@ public class MockTracer implements Tracer { private List finishedSpans = new ArrayList<>(); private final Propagator propagator; - private ActiveSpanSource spanSource; + private ScopeManager scopeManager; public MockTracer() { - this(new ThreadLocalActiveSpanSource(), Propagator.PRINTER); + this(new ThreadLocalScopeManager(), Propagator.PRINTER); } - public MockTracer(ActiveSpanSource spanSource) { - this(spanSource, Propagator.PRINTER); + public MockTracer(ScopeManager scopeManager) { + this(scopeManager, Propagator.PRINTER); } - public MockTracer(ActiveSpanSource spanSource, Propagator propagator) { + public MockTracer(ScopeManager scopeManager, Propagator propagator) { + this.scopeManager = scopeManager; this.propagator = propagator; - this.spanSource = spanSource; } /** * Create a new MockTracer that passes through any calls to inject() and/or extract(). */ public MockTracer(Propagator propagator) { - this(NoopActiveSpanSource.INSTANCE, propagator); + this(NoopScopeManager.INSTANCE, propagator); } /** @@ -89,16 +88,6 @@ public synchronized List finishedSpans() { protected void onSpanFinished(MockSpan mockSpan) { } - @Override - public ActiveSpan activeSpan() { - return spanSource.activeSpan(); - } - - @Override - public ActiveSpan makeActive(Span span) { - return spanSource.makeActive(span); - } - /** * Propagator allows the developer to intercept and verify any calls to inject() and/or extract(). * @@ -174,17 +163,13 @@ public MockSpan.MockContext extract(Format format, C carrier) { } @Override - public SpanBuilder buildSpan(String operationName) { - return new SpanBuilder(operationName); + public ScopeManager scopeManager() { + return this.scopeManager; } - private SpanContext activeSpanContext() { - ActiveSpan handle = this.spanSource.activeSpan(); - if (handle == null) { - return null; - } - - return handle.context(); + @Override + public SpanBuilder buildSpan(String operationName) { + return new SpanBuilder(operationName); } @Override @@ -219,7 +204,7 @@ public SpanBuilder asChildOf(SpanContext parent) { } @Override - public SpanBuilder asChildOf(BaseSpan parent) { + public SpanBuilder asChildOf(Span parent) { return addReference(References.CHILD_OF, parent.context()); } @@ -263,14 +248,18 @@ public SpanBuilder withStartTimestamp(long microseconds) { } @Override - public MockSpan start() { - return startManual(); + public Scope startActive() { + return MockTracer.this.scopeManager().activate(this.startManual()); } @Override - public ActiveSpan startActive() { - MockSpan span = this.startManual(); - return spanSource.makeActive(span); + public Scope startActive(boolean finishOnClose) { + return MockTracer.this.scopeManager().activate(this.startManual(), finishOnClose); + } + + @Override + public MockSpan start() { + return startManual(); } @Override @@ -279,7 +268,10 @@ public MockSpan startManual() { this.startMicros = MockSpan.nowMicros(); } if (firstParent == null && !ignoringActiveSpan) { - firstParent = (MockSpan.MockContext) activeSpanContext(); + Scope activeScope = scopeManager().active(); + if (activeScope != null) { + firstParent = (MockSpan.MockContext) activeScope.span().context(); + } } return new MockSpan(MockTracer.this, operationName, startMicros, initialTags, firstParent); } diff --git a/opentracing-noop/src/main/java/io/opentracing/noop/NoopActiveSpanSource.java b/opentracing-noop/src/main/java/io/opentracing/noop/NoopActiveSpanSource.java deleted file mode 100644 index ddd150ce..00000000 --- a/opentracing-noop/src/main/java/io/opentracing/noop/NoopActiveSpanSource.java +++ /dev/null @@ -1,120 +0,0 @@ -/* - * Copyright 2016-2017 The OpenTracing 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.opentracing.noop; - -import io.opentracing.ActiveSpan; -import io.opentracing.ActiveSpanSource; -import io.opentracing.Span; -import io.opentracing.SpanContext; - -import java.util.Map; - -public interface NoopActiveSpanSource extends ActiveSpanSource { - NoopActiveSpanSource INSTANCE = new NoopActiveSpanSourceImpl(); - - interface NoopActiveSpan extends ActiveSpan { - NoopActiveSpanSource.NoopActiveSpan INSTANCE = new NoopActiveSpanSourceImpl.NoopActiveSpanImpl(); - } - interface NoopContinuation extends ActiveSpan.Continuation { - NoopActiveSpanSource.NoopContinuation INSTANCE = new NoopActiveSpanSourceImpl.NoopContinuationImpl(); - } -} - -/** - * A noop (i.e., cheap-as-possible) implementation of an ActiveSpanSource. - */ -class NoopActiveSpanSourceImpl implements NoopActiveSpanSource { - @Override - public ActiveSpan makeActive(Span span) { - return NoopActiveSpanSource.NoopActiveSpan.INSTANCE; - } - - @Override - public ActiveSpan activeSpan() { return null; } - - static class NoopActiveSpanImpl implements NoopActiveSpanSource.NoopActiveSpan { - @Override - public void deactivate() {} - - @Override - public Continuation capture() { - return NoopActiveSpanSource.NoopContinuation.INSTANCE; - } - - @Override - public SpanContext context() { - return NoopSpanContextImpl.INSTANCE; - } - - @Override - public void close() {} - - @Override - public NoopActiveSpan setTag(String key, String value) { - return NoopActiveSpanSource.NoopActiveSpan.INSTANCE; - } - - @Override - public NoopActiveSpan setTag(String key, boolean value) { - return NoopActiveSpanSource.NoopActiveSpan.INSTANCE; - } - - @Override - public NoopActiveSpan setTag(String key, Number value) { - return NoopActiveSpanSource.NoopActiveSpan.INSTANCE; - } - - @Override - public NoopActiveSpan log(Map fields) { - return NoopActiveSpanSource.NoopActiveSpan.INSTANCE; - } - - @Override - public NoopActiveSpan log(long timestampMicroseconds, Map fields) { - return NoopActiveSpanSource.NoopActiveSpan.INSTANCE; - } - - @Override - public NoopActiveSpan log(String event) { - return NoopActiveSpanSource.NoopActiveSpan.INSTANCE; - } - - @Override - public NoopActiveSpan log(long timestampMicroseconds, String event) { - return NoopActiveSpanSource.NoopActiveSpan.INSTANCE; - } - - @Override - public NoopActiveSpan setBaggageItem(String key, String value) { - return NoopActiveSpanSource.NoopActiveSpan.INSTANCE; - } - - @Override - public String getBaggageItem(String key) { - return null; - } - - @Override - public NoopActiveSpan setOperationName(String operationName) { - return NoopActiveSpanSource.NoopActiveSpan.INSTANCE; - } - } - - static class NoopContinuationImpl implements NoopActiveSpanSource.NoopContinuation { - @Override - public ActiveSpan activate() { - return NoopActiveSpanSource.NoopActiveSpan.INSTANCE; - } - } -} diff --git a/opentracing-noop/src/main/java/io/opentracing/noop/NoopScopeManager.java b/opentracing-noop/src/main/java/io/opentracing/noop/NoopScopeManager.java new file mode 100644 index 00000000..2b9ab300 --- /dev/null +++ b/opentracing-noop/src/main/java/io/opentracing/noop/NoopScopeManager.java @@ -0,0 +1,56 @@ +/* + * Copyright 2016-2017 The OpenTracing 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.opentracing.noop; + +import io.opentracing.Scope; +import io.opentracing.ScopeManager; +import io.opentracing.Span; + +public interface NoopScopeManager extends ScopeManager { + NoopScopeManager INSTANCE = new NoopScopeManagerImpl(); + + interface NoopScope extends Scope { + NoopScope INSTANCE = new NoopScopeManagerImpl.NoopScopeImpl(); + } +} + +/** + * A noop (i.e., cheap-as-possible) implementation of an ScopeManager. + */ +class NoopScopeManagerImpl implements NoopScopeManager { + @Override + public Scope activate(Span span) { + return NoopScope.INSTANCE; + } + + @Override + public Scope activate(Span span, boolean finishOnClose) { + return NoopScope.INSTANCE; + } + + @Override + public Scope active() { + return null; + } + + static class NoopScopeImpl implements NoopScopeManager.NoopScope { + @Override + public void close() {} + + @Override + public Span span() { + return NoopSpan.INSTANCE; + } + } +} diff --git a/opentracing-noop/src/main/java/io/opentracing/noop/NoopSpan.java b/opentracing-noop/src/main/java/io/opentracing/noop/NoopSpan.java index 7d503066..b720aa07 100644 --- a/opentracing-noop/src/main/java/io/opentracing/noop/NoopSpan.java +++ b/opentracing-noop/src/main/java/io/opentracing/noop/NoopSpan.java @@ -19,7 +19,7 @@ import java.util.Map; public interface NoopSpan extends Span { - static final NoopSpan INSTANCE = new NoopSpanImpl(); + NoopSpan INSTANCE = new NoopSpanImpl(); } final class NoopSpanImpl implements NoopSpan { diff --git a/opentracing-noop/src/main/java/io/opentracing/noop/NoopSpanBuilder.java b/opentracing-noop/src/main/java/io/opentracing/noop/NoopSpanBuilder.java index 06129830..a114e96f 100644 --- a/opentracing-noop/src/main/java/io/opentracing/noop/NoopSpanBuilder.java +++ b/opentracing-noop/src/main/java/io/opentracing/noop/NoopSpanBuilder.java @@ -13,8 +13,7 @@ */ package io.opentracing.noop; -import io.opentracing.ActiveSpan; -import io.opentracing.BaseSpan; +import io.opentracing.Scope; import io.opentracing.Span; import io.opentracing.SpanContext; import io.opentracing.Tracer; @@ -42,7 +41,7 @@ public Tracer.SpanBuilder asChildOf(SpanContext parent) { public Tracer.SpanBuilder ignoreActiveSpan() { return this; } @Override - public Tracer.SpanBuilder asChildOf(BaseSpan parent) { + public Tracer.SpanBuilder asChildOf(Span parent) { return this; } @@ -67,13 +66,18 @@ public Tracer.SpanBuilder withStartTimestamp(long microseconds) { } @Override - public Span start() { - return startManual(); + public Scope startActive() { + return NoopScopeManager.NoopScope.INSTANCE; + } + + @Override + public Scope startActive(boolean finishOnClose) { + return NoopScopeManager.NoopScope.INSTANCE; } @Override - public ActiveSpan startActive() { - return NoopActiveSpanSource.NoopActiveSpan.INSTANCE; + public Span start() { + return startManual(); } @Override @@ -88,4 +92,4 @@ public Iterable> baggageItems() { @Override public String toString() { return NoopSpanBuilder.class.getSimpleName(); } -} \ No newline at end of file +} diff --git a/opentracing-noop/src/main/java/io/opentracing/noop/NoopTracer.java b/opentracing-noop/src/main/java/io/opentracing/noop/NoopTracer.java index 678a302a..f3480c1c 100644 --- a/opentracing-noop/src/main/java/io/opentracing/noop/NoopTracer.java +++ b/opentracing-noop/src/main/java/io/opentracing/noop/NoopTracer.java @@ -13,8 +13,7 @@ */ package io.opentracing.noop; -import io.opentracing.ActiveSpan; -import io.opentracing.Span; +import io.opentracing.ScopeManager; import io.opentracing.SpanContext; import io.opentracing.Tracer; import io.opentracing.propagation.Format; @@ -25,6 +24,11 @@ public interface NoopTracer extends Tracer { final class NoopTracerImpl implements NoopTracer { final static NoopTracer INSTANCE = new NoopTracerImpl(); + @Override + public ScopeManager scopeManager() { + return null; + } + @Override public SpanBuilder buildSpan(String operationName) { return NoopSpanBuilderImpl.INSTANCE; } @@ -36,15 +40,5 @@ public void inject(SpanContext spanContext, Format format, C carrier) {} @Override public String toString() { return NoopTracer.class.getSimpleName(); } - - @Override - public ActiveSpan activeSpan() { - return null; - } - - @Override - public ActiveSpan makeActive(Span span) { - return NoopActiveSpanSource.NoopActiveSpan.INSTANCE; - } } diff --git a/opentracing-util/src/main/java/io/opentracing/util/GlobalTracer.java b/opentracing-util/src/main/java/io/opentracing/util/GlobalTracer.java index 89b6f073..24ef261b 100644 --- a/opentracing-util/src/main/java/io/opentracing/util/GlobalTracer.java +++ b/opentracing-util/src/main/java/io/opentracing/util/GlobalTracer.java @@ -13,10 +13,9 @@ */ package io.opentracing.util; -import io.opentracing.ActiveSpan; +import io.opentracing.ScopeManager; import io.opentracing.noop.NoopTracer; import io.opentracing.noop.NoopTracerFactory; -import io.opentracing.Span; import io.opentracing.SpanContext; import io.opentracing.Tracer; import io.opentracing.propagation.Format; @@ -123,6 +122,11 @@ public static synchronized boolean isRegistered() { return !(GlobalTracer.tracer instanceof NoopTracer); } + @Override + public ScopeManager scopeManager() { + return tracer.scopeManager(); + } + @Override public SpanBuilder buildSpan(String operationName) { return tracer.buildSpan(operationName); @@ -142,14 +146,4 @@ public SpanContext extract(Format format, C carrier) { public String toString() { return GlobalTracer.class.getSimpleName() + '{' + tracer + '}'; } - - @Override - public ActiveSpan activeSpan() { - return tracer.activeSpan(); - } - - @Override - public ActiveSpan makeActive(Span span) { - return tracer.makeActive(span); - } } diff --git a/opentracing-util/src/main/java/io/opentracing/util/ThreadLocalActiveSpan.java b/opentracing-util/src/main/java/io/opentracing/util/ThreadLocalActiveSpan.java deleted file mode 100644 index ba90ca43..00000000 --- a/opentracing-util/src/main/java/io/opentracing/util/ThreadLocalActiveSpan.java +++ /dev/null @@ -1,149 +0,0 @@ -/* - * Copyright 2016-2017 The OpenTracing 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.opentracing.util; - -import java.util.Map; -import java.util.concurrent.atomic.AtomicInteger; - -import io.opentracing.ActiveSpan; -import io.opentracing.ActiveSpanSource; -import io.opentracing.Span; -import io.opentracing.SpanContext; -import io.opentracing.Tracer; - -/** - * {@link ThreadLocalActiveSpan} is a simple {@link ActiveSpan} implementation that relies on Java's - * thread-local storage primitive. - * - * @see ActiveSpanSource - * @see Tracer#activeSpan() - */ -public class ThreadLocalActiveSpan implements ActiveSpan { - private final ThreadLocalActiveSpanSource source; - private final Span wrapped; - private final ThreadLocalActiveSpan toRestore; - private final AtomicInteger refCount; - - ThreadLocalActiveSpan(ThreadLocalActiveSpanSource source, Span wrapped, AtomicInteger refCount) { - this.source = source; - this.refCount = refCount; - this.wrapped = wrapped; - this.toRestore = source.tlsSnapshot.get(); - source.tlsSnapshot.set(this); - } - - @Override - public void deactivate() { - if (source.tlsSnapshot.get() != this) { - // This shouldn't happen if users call methods in the expected order. Bail out. - return; - } - source.tlsSnapshot.set(toRestore); - - if (0 == refCount.decrementAndGet()) { - wrapped.finish(); - } - } - - @Override - public Continuation capture() { - return new ThreadLocalActiveSpan.Continuation(); - } - - @Override - public SpanContext context() { - return wrapped.context(); - } - - @Override - public ThreadLocalActiveSpan setTag(String key, String value) { - wrapped.setTag(key, value); - return this; - } - - @Override - public ThreadLocalActiveSpan setTag(String key, boolean value) { - wrapped.setTag(key, value); - return this; - } - - @Override - public ThreadLocalActiveSpan setTag(String key, Number value) { - wrapped.setTag(key, value); - return this; - } - - @Override - public ThreadLocalActiveSpan log(Map fields) { - wrapped.log(fields); - return this; - } - - @Override - public ThreadLocalActiveSpan log(long timestampMicroseconds, Map fields) { - wrapped.log(timestampMicroseconds, fields); - return this; - } - - @Override - public ThreadLocalActiveSpan log(String event) { - wrapped.log(event); - return this; - } - - @Override - public ThreadLocalActiveSpan log(long timestampMicroseconds, String event) { - wrapped.log(timestampMicroseconds, event); - return this; - } - - @Override - public ThreadLocalActiveSpan setBaggageItem(String key, String value) { - wrapped.setBaggageItem(key, value); - return this; - } - - @Override - public String getBaggageItem(String key) { - return wrapped.getBaggageItem(key); - } - - @Override - public ThreadLocalActiveSpan setOperationName(String operationName) { - wrapped.setOperationName(operationName); - return this; - } - - @Override - public void close() { - deactivate(); - } - - @Override - public String toString() { - return wrapped.toString(); - } - - private final class Continuation implements ActiveSpan.Continuation { - Continuation() { - refCount.incrementAndGet(); - } - - @Override - public ThreadLocalActiveSpan activate() { - return new ThreadLocalActiveSpan(source, wrapped, refCount); - } - } - -} diff --git a/opentracing-util/src/main/java/io/opentracing/util/ThreadLocalScope.java b/opentracing-util/src/main/java/io/opentracing/util/ThreadLocalScope.java new file mode 100644 index 00000000..8ff5d134 --- /dev/null +++ b/opentracing-util/src/main/java/io/opentracing/util/ThreadLocalScope.java @@ -0,0 +1,57 @@ +/* + * Copyright 2016-2017 The OpenTracing 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.opentracing.util; + +import io.opentracing.Scope; +import io.opentracing.ScopeManager; +import io.opentracing.Span; + +/** + * {@link ThreadLocalScope} is a simple {@link Scope} implementation that relies on Java's + * thread-local storage primitive. + * + * @see ScopeManager + */ +public class ThreadLocalScope implements Scope { + private final ThreadLocalScopeManager scopeManager; + private final Span wrapped; + private final boolean finishOnClose; + private final ThreadLocalScope toRestore; + + ThreadLocalScope(ThreadLocalScopeManager scopeManager, Span wrapped, boolean finishOnClose) { + this.scopeManager = scopeManager; + this.wrapped = wrapped; + this.finishOnClose = finishOnClose; + this.toRestore = scopeManager.tlsScope.get(); + scopeManager.tlsScope.set(this); + } + + @Override + public void close() { + if (scopeManager.tlsScope.get() != this) { + // This shouldn't happen if users call methods in the expected order. Bail out. + return; + } + + if (finishOnClose) + wrapped.finish(); + + scopeManager.tlsScope.set(toRestore); + } + + @Override + public Span span() { + return wrapped; + } +} diff --git a/opentracing-util/src/main/java/io/opentracing/util/ThreadLocalActiveSpanSource.java b/opentracing-util/src/main/java/io/opentracing/util/ThreadLocalScopeManager.java similarity index 50% rename from opentracing-util/src/main/java/io/opentracing/util/ThreadLocalActiveSpanSource.java rename to opentracing-util/src/main/java/io/opentracing/util/ThreadLocalScopeManager.java index 2cd7e6e2..095c4c8f 100644 --- a/opentracing-util/src/main/java/io/opentracing/util/ThreadLocalActiveSpanSource.java +++ b/opentracing-util/src/main/java/io/opentracing/util/ThreadLocalScopeManager.java @@ -13,30 +13,30 @@ */ package io.opentracing.util; -import io.opentracing.ActiveSpan; -import io.opentracing.ActiveSpanSource; +import io.opentracing.Scope; +import io.opentracing.ScopeManager; import io.opentracing.Span; -import io.opentracing.Tracer; - -import java.util.concurrent.atomic.AtomicInteger; /** - * A simple {@link ActiveSpanSource} implementation built on top of Java's thread-local storage primitive. + * A simple {@link ScopeManager} implementation built on top of Java's thread-local storage primitive. * - * @see ThreadLocalActiveSpan - * @see Tracer#activeSpan() + * @see ThreadLocalScope */ -public class ThreadLocalActiveSpanSource implements ActiveSpanSource { - final ThreadLocal tlsSnapshot = new ThreadLocal(); +public class ThreadLocalScopeManager implements ScopeManager { + final ThreadLocal tlsScope = new ThreadLocal(); @Override - public ThreadLocalActiveSpan activeSpan() { - return tlsSnapshot.get(); + public Scope activate(Span span) { + return new ThreadLocalScope(this, span, true); } @Override - public ActiveSpan makeActive(Span span) { - return new ThreadLocalActiveSpan(this, span, new AtomicInteger(1)); + public Scope activate(Span span, boolean finishOnClose) { + return new ThreadLocalScope(this, span, finishOnClose); } + @Override + public Scope active() { + return tlsScope.get(); + } } diff --git a/opentracing-util/src/test/java/io/opentracing/util/ThreadLocalActiveSpanSourceTest.java b/opentracing-util/src/test/java/io/opentracing/util/ThreadLocalScopeManagerTest.java similarity index 61% rename from opentracing-util/src/test/java/io/opentracing/util/ThreadLocalActiveSpanSourceTest.java rename to opentracing-util/src/test/java/io/opentracing/util/ThreadLocalScopeManagerTest.java index 180662ee..582f685e 100644 --- a/opentracing-util/src/test/java/io/opentracing/util/ThreadLocalActiveSpanSourceTest.java +++ b/opentracing-util/src/test/java/io/opentracing/util/ThreadLocalScopeManagerTest.java @@ -13,48 +13,50 @@ */ package io.opentracing.util; -import io.opentracing.ActiveSpan; +import io.opentracing.Scope; import io.opentracing.Span; import org.junit.Before; import org.junit.Test; import static org.junit.Assert.*; import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; -public class ThreadLocalActiveSpanSourceTest { - private ThreadLocalActiveSpanSource source; +public class ThreadLocalScopeManagerTest { + private ThreadLocalScopeManager source; + @Before public void before() throws Exception { - source = new ThreadLocalActiveSpanSource(); + source = new ThreadLocalScopeManager(); } @Test - public void missingActiveSpan() throws Exception { - ActiveSpan missingSpan = source.activeSpan(); - assertNull(missingSpan); + public void missingActiveScope() throws Exception { + Scope missingScope = source.active(); + assertNull(missingScope); } @Test - public void makeActiveSpan() throws Exception { + public void activateSpan() throws Exception { Span span = mock(Span.class); // We can't use 1.7 features like try-with-resources in this repo without meddling with pom details for tests. - ActiveSpan activeSpan = source.makeActive(span); + Scope scope = source.activate(span); try { - assertNotNull(activeSpan); - ActiveSpan otherActiveSpan = source.activeSpan(); - assertEquals(otherActiveSpan, activeSpan); + assertNotNull(scope); + Scope otherScope = source.active(); + assertEquals(otherScope, scope); } finally { - activeSpan.close(); + scope.close(); } // Make sure the Span got finish()ed. - verify(span).finish(); + verify(span, times(1)).finish(); // And now it's gone: - ActiveSpan missingSpan = source.activeSpan(); - assertNull(missingSpan); + Scope missingScope = source.active(); + assertNull(missingScope); } -} \ No newline at end of file +} diff --git a/opentracing-util/src/test/java/io/opentracing/util/ThreadLocalActiveSpanTest.java b/opentracing-util/src/test/java/io/opentracing/util/ThreadLocalScopeTest.java similarity index 56% rename from opentracing-util/src/test/java/io/opentracing/util/ThreadLocalActiveSpanTest.java rename to opentracing-util/src/test/java/io/opentracing/util/ThreadLocalScopeTest.java index 06d49093..e97c4cbd 100644 --- a/opentracing-util/src/test/java/io/opentracing/util/ThreadLocalActiveSpanTest.java +++ b/opentracing-util/src/test/java/io/opentracing/util/ThreadLocalScopeTest.java @@ -21,49 +21,17 @@ import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; -import io.opentracing.ActiveSpan; +import io.opentracing.Scope; import io.opentracing.Span; import org.junit.Before; import org.junit.Test; -public class ThreadLocalActiveSpanTest { - private ThreadLocalActiveSpanSource source; +public class ThreadLocalScopeTest { + private ThreadLocalScopeManager scopeManager; @Before public void before() throws Exception { - source = new ThreadLocalActiveSpanSource(); - } - - @Test - public void continuation() throws Exception { - Span span = mock(Span.class); - - // Quasi try-with-resources (this is 1.6). - ActiveSpan activeSpan = source.makeActive(span); - ActiveSpan.Continuation continued = null; - try { - assertNotNull(activeSpan); - continued = activeSpan.capture(); - } finally { - activeSpan.close(); - } - - // Make sure the Span was not finished since there was a capture(). - verify(span, never()).finish(); - - // Activate the continuation. - try { - activeSpan = continued.activate(); - } finally { - activeSpan.close(); - } - - // Now the Span should be finished. - verify(span, times(1)).finish(); - - // And now it's no longer active. - ActiveSpan missingSpan = source.activeSpan(); - assertNull(missingSpan); + scopeManager = new ThreadLocalScopeManager(); } @Test @@ -72,21 +40,21 @@ public void implicitSpanStack() throws Exception { Span foregroundSpan = mock(Span.class); // Quasi try-with-resources (this is 1.6). - ActiveSpan backgroundActive = source.makeActive(backgroundSpan); + Scope backgroundActive = scopeManager.activate(backgroundSpan); try { assertNotNull(backgroundActive); - // Activate a new ActiveSpan on top of the background one. - ActiveSpan foregroundActive = source.makeActive(foregroundSpan); + // Activate a new Scope on top of the background one. + Scope foregroundActive = scopeManager.activate(foregroundSpan); try { - ActiveSpan shouldBeForeground = source.activeSpan(); + Scope shouldBeForeground = scopeManager.active(); assertEquals(foregroundActive, shouldBeForeground); } finally { foregroundActive.close(); } // And now the backgroundActive should be reinstated. - ActiveSpan shouldBeBackground = source.activeSpan(); + Scope shouldBeBackground = scopeManager.active(); assertEquals(backgroundActive, shouldBeBackground); } finally { backgroundActive.close(); @@ -97,7 +65,7 @@ public void implicitSpanStack() throws Exception { verify(foregroundSpan, times(1)).finish(); // And now nothing is active. - ActiveSpan missingSpan = source.activeSpan(); + Scope missingSpan = scopeManager.active(); assertNull(missingSpan); } @@ -105,9 +73,9 @@ public void implicitSpanStack() throws Exception { public void testDeactivateWhenDifferentSpanIsActive() { Span span = mock(Span.class); - ActiveSpan activeSpan = source.makeActive(span); - source.makeActive(mock(Span.class)); - activeSpan.deactivate(); + Scope active = scopeManager.activate(span); + scopeManager.activate(mock(Span.class)); + active.close(); verify(span, times(0)).finish(); } From 4956655453917c13965680c3fc508dc1713bf984 Mon Sep 17 00:00:00 2001 From: Carlos Alberto Cortez Date: Tue, 19 Sep 2017 03:53:46 +0200 Subject: [PATCH 2/5] Make IntOrStringTag use Span, as BaseSpan is not used anymore. --- .../src/main/java/io/opentracing/tag/IntOrStringTag.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/opentracing-api/src/main/java/io/opentracing/tag/IntOrStringTag.java b/opentracing-api/src/main/java/io/opentracing/tag/IntOrStringTag.java index e173b842..1ea09cbf 100644 --- a/opentracing-api/src/main/java/io/opentracing/tag/IntOrStringTag.java +++ b/opentracing-api/src/main/java/io/opentracing/tag/IntOrStringTag.java @@ -13,14 +13,14 @@ */ package io.opentracing.tag; -import io.opentracing.BaseSpan; +import io.opentracing.Span; public class IntOrStringTag extends IntTag { public IntOrStringTag(String key) { super(key); } - public void set(BaseSpan span, String tagValue) { + public void set(Span span, String tagValue) { span.setTag(super.key, tagValue); } } From 9bf499d98a4dc0e6914313e9f44f4ea8b9c9abba Mon Sep 17 00:00:00 2001 From: Carlos Alberto Cortez Date: Tue, 19 Sep 2017 17:35:27 +0200 Subject: [PATCH 3/5] Update our examples to use the Scope design. Part of handling the examples related to multiple asynchronous callbacks, an AutoFinishScopeManager has been included, which mimics the ref counting in the previous ActiveSpan approach. --- .../opentracing/examples/AutoFinishScope.java | 66 +++++++++++++++++++ .../examples/AutoFinishScopeManager.java | 39 +++++++++++ .../activate_deactivate/RunnableAction.java | 14 ++-- .../ScheduledActionsTest.java | 17 ++--- .../ActiveSpanReplacementTest.java | 24 +++---- .../examples/client_server/Client.java | 6 +- .../examples/client_server/Server.java | 4 +- .../client_server/TestClientServerTest.java | 6 +- .../common_request_handler/HandlerTest.java | 14 ++-- .../late_span_finish/LateSpanFinishTest.java | 18 +++-- .../listener_per_request/ListenerTest.java | 6 +- .../examples/multiple_callbacks/Client.java | 14 ++-- .../MultipleCallbacksTest.java | 16 ++--- .../nested_callbacks/NestedCallbacksTest.java | 24 ++++--- 14 files changed, 188 insertions(+), 80 deletions(-) create mode 100644 opentracing-examples/src/test/java/io/opentracing/examples/AutoFinishScope.java create mode 100644 opentracing-examples/src/test/java/io/opentracing/examples/AutoFinishScopeManager.java diff --git a/opentracing-examples/src/test/java/io/opentracing/examples/AutoFinishScope.java b/opentracing-examples/src/test/java/io/opentracing/examples/AutoFinishScope.java new file mode 100644 index 00000000..0010a54e --- /dev/null +++ b/opentracing-examples/src/test/java/io/opentracing/examples/AutoFinishScope.java @@ -0,0 +1,66 @@ +/* + * Copyright 2016-2017 The OpenTracing 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.opentracing.examples; + +import io.opentracing.Scope; +import io.opentracing.Span; + +import java.util.concurrent.atomic.AtomicInteger; + +public class AutoFinishScope implements Scope { + final AutoFinishScopeManager manager; + final AtomicInteger refCount; + private final Span wrapped; + private final AutoFinishScope toRestore; + + AutoFinishScope(AutoFinishScopeManager manager, AtomicInteger refCount, Span wrapped) { + this.manager = manager; + this.refCount = refCount; + this.wrapped = wrapped; + this.toRestore = manager.tlsScope.get(); + manager.tlsScope.set(this); + } + + public class Continuation { + public Continuation() { + refCount.incrementAndGet(); + } + + public AutoFinishScope activate() { + return new AutoFinishScope(manager, refCount, wrapped); + } + } + + public Continuation capture() { + return new Continuation(); + } + + @Override + public void close() { + if (manager.tlsScope.get() != this) { + return; + } + + if (refCount.decrementAndGet() == 0) { + wrapped.finish(); + } + + manager.tlsScope.set(toRestore); + } + + @Override + public Span span() { + return wrapped; + } +} diff --git a/opentracing-examples/src/test/java/io/opentracing/examples/AutoFinishScopeManager.java b/opentracing-examples/src/test/java/io/opentracing/examples/AutoFinishScopeManager.java new file mode 100644 index 00000000..bfb578bd --- /dev/null +++ b/opentracing-examples/src/test/java/io/opentracing/examples/AutoFinishScopeManager.java @@ -0,0 +1,39 @@ +/* + * Copyright 2016-2017 The OpenTracing 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.opentracing.examples; + +import io.opentracing.ScopeManager; +import io.opentracing.Span; + +import java.util.concurrent.atomic.AtomicInteger; + +public class AutoFinishScopeManager implements ScopeManager { + final ThreadLocal tlsScope = new ThreadLocal(); + + @Override + public AutoFinishScope activate(Span span) { + return new AutoFinishScope(this, new AtomicInteger(1), span); + } + + @Override + public AutoFinishScope activate(Span span, boolean finishOnClose) { + return new AutoFinishScope(this, new AtomicInteger(1), span); + } + + @Override + public AutoFinishScope active() { + return tlsScope.get(); + } + +} diff --git a/opentracing-examples/src/test/java/io/opentracing/examples/activate_deactivate/RunnableAction.java b/opentracing-examples/src/test/java/io/opentracing/examples/activate_deactivate/RunnableAction.java index fab14632..bda704d3 100644 --- a/opentracing-examples/src/test/java/io/opentracing/examples/activate_deactivate/RunnableAction.java +++ b/opentracing-examples/src/test/java/io/opentracing/examples/activate_deactivate/RunnableAction.java @@ -13,8 +13,8 @@ */ package io.opentracing.examples.activate_deactivate; -import io.opentracing.ActiveSpan; -import io.opentracing.ActiveSpan.Continuation; +import io.opentracing.examples.AutoFinishScope; +import io.opentracing.examples.AutoFinishScope.Continuation; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -30,8 +30,8 @@ public class RunnableAction implements Runnable { private final Continuation continuation; - RunnableAction(ActiveSpan activeSpan) { - continuation = activeSpan.capture(); + RunnableAction(AutoFinishScope scope) { + continuation = scope.capture(); logger.info("Action created"); } @@ -42,7 +42,7 @@ public class RunnableAction implements Runnable { @Override public void run() { logger.info("Action started"); - ActiveSpan activeSpan = continuation.activate(); + AutoFinishScope scope = continuation.activate(); try { TimeUnit.SECONDS.sleep(1); // without sleep first action can finish before second is started @@ -51,9 +51,9 @@ public void run() { } // set random tag starting with 'test_tag_' to test that finished span has all of them - activeSpan.setTag("test_tag_" + ThreadLocalRandom.current().nextInt(), "random"); + scope.span().setTag("test_tag_" + ThreadLocalRandom.current().nextInt(), "random"); - activeSpan.deactivate(); + scope.close(); logger.info("Action finished"); } } diff --git a/opentracing-examples/src/test/java/io/opentracing/examples/activate_deactivate/ScheduledActionsTest.java b/opentracing-examples/src/test/java/io/opentracing/examples/activate_deactivate/ScheduledActionsTest.java index c42ad772..cc5307c2 100644 --- a/opentracing-examples/src/test/java/io/opentracing/examples/activate_deactivate/ScheduledActionsTest.java +++ b/opentracing-examples/src/test/java/io/opentracing/examples/activate_deactivate/ScheduledActionsTest.java @@ -13,11 +13,12 @@ */ package io.opentracing.examples.activate_deactivate; -import io.opentracing.ActiveSpan; +import io.opentracing.Scope; +import io.opentracing.examples.AutoFinishScope; +import io.opentracing.examples.AutoFinishScopeManager; import io.opentracing.mock.MockSpan; import io.opentracing.mock.MockTracer; import io.opentracing.mock.MockTracer.Propagator; -import io.opentracing.util.ThreadLocalActiveSpanSource; import org.junit.Test; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -37,7 +38,7 @@ public class ScheduledActionsTest { private static final Logger logger = LoggerFactory.getLogger(ScheduledActionsTest.class); - private final MockTracer tracer = new MockTracer(new ThreadLocalActiveSpanSource(), + private final MockTracer tracer = new MockTracer(new AutoFinishScopeManager(), Propagator.TEXT_MAP); private final ScheduledExecutorService service = Executors.newScheduledThreadPool(10); @@ -88,8 +89,8 @@ private Thread entryThread() { @Override public void run() { logger.info("Entry thread started"); - try (ActiveSpan activeSpan = tracer.buildSpan("parent").startActive()) { - Runnable action = new RunnableAction(activeSpan); + try (Scope scope = tracer.buildSpan("parent").startActive()) { + Runnable action = new RunnableAction((AutoFinishScope)scope); // Action is executed at some time and we are not able to check status service.schedule(action, 500, TimeUnit.MILLISECONDS); @@ -107,9 +108,9 @@ private Thread entryThreadWithTwoActions() { @Override public void run() { logger.info("Entry thread 2x started"); - try (ActiveSpan activeSpan = tracer.buildSpan("parent").startActive()) { - Runnable action = new RunnableAction(activeSpan); - Runnable action2 = new RunnableAction(activeSpan); + try (Scope scope = tracer.buildSpan("parent").startActive()) { + Runnable action = new RunnableAction((AutoFinishScope)scope); + Runnable action2 = new RunnableAction((AutoFinishScope)scope); Random random = new Random(); diff --git a/opentracing-examples/src/test/java/io/opentracing/examples/active_span_replacement/ActiveSpanReplacementTest.java b/opentracing-examples/src/test/java/io/opentracing/examples/active_span_replacement/ActiveSpanReplacementTest.java index 7c907014..72cb979b 100644 --- a/opentracing-examples/src/test/java/io/opentracing/examples/active_span_replacement/ActiveSpanReplacementTest.java +++ b/opentracing-examples/src/test/java/io/opentracing/examples/active_span_replacement/ActiveSpanReplacementTest.java @@ -13,11 +13,12 @@ */ package io.opentracing.examples.active_span_replacement; -import io.opentracing.ActiveSpan; +import io.opentracing.Scope; +import io.opentracing.Span; import io.opentracing.mock.MockSpan; import io.opentracing.mock.MockTracer; import io.opentracing.mock.MockTracer.Propagator; -import io.opentracing.util.ThreadLocalActiveSpanSource; +import io.opentracing.util.ThreadLocalScopeManager; import org.junit.Test; import java.util.List; @@ -35,7 +36,7 @@ public class ActiveSpanReplacementTest { - private final MockTracer tracer = new MockTracer(new ThreadLocalActiveSpanSource(), + private final MockTracer tracer = new MockTracer(new ThreadLocalScopeManager(), Propagator.TEXT_MAP); private final ExecutorService executor = Executors.newCachedThreadPool(); @@ -43,8 +44,9 @@ public class ActiveSpanReplacementTest { @Test public void test() throws Exception { // Start an isolated task and query for its result in another task/thread - try (ActiveSpan span = tracer.buildSpan("initial").startActive()) { - submitAnotherTask(span); + try (Scope scope = tracer.buildSpan("initial").startActive(false)) { + // Explicitly pass a Span to be finished once a late calculation is done. + submitAnotherTask(scope.span()); } await().atMost(15, TimeUnit.SECONDS).until(finishedSpansSize(tracer), equalTo(3)); @@ -63,25 +65,25 @@ public void test() throws Exception { assertNotEquals(spans.get(0).context().traceId(), spans.get(1).context().traceId()); assertEquals(0, spans.get(0).parentId()); - assertNull(tracer.activeSpan()); + assertNull(tracer.scopeManager().active()); } - private void submitAnotherTask(ActiveSpan span) { - final ActiveSpan.Continuation cont = span.capture(); + private void submitAnotherTask(final Span initialSpan) { executor.submit(new Runnable() { @Override public void run() { // Create a new Span for this task - try (ActiveSpan taskSpan = tracer.buildSpan("task").startActive()) { + try (Scope taskScope = tracer.buildSpan("task").startActive()) { // Simulate work strictly related to the initial Span - try (ActiveSpan initialSpan = cont.activate()) { + // and finish it. + try (Scope initialScope = tracer.scopeManager().activate(initialSpan)) { sleep(50); } // Restore the span for this task and create a subspan - try (ActiveSpan subTask = tracer.buildSpan("subtask").startActive()) { + try (Scope subTaskScope = tracer.buildSpan("subtask").startActive()) { } } } diff --git a/opentracing-examples/src/test/java/io/opentracing/examples/client_server/Client.java b/opentracing-examples/src/test/java/io/opentracing/examples/client_server/Client.java index 15554a08..2954ab33 100644 --- a/opentracing-examples/src/test/java/io/opentracing/examples/client_server/Client.java +++ b/opentracing-examples/src/test/java/io/opentracing/examples/client_server/Client.java @@ -13,7 +13,7 @@ */ package io.opentracing.examples.client_server; -import io.opentracing.ActiveSpan; +import io.opentracing.Scope; import io.opentracing.Tracer; import io.opentracing.propagation.Format.Builtin; import io.opentracing.propagation.TextMapInjectAdapter; @@ -34,11 +34,11 @@ public Client(ArrayBlockingQueue queue, Tracer tracer) { public void send() throws InterruptedException { Message message = new Message(); - try (ActiveSpan activeSpan = tracer.buildSpan("send") + try (Scope scope = tracer.buildSpan("send") .withTag(Tags.SPAN_KIND.getKey(), Tags.SPAN_KIND_CLIENT) .withTag(Tags.COMPONENT.getKey(), "example-client") .startActive()) { - tracer.inject(activeSpan.context(), Builtin.TEXT_MAP, new TextMapInjectAdapter(message)); + tracer.inject(scope.span().context(), Builtin.TEXT_MAP, new TextMapInjectAdapter(message)); queue.put(message); } } diff --git a/opentracing-examples/src/test/java/io/opentracing/examples/client_server/Server.java b/opentracing-examples/src/test/java/io/opentracing/examples/client_server/Server.java index 2067ee2d..240445ea 100644 --- a/opentracing-examples/src/test/java/io/opentracing/examples/client_server/Server.java +++ b/opentracing-examples/src/test/java/io/opentracing/examples/client_server/Server.java @@ -13,7 +13,7 @@ */ package io.opentracing.examples.client_server; -import io.opentracing.ActiveSpan; +import io.opentracing.Scope; import io.opentracing.SpanContext; import io.opentracing.Tracer; import io.opentracing.propagation.Format.Builtin; @@ -34,7 +34,7 @@ public Server(ArrayBlockingQueue queue, Tracer tracer) { private void process(Message message) { SpanContext context = tracer.extract(Builtin.TEXT_MAP, new TextMapExtractAdapter(message)); - try (ActiveSpan activeSpan = tracer.buildSpan("receive") + try (Scope scope = tracer.buildSpan("receive") .withTag(Tags.SPAN_KIND.getKey(), Tags.SPAN_KIND_SERVER) .withTag(Tags.COMPONENT.getKey(), "example-server") .asChildOf(context).startActive()) { diff --git a/opentracing-examples/src/test/java/io/opentracing/examples/client_server/TestClientServerTest.java b/opentracing-examples/src/test/java/io/opentracing/examples/client_server/TestClientServerTest.java index 489b98b6..a289cc06 100644 --- a/opentracing-examples/src/test/java/io/opentracing/examples/client_server/TestClientServerTest.java +++ b/opentracing-examples/src/test/java/io/opentracing/examples/client_server/TestClientServerTest.java @@ -17,7 +17,7 @@ import io.opentracing.mock.MockTracer; import io.opentracing.mock.MockTracer.Propagator; import io.opentracing.tag.Tags; -import io.opentracing.util.ThreadLocalActiveSpanSource; +import io.opentracing.util.ThreadLocalScopeManager; import org.junit.After; import org.junit.Before; import org.junit.Test; @@ -36,7 +36,7 @@ public class TestClientServerTest { - private final MockTracer tracer = new MockTracer(new ThreadLocalActiveSpanSource(), + private final MockTracer tracer = new MockTracer(new ThreadLocalScopeManager(), Propagator.TEXT_MAP); private final ArrayBlockingQueue queue = new ArrayBlockingQueue<>(10); private Server server; @@ -65,6 +65,6 @@ public void test() throws Exception { assertEquals(finished.get(0).context().traceId(), finished.get(1).context().traceId()); assertNotNull(getOneByTag(finished, Tags.SPAN_KIND, Tags.SPAN_KIND_CLIENT)); assertNotNull(getOneByTag(finished, Tags.SPAN_KIND, Tags.SPAN_KIND_SERVER)); - assertNull(tracer.activeSpan()); + assertNull(tracer.scopeManager().active()); } } diff --git a/opentracing-examples/src/test/java/io/opentracing/examples/common_request_handler/HandlerTest.java b/opentracing-examples/src/test/java/io/opentracing/examples/common_request_handler/HandlerTest.java index 189ae1de..3e487d4c 100644 --- a/opentracing-examples/src/test/java/io/opentracing/examples/common_request_handler/HandlerTest.java +++ b/opentracing-examples/src/test/java/io/opentracing/examples/common_request_handler/HandlerTest.java @@ -13,12 +13,12 @@ */ package io.opentracing.examples.common_request_handler; -import io.opentracing.ActiveSpan; +import io.opentracing.Scope; import io.opentracing.mock.MockSpan; import io.opentracing.mock.MockTracer; import io.opentracing.mock.MockTracer.Propagator; import io.opentracing.tag.Tags; -import io.opentracing.util.ThreadLocalActiveSpanSource; +import io.opentracing.util.ThreadLocalScopeManager; import org.junit.Before; import org.junit.Test; @@ -39,7 +39,7 @@ */ public class HandlerTest { - private final MockTracer tracer = new MockTracer(new ThreadLocalActiveSpanSource(), + private final MockTracer tracer = new MockTracer(new ThreadLocalScopeManager(), Propagator.TEXT_MAP); private final Client client = new Client(new RequestHandler(tracer)); @@ -67,7 +67,7 @@ public void two_requests() throws Exception { assertEquals(0, finished.get(0).parentId()); assertEquals(0, finished.get(1).parentId()); - assertNull(tracer.activeSpan()); + assertNull(tracer.scopeManager().active()); } /** @@ -75,7 +75,7 @@ public void two_requests() throws Exception { */ @Test public void parent_not_picked_up() throws Exception { - try (ActiveSpan parent = tracer.buildSpan("parent").startActive()) { + try (Scope parent = tracer.buildSpan("parent").startActive()) { String response = client.send("no_parent").get(15, TimeUnit.SECONDS); assertEquals("no_parent:response", response); } @@ -102,8 +102,8 @@ public void parent_not_picked_up() throws Exception { @Test public void bad_solution_to_set_parent() throws Exception { Client client; - try (ActiveSpan parent = tracer.buildSpan("parent").startActive()) { - client = new Client(new RequestHandler(tracer, parent.context())); + try (Scope parent = tracer.buildSpan("parent").startActive()) { + client = new Client(new RequestHandler(tracer, parent.span().context())); String response = client.send("correct_parent").get(15, TimeUnit.SECONDS); assertEquals("correct_parent:response", response); } diff --git a/opentracing-examples/src/test/java/io/opentracing/examples/late_span_finish/LateSpanFinishTest.java b/opentracing-examples/src/test/java/io/opentracing/examples/late_span_finish/LateSpanFinishTest.java index 9fc043a0..60260771 100644 --- a/opentracing-examples/src/test/java/io/opentracing/examples/late_span_finish/LateSpanFinishTest.java +++ b/opentracing-examples/src/test/java/io/opentracing/examples/late_span_finish/LateSpanFinishTest.java @@ -13,12 +13,12 @@ */ package io.opentracing.examples.late_span_finish; -import io.opentracing.ActiveSpan; +import io.opentracing.Scope; import io.opentracing.Span; import io.opentracing.mock.MockSpan; import io.opentracing.mock.MockTracer; import io.opentracing.mock.MockTracer.Propagator; -import io.opentracing.util.ThreadLocalActiveSpanSource; +import io.opentracing.util.ThreadLocalScopeManager; import org.junit.Test; import java.util.List; @@ -33,7 +33,7 @@ public class LateSpanFinishTest { - private final MockTracer tracer = new MockTracer(new ThreadLocalActiveSpanSource(), + private final MockTracer tracer = new MockTracer(new ThreadLocalScopeManager(), Propagator.TEXT_MAP); private final ExecutorService executor = Executors.newCachedThreadPool(); @@ -58,7 +58,7 @@ public void test() throws Exception { assertSameTrace(spans); - assertNull(tracer.activeSpan()); + assertNull(tracer.scopeManager().active()); } @@ -72,11 +72,10 @@ private void submitTasks(final Span parentSpan) { @Override public void run() { // Alternative to calling makeActive() is to pass it manually to asChildOf() for each created Span. - try (ActiveSpan span = tracer.makeActive(parentSpan)) { - try (ActiveSpan childSpan1 = tracer.buildSpan("task1").startActive()) { + try (Scope scope = tracer.scopeManager().activate(parentSpan, false)) { + try (Scope childScope1 = tracer.buildSpan("task1").startActive()) { sleep(55); } - span.capture(); // Workaround, prevent parentSpan from being finished here. } } }); @@ -84,11 +83,10 @@ public void run() { executor.submit(new Runnable() { @Override public void run() { - try (ActiveSpan span = tracer.makeActive(parentSpan)) { - try (ActiveSpan childSpan1 = tracer.buildSpan("task2").startActive()) { + try (Scope span = tracer.scopeManager().activate(parentSpan, false)) { + try (Scope childScope2 = tracer.buildSpan("task2").startActive()) { sleep(85); } - span.capture(); // Workaround, prevent parentSpan from being finished here. } } }); diff --git a/opentracing-examples/src/test/java/io/opentracing/examples/listener_per_request/ListenerTest.java b/opentracing-examples/src/test/java/io/opentracing/examples/listener_per_request/ListenerTest.java index 0d8646cb..4afd3b0e 100644 --- a/opentracing-examples/src/test/java/io/opentracing/examples/listener_per_request/ListenerTest.java +++ b/opentracing-examples/src/test/java/io/opentracing/examples/listener_per_request/ListenerTest.java @@ -17,7 +17,7 @@ import io.opentracing.mock.MockTracer; import io.opentracing.mock.MockTracer.Propagator; import io.opentracing.tag.Tags; -import io.opentracing.util.ThreadLocalActiveSpanSource; +import io.opentracing.util.ThreadLocalScopeManager; import org.junit.Test; import java.util.List; @@ -32,7 +32,7 @@ */ public class ListenerTest { - private final MockTracer tracer = new MockTracer(new ThreadLocalActiveSpanSource(), + private final MockTracer tracer = new MockTracer(new ThreadLocalScopeManager(), Propagator.TEXT_MAP); @Test @@ -44,6 +44,6 @@ public void test() throws Exception { List finished = tracer.finishedSpans(); assertEquals(1, finished.size()); assertNotNull(getOneByTag(finished, Tags.SPAN_KIND, Tags.SPAN_KIND_CLIENT)); - assertNull(tracer.activeSpan()); + assertNull(tracer.scopeManager().active()); } } diff --git a/opentracing-examples/src/test/java/io/opentracing/examples/multiple_callbacks/Client.java b/opentracing-examples/src/test/java/io/opentracing/examples/multiple_callbacks/Client.java index 0a7c9858..6be803f5 100644 --- a/opentracing-examples/src/test/java/io/opentracing/examples/multiple_callbacks/Client.java +++ b/opentracing-examples/src/test/java/io/opentracing/examples/multiple_callbacks/Client.java @@ -13,8 +13,10 @@ */ package io.opentracing.examples.multiple_callbacks; -import io.opentracing.ActiveSpan; +import io.opentracing.Scope; import io.opentracing.Tracer; +import io.opentracing.examples.AutoFinishScope; +import io.opentracing.examples.AutoFinishScope.Continuation; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -36,15 +38,17 @@ public Client(Tracer tracer) { this.tracer = tracer; } - public Future send(final Object message, ActiveSpan parentSpan, final long milliseconds) { - final ActiveSpan.Continuation cont = parentSpan.capture(); + public Future send(final Object message, final long milliseconds) { + Scope scope = tracer.scopeManager().active(); + final Continuation cont = ((AutoFinishScope)scope).capture(); + return executor.submit(new Callable() { @Override public Object call() throws Exception { logger.info("Child thread with message '{}' started", message); - try (ActiveSpan parentSpan = cont.activate()) { - try (ActiveSpan span = tracer.buildSpan("subtask").startActive()) { + try (Scope parentScope = cont.activate()) { + try (Scope subtaskScope = tracer.buildSpan("subtask").startActive()) { // Simulate work. sleep(milliseconds); } diff --git a/opentracing-examples/src/test/java/io/opentracing/examples/multiple_callbacks/MultipleCallbacksTest.java b/opentracing-examples/src/test/java/io/opentracing/examples/multiple_callbacks/MultipleCallbacksTest.java index 92100687..517e77fd 100644 --- a/opentracing-examples/src/test/java/io/opentracing/examples/multiple_callbacks/MultipleCallbacksTest.java +++ b/opentracing-examples/src/test/java/io/opentracing/examples/multiple_callbacks/MultipleCallbacksTest.java @@ -13,11 +13,11 @@ */ package io.opentracing.examples.multiple_callbacks; -import io.opentracing.ActiveSpan; +import io.opentracing.Scope; +import io.opentracing.examples.AutoFinishScopeManager; import io.opentracing.mock.MockSpan; import io.opentracing.mock.MockTracer; import io.opentracing.mock.MockTracer.Propagator; -import io.opentracing.util.ThreadLocalActiveSpanSource; import org.junit.Test; import java.util.List; @@ -31,16 +31,16 @@ public class MultipleCallbacksTest { - private final MockTracer tracer = new MockTracer(new ThreadLocalActiveSpanSource(), + private final MockTracer tracer = new MockTracer(new AutoFinishScopeManager(), Propagator.TEXT_MAP); @Test public void test() throws Exception { Client client = new Client(tracer); - try (ActiveSpan span = tracer.buildSpan("parent").startActive()) { - client.send("task1", span, 300); - client.send("task2", span, 200); - client.send("task3", span, 100); + try (Scope scope = tracer.buildSpan("parent").startActive()) { + client.send("task1", 300); + client.send("task2", 200); + client.send("task3", 100); } await().atMost(15, TimeUnit.SECONDS).until(finishedSpansSize(tracer), equalTo(4)); @@ -56,6 +56,6 @@ public void test() throws Exception { assertEquals(parentSpan.context().spanId(), spans.get(i).parentId()); } - assertNull(tracer.activeSpan()); + assertNull(tracer.scopeManager().active()); } } diff --git a/opentracing-examples/src/test/java/io/opentracing/examples/nested_callbacks/NestedCallbacksTest.java b/opentracing-examples/src/test/java/io/opentracing/examples/nested_callbacks/NestedCallbacksTest.java index d25830ba..9f74fc83 100644 --- a/opentracing-examples/src/test/java/io/opentracing/examples/nested_callbacks/NestedCallbacksTest.java +++ b/opentracing-examples/src/test/java/io/opentracing/examples/nested_callbacks/NestedCallbacksTest.java @@ -13,11 +13,12 @@ */ package io.opentracing.examples.nested_callbacks; -import io.opentracing.ActiveSpan; +import io.opentracing.Scope; +import io.opentracing.Span; import io.opentracing.mock.MockSpan; import io.opentracing.mock.MockTracer; import io.opentracing.mock.MockTracer.Propagator; -import io.opentracing.util.ThreadLocalActiveSpanSource; +import io.opentracing.util.ThreadLocalScopeManager; import org.junit.Test; import java.util.List; @@ -34,15 +35,15 @@ public class NestedCallbacksTest { - private final MockTracer tracer = new MockTracer(new ThreadLocalActiveSpanSource(), + private final MockTracer tracer = new MockTracer(new ThreadLocalScopeManager(), Propagator.TEXT_MAP); private final ExecutorService executor = Executors.newCachedThreadPool(); @Test public void test() throws Exception { - try (ActiveSpan span = tracer.buildSpan("one").startActive()) { - submitCallbacks(span); + try (Scope scope = tracer.buildSpan("one").startActive(false)) { + submitCallbacks(scope.span()); } await().atMost(15, TimeUnit.SECONDS).until(finishedSpansSize(tracer), equalTo(1)); @@ -57,30 +58,27 @@ public void test() throws Exception { assertEquals(Integer.toString(i), tags.get("key" + i)); } - assertNull(tracer.activeSpan()); + assertNull(tracer.scopeManager().active()); } - private void submitCallbacks(ActiveSpan span) { - final ActiveSpan.Continuation cont = span.capture(); + private void submitCallbacks(final Span span) { executor.submit(new Runnable() { @Override public void run() { - try (ActiveSpan span = cont.activate()) { + try (Scope scope = tracer.scopeManager().activate(span, false)) { span.setTag("key1", "1"); - final ActiveSpan.Continuation cont = span.capture(); executor.submit(new Runnable() { @Override public void run() { - try (ActiveSpan span = cont.activate()) { + try (Scope scope = tracer.scopeManager().activate(span, false)) { span.setTag("key2", "2"); - final ActiveSpan.Continuation cont = span.capture(); executor.submit(new Runnable() { @Override public void run() { - try (ActiveSpan span = cont.activate()) { + try (Scope scope = tracer.scopeManager().activate(span)) { span.setTag("key3", "3"); } } From ba0984c46ebc5f19a0498de4a80c4646c2267629 Mon Sep 17 00:00:00 2001 From: Tyler Benson Date: Fri, 15 Sep 2017 14:45:06 -0700 Subject: [PATCH 4/5] Add examples for async as test cases This includes execution flow similar to: * Actor ask/tell * Promises with callbacks * Work interleaved on a thread using suspend/resume. The implementations of these execution models are obviously very simplistic, but intended to emphasize the tracing aspect. These tests also make heavy use of the Phaser in order to insure deterministic execution of the tests for multi-threaded execution. Hopefully this does not detract from the examples too much. --- .../examples/async_propagation/Actor.java | 102 +++++++++ .../AsyncPropagationTest.java | 213 ++++++++++++++++++ .../examples/async_propagation/Promise.java | 114 ++++++++++ .../async_propagation/PromiseContext.java | 44 ++++ .../async_propagation/SuspendResume.java | 52 +++++ 5 files changed, 525 insertions(+) create mode 100644 opentracing-examples/src/test/java/io/opentracing/examples/async_propagation/Actor.java create mode 100644 opentracing-examples/src/test/java/io/opentracing/examples/async_propagation/AsyncPropagationTest.java create mode 100644 opentracing-examples/src/test/java/io/opentracing/examples/async_propagation/Promise.java create mode 100644 opentracing-examples/src/test/java/io/opentracing/examples/async_propagation/PromiseContext.java create mode 100644 opentracing-examples/src/test/java/io/opentracing/examples/async_propagation/SuspendResume.java diff --git a/opentracing-examples/src/test/java/io/opentracing/examples/async_propagation/Actor.java b/opentracing-examples/src/test/java/io/opentracing/examples/async_propagation/Actor.java new file mode 100644 index 00000000..1c60b4c0 --- /dev/null +++ b/opentracing-examples/src/test/java/io/opentracing/examples/async_propagation/Actor.java @@ -0,0 +1,102 @@ +/* + * Copyright 2016-2017 The OpenTracing 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.opentracing.examples.async_propagation; + +import io.opentracing.ActiveSpan; +import io.opentracing.mock.MockTracer; +import io.opentracing.tag.Tags; + +import java.util.concurrent.Callable; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.Future; +import java.util.concurrent.Phaser; + +/** @author tylerbenson */ +public class Actor implements AutoCloseable { + private final ExecutorService executor; + private final MockTracer tracer; + private final Phaser phaser; + + public Actor(MockTracer tracer, Phaser phaser) { + // Passed along here for testing. Normally should be referenced via GlobalTracer.get(). + this.tracer = tracer; + + this.phaser = phaser; + executor = Executors.newSingleThreadExecutor(); + } + + @Override + public void close() { + executor.shutdown(); + } + + public void tell(final String message) { + final ActiveSpan.Continuation continuation = tracer.activeSpan().capture(); + phaser.register(); + executor.submit( + new Runnable() { + @Override + public void run() { + try (ActiveSpan parent = continuation.activate()) { + try (ActiveSpan child = + tracer + .buildSpan("sent") + .asChildOf(parent) + .withTag(Tags.SPAN_KIND.getKey(), Tags.SPAN_KIND_CONSUMER) + .startActive()) { + phaser.arriveAndAwaitAdvance(); // child tracer started + System.out.println("received " + message); + phaser.arriveAndAwaitAdvance(); // assert size + } + phaser.arriveAndAwaitAdvance(); // child tracer finished + phaser.arriveAndAwaitAdvance(); // assert size + } + phaser.arriveAndAwaitAdvance(); // parent tracer finished + phaser.arriveAndDeregister(); // assert size + } + }); + } + + public Future ask(final String message) { + final ActiveSpan.Continuation continuation = tracer.activeSpan().capture(); + phaser.register(); + Future future = + executor.submit( + new Callable() { + @Override + public String call() throws Exception { + try (ActiveSpan parent = continuation.activate()) { + try (ActiveSpan child = + tracer + .buildSpan("sent") + .asChildOf(parent) + .withTag(Tags.SPAN_KIND.getKey(), Tags.SPAN_KIND_CONSUMER) + .startActive()) { + phaser.arriveAndAwaitAdvance(); // child tracer started + phaser.arriveAndAwaitAdvance(); // assert size + return "received " + message; + } finally { + phaser.arriveAndAwaitAdvance(); // child tracer finished + phaser.arriveAndAwaitAdvance(); // assert size + } + } finally { + phaser.arriveAndAwaitAdvance(); // parent tracer finished + phaser.arriveAndDeregister(); // assert size + } + } + }); + return future; + } +} diff --git a/opentracing-examples/src/test/java/io/opentracing/examples/async_propagation/AsyncPropagationTest.java b/opentracing-examples/src/test/java/io/opentracing/examples/async_propagation/AsyncPropagationTest.java new file mode 100644 index 00000000..426de4e9 --- /dev/null +++ b/opentracing-examples/src/test/java/io/opentracing/examples/async_propagation/AsyncPropagationTest.java @@ -0,0 +1,213 @@ +/* + * Copyright 2016-2017 The OpenTracing 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.opentracing.examples.async_propagation; + +import io.opentracing.ActiveSpan; +import io.opentracing.mock.MockSpan; +import io.opentracing.mock.MockTracer; +import io.opentracing.mock.MockTracer.Propagator; +import io.opentracing.tag.Tags; +import io.opentracing.util.ThreadLocalActiveSpanSource; +import org.junit.Before; +import org.junit.Test; + +import java.util.List; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.Future; +import java.util.concurrent.Phaser; +import java.util.concurrent.atomic.AtomicReference; + +import static io.opentracing.examples.TestUtils.getOneByTag; +import static org.assertj.core.api.Assertions.assertThat; + +/** + * These tests are intended to simulate the kind of async models that are common in java async + * frameworks. + * + *
    + *
  • Actor ask/tell + *
  • Promises with callbacks + *
  • Work split by suspend/resume + *
+ * + * For improved readability, ignore the phaser lines as those are there to ensure deterministic + * execution for the tests without sleeps. + * + * @author tylerbenson + */ +public class AsyncPropagationTest { + + private final MockTracer tracer = + new MockTracer(new ThreadLocalActiveSpanSource(), Propagator.TEXT_MAP); + private Phaser phaser; + + @Before + public void before() { + phaser = new Phaser(); + } + + @Test + public void testActorTell() { + try (Actor actor = new Actor(tracer, phaser)) { + phaser.register(); + try (ActiveSpan parent = + tracer + .buildSpan("actorTell") + .withTag(Tags.SPAN_KIND.getKey(), Tags.SPAN_KIND_PRODUCER) + .withTag(Tags.COMPONENT.getKey(), "example-actor") + .startActive()) { + actor.tell("my message"); + } + phaser.arriveAndAwaitAdvance(); // child tracer started + assertThat(tracer.finishedSpans().size()).isEqualTo(0); + phaser.arriveAndAwaitAdvance(); // continue... + + phaser.arriveAndAwaitAdvance(); // child tracer finished + assertThat(tracer.finishedSpans().size()).isEqualTo(1); + assertThat(getOneByTag(tracer.finishedSpans(), Tags.SPAN_KIND, Tags.SPAN_KIND_CONSUMER)) + .isNotNull(); + phaser.arriveAndAwaitAdvance(); // continue... + + phaser.arriveAndAwaitAdvance(); // parent tracer finished + List finished = tracer.finishedSpans(); + phaser.arriveAndDeregister(); // continue... + + assertThat(finished.size()).isEqualTo(2); + assertThat(finished.get(0).context().traceId()) + .isEqualTo(finished.get(1).context().traceId()); + assertThat(getOneByTag(finished, Tags.SPAN_KIND, Tags.SPAN_KIND_CONSUMER)).isNotNull(); + assertThat(getOneByTag(finished, Tags.SPAN_KIND, Tags.SPAN_KIND_PRODUCER)).isNotNull(); + assertThat(tracer.activeSpan()).isNull(); + } + } + + @Test + public void testActorAsk() throws ExecutionException, InterruptedException { + try (Actor actor = new Actor(tracer, phaser)) { + phaser.register(); + Future future; + try (ActiveSpan parent = + tracer + .buildSpan("actorAsk") + .withTag(Tags.SPAN_KIND.getKey(), Tags.SPAN_KIND_PRODUCER) + .withTag(Tags.COMPONENT.getKey(), "example-actor") + .startActive()) { + future = actor.ask("my message"); + } + phaser.arriveAndAwaitAdvance(); // child tracer started + assertThat(tracer.finishedSpans().size()).isEqualTo(0); + phaser.arriveAndAwaitAdvance(); // continue... + + phaser.arriveAndAwaitAdvance(); // child tracer finished + assertThat(tracer.finishedSpans().size()).isEqualTo(1); + assertThat(getOneByTag(tracer.finishedSpans(), Tags.SPAN_KIND, Tags.SPAN_KIND_CONSUMER)) + .isNotNull(); + phaser.arriveAndAwaitAdvance(); // continue... + + phaser.arriveAndAwaitAdvance(); // parent tracer finished + List finished = tracer.finishedSpans(); + phaser.arriveAndDeregister(); // continue... + + String message = future.get(); // This really should be a non-blocking callback... + assertThat(message).isEqualTo("received my message"); + assertThat(finished.size()).isEqualTo(2); + assertThat(finished.get(0).context().traceId()) + .isEqualTo(finished.get(1).context().traceId()); + assertThat(getOneByTag(finished, Tags.SPAN_KIND, Tags.SPAN_KIND_CONSUMER)).isNotNull(); + assertThat(getOneByTag(finished, Tags.SPAN_KIND, Tags.SPAN_KIND_PRODUCER)).isNotNull(); + assertThat(tracer.activeSpan()).isNull(); + } + } + + @Test + public void testPromiseCallback() { + phaser.register(); // register test thread + final AtomicReference successResult = new AtomicReference<>(); + final AtomicReference errorResult = new AtomicReference<>(); + try (PromiseContext context = new PromiseContext(phaser, 2)) { + try (ActiveSpan parent = + tracer + .buildSpan("promises") + .withTag(Tags.COMPONENT.getKey(), "example-promises") + .startActive()) { + + Promise promise1 = new Promise<>(context, tracer); + + promise1.onSuccess( + new Promise.SuccessCallback() { + @Override + public void accept(String s) { + successResult.set(s); + phaser.arriveAndAwaitAdvance(); // result set + } + }); + + Promise promise2 = new Promise(context, tracer); + + promise2.onError( + new Promise.ErrorCallback() { + @Override + public void accept(Throwable t) { + errorResult.set(t); + phaser.arriveAndAwaitAdvance(); // result set + } + }); + assertThat(tracer.finishedSpans().size()).isEqualTo(0); + promise1.success("success!"); + promise2.error(new Exception("some error.")); + } + + phaser.arriveAndAwaitAdvance(); // wait for results to be set + assertThat(successResult.get()).isEqualTo("success!"); + assertThat(errorResult.get()).hasMessage("some error."); + + phaser.arriveAndAwaitAdvance(); // wait for traces to be reported + List finished = tracer.finishedSpans(); + assertThat(finished.size()).isEqualTo(3); + assertThat(getOneByTag(finished, Tags.COMPONENT, "example-promises")).isNotNull(); + assertThat(getOneByTag(finished, Tags.COMPONENT, "example-promises").parentId()).isEqualTo(0); + long parentId = getOneByTag(finished, Tags.COMPONENT, "example-promises").context().spanId(); + assertThat(getOneByTag(finished, Tags.COMPONENT, "success")).isNotNull(); + assertThat(getOneByTag(finished, Tags.COMPONENT, "success").parentId()).isEqualTo(parentId); + assertThat(getOneByTag(finished, Tags.COMPONENT, "error")).isNotNull(); + assertThat(getOneByTag(finished, Tags.COMPONENT, "error").parentId()).isEqualTo(parentId); + } + } + + @Test + public void testContinuationInterleaving() { + SuspendResume job1 = new SuspendResume(1, tracer); + SuspendResume job2 = new SuspendResume(2, tracer); + + // Pretend that the framework is controlling actual execution here. + job1.doPart("some work for 1"); + job2.doPart("some work for 2"); + job1.doPart("other work for 1"); + job2.doPart("other work for 2"); + job2.doPart("more work for 2"); + job1.doPart("more work for 1"); + + job1.done(); + job2.done(); + + List finished = tracer.finishedSpans(); + assertThat(finished.size()).isEqualTo(2); + + assertThat(finished.get(0).operationName()).isEqualTo("job 1"); + assertThat(finished.get(1).operationName()).isEqualTo("job 2"); + + assertThat(finished.get(0).parentId()).isEqualTo(0); + assertThat(finished.get(1).parentId()).isEqualTo(0); + } +} diff --git a/opentracing-examples/src/test/java/io/opentracing/examples/async_propagation/Promise.java b/opentracing-examples/src/test/java/io/opentracing/examples/async_propagation/Promise.java new file mode 100644 index 00000000..80eb491b --- /dev/null +++ b/opentracing-examples/src/test/java/io/opentracing/examples/async_propagation/Promise.java @@ -0,0 +1,114 @@ +/* + * Copyright 2016-2017 The OpenTracing 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.opentracing.examples.async_propagation; + +import io.opentracing.ActiveSpan; +import io.opentracing.mock.MockTracer; +import io.opentracing.tag.Tags; + +import java.util.Collection; +import java.util.LinkedList; + +/** @author tylerbenson */ +public class Promise { + private final PromiseContext context; + private final MockTracer tracer; + private final ActiveSpan activeSpan; + + private final Collection>> successCallbacks = new LinkedList<>(); + private final Collection> errorCallbacks = new LinkedList<>(); + + public Promise(PromiseContext context, MockTracer tracer) { + this.context = context; + + // Passed along here for testing. Normally should be referenced via GlobalTracer.get(). + this.tracer = tracer; + activeSpan = tracer.activeSpan(); + } + + public void onSuccess(SuccessCallback successCallback) { + ActiveSpan.Continuation capture = activeSpan.capture(); + successCallbacks.add(new Pair<>(capture, successCallback)); + } + + public void onError(ErrorCallback errorCallback) { + ActiveSpan.Continuation capture = activeSpan.capture(); + errorCallbacks.add(new Pair<>(capture, errorCallback)); + } + + public void success(final T result) { + for (final Pair> pair : successCallbacks) { + context.submit( + new Runnable() { + @Override + public void run() { + try (ActiveSpan parent = pair.capture.activate()) { + try (ActiveSpan child = + tracer + .buildSpan("success") + .withTag(Tags.COMPONENT.getKey(), "success") + .asChildOf(parent) + .startActive()) { + pair.callback.accept(result); + } + } + context.getPhaser().arriveAndAwaitAdvance(); // trace reported + } + }); + } + } + + public void error(final Throwable error) { + for (final Pair pair : errorCallbacks) { + context.submit( + new Runnable() { + @Override + public void run() { + try (ActiveSpan parent = pair.capture.activate()) { + try (ActiveSpan child = + tracer + .buildSpan("error") + .withTag(Tags.COMPONENT.getKey(), "error") + .asChildOf(parent) + .startActive()) { + pair.callback.accept(error); + } + } + context.getPhaser().arriveAndAwaitAdvance(); // trace reported + } + }); + } + } + + public interface SuccessCallback { + /** @param t the result of the promise */ + void accept(T t); + } + + public interface ErrorCallback { + /** @param t the error result of the promise */ + void accept(Throwable t); + } + + private class Pair { + + final ActiveSpan.Continuation capture; + final C callback; + + public Pair(ActiveSpan.Continuation capture, C callback) { + this.capture = capture; + this.callback = callback; + } + } +} diff --git a/opentracing-examples/src/test/java/io/opentracing/examples/async_propagation/PromiseContext.java b/opentracing-examples/src/test/java/io/opentracing/examples/async_propagation/PromiseContext.java new file mode 100644 index 00000000..8951e0d3 --- /dev/null +++ b/opentracing-examples/src/test/java/io/opentracing/examples/async_propagation/PromiseContext.java @@ -0,0 +1,44 @@ +/* + * Copyright 2016-2017 The OpenTracing 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.opentracing.examples.async_propagation; + +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.Phaser; + +/** @author tylerbenson */ +public class PromiseContext implements AutoCloseable { + + private final Phaser phaser; + private final ExecutorService executor; + + public PromiseContext(Phaser phaser, int concurrency) { + this.phaser = phaser; + executor = Executors.newFixedThreadPool(concurrency); + } + + @Override + public void close() { + executor.shutdown(); + } + + public void submit(Runnable runnable) { + phaser.register(); // register the work to be done on the executor + executor.submit(runnable); + } + + public Phaser getPhaser() { + return phaser; + } +} diff --git a/opentracing-examples/src/test/java/io/opentracing/examples/async_propagation/SuspendResume.java b/opentracing-examples/src/test/java/io/opentracing/examples/async_propagation/SuspendResume.java new file mode 100644 index 00000000..47293308 --- /dev/null +++ b/opentracing-examples/src/test/java/io/opentracing/examples/async_propagation/SuspendResume.java @@ -0,0 +1,52 @@ +/* + * Copyright 2016-2017 The OpenTracing 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.opentracing.examples.async_propagation; + +import io.opentracing.ActiveSpan; +import io.opentracing.mock.MockTracer; +import io.opentracing.tag.Tags; + +/** @author tylerbenson */ +public class SuspendResume { + + private final int id; + private final MockTracer tracer; + private ActiveSpan.Continuation continuation; + + public SuspendResume(int id, MockTracer tracer) { + this.id = id; + + // Passed along here for testing. Normally should be referenced via GlobalTracer.get(). + this.tracer = tracer; + + try (ActiveSpan span = + tracer + .buildSpan("job " + id) + .withTag(Tags.COMPONENT.getKey(), "suspend-resume") + .startActive()) { + continuation = span.capture(); + } + } + + public void doPart(String name) { + try (ActiveSpan span = continuation.activate()) { + continuation = span.capture(); // prepare for the next part. + span.log("part: " + name); + } + } + + public void done() { + continuation.activate().deactivate(); + } +} From 6a56a6dd72b6548b42abd254286fd960df601dd0 Mon Sep 17 00:00:00 2001 From: Carlos Alberto Cortez Date: Wed, 20 Sep 2017 02:12:48 +0200 Subject: [PATCH 5/5] Make the async_propagation sample use the new Scope, as needed. * ThreadLocalScopeManager (without Continuation) where it's possible to predict where the Span should be finished. * AutoCloseScopeManager, where a ref-counting scenario is needed. --- .../examples/async_propagation/Actor.java | 19 ++++++----- .../AsyncPropagationTest.java | 34 +++++++++++-------- .../examples/async_propagation/Promise.java | 28 ++++++++------- .../async_propagation/SuspendResume.java | 18 +++++----- 4 files changed, 53 insertions(+), 46 deletions(-) diff --git a/opentracing-examples/src/test/java/io/opentracing/examples/async_propagation/Actor.java b/opentracing-examples/src/test/java/io/opentracing/examples/async_propagation/Actor.java index 1c60b4c0..d36c1885 100644 --- a/opentracing-examples/src/test/java/io/opentracing/examples/async_propagation/Actor.java +++ b/opentracing-examples/src/test/java/io/opentracing/examples/async_propagation/Actor.java @@ -13,7 +13,8 @@ */ package io.opentracing.examples.async_propagation; -import io.opentracing.ActiveSpan; +import io.opentracing.Scope; +import io.opentracing.Span; import io.opentracing.mock.MockTracer; import io.opentracing.tag.Tags; @@ -43,17 +44,17 @@ public void close() { } public void tell(final String message) { - final ActiveSpan.Continuation continuation = tracer.activeSpan().capture(); + final Span span = tracer.scopeManager().active().span(); phaser.register(); executor.submit( new Runnable() { @Override public void run() { - try (ActiveSpan parent = continuation.activate()) { - try (ActiveSpan child = + try (Scope parent = tracer.scopeManager().activate(span)) { + try (Scope child = tracer .buildSpan("sent") - .asChildOf(parent) + .asChildOf(parent.span()) .withTag(Tags.SPAN_KIND.getKey(), Tags.SPAN_KIND_CONSUMER) .startActive()) { phaser.arriveAndAwaitAdvance(); // child tracer started @@ -70,18 +71,18 @@ public void run() { } public Future ask(final String message) { - final ActiveSpan.Continuation continuation = tracer.activeSpan().capture(); + final Span span = tracer.scopeManager().active().span(); phaser.register(); Future future = executor.submit( new Callable() { @Override public String call() throws Exception { - try (ActiveSpan parent = continuation.activate()) { - try (ActiveSpan child = + try (Scope parent = tracer.scopeManager().activate(span)) { + try (Scope child = tracer .buildSpan("sent") - .asChildOf(parent) + .asChildOf(parent.span()) .withTag(Tags.SPAN_KIND.getKey(), Tags.SPAN_KIND_CONSUMER) .startActive()) { phaser.arriveAndAwaitAdvance(); // child tracer started diff --git a/opentracing-examples/src/test/java/io/opentracing/examples/async_propagation/AsyncPropagationTest.java b/opentracing-examples/src/test/java/io/opentracing/examples/async_propagation/AsyncPropagationTest.java index 426de4e9..1888d682 100644 --- a/opentracing-examples/src/test/java/io/opentracing/examples/async_propagation/AsyncPropagationTest.java +++ b/opentracing-examples/src/test/java/io/opentracing/examples/async_propagation/AsyncPropagationTest.java @@ -13,12 +13,14 @@ */ package io.opentracing.examples.async_propagation; -import io.opentracing.ActiveSpan; +import io.opentracing.Scope; +import io.opentracing.examples.AutoFinishScope; +import io.opentracing.examples.AutoFinishScopeManager; import io.opentracing.mock.MockSpan; import io.opentracing.mock.MockTracer; import io.opentracing.mock.MockTracer.Propagator; import io.opentracing.tag.Tags; -import io.opentracing.util.ThreadLocalActiveSpanSource; +import io.opentracing.util.ThreadLocalScopeManager; import org.junit.Before; import org.junit.Test; @@ -49,7 +51,9 @@ public class AsyncPropagationTest { private final MockTracer tracer = - new MockTracer(new ThreadLocalActiveSpanSource(), Propagator.TEXT_MAP); + new MockTracer(new ThreadLocalScopeManager(), Propagator.TEXT_MAP); + private final MockTracer autoTracer = + new MockTracer(new AutoFinishScopeManager(), Propagator.TEXT_MAP); private Phaser phaser; @Before @@ -61,12 +65,12 @@ public void before() { public void testActorTell() { try (Actor actor = new Actor(tracer, phaser)) { phaser.register(); - try (ActiveSpan parent = + try (Scope parent = tracer .buildSpan("actorTell") .withTag(Tags.SPAN_KIND.getKey(), Tags.SPAN_KIND_PRODUCER) .withTag(Tags.COMPONENT.getKey(), "example-actor") - .startActive()) { + .startActive(false)) { actor.tell("my message"); } phaser.arriveAndAwaitAdvance(); // child tracer started @@ -88,7 +92,7 @@ public void testActorTell() { .isEqualTo(finished.get(1).context().traceId()); assertThat(getOneByTag(finished, Tags.SPAN_KIND, Tags.SPAN_KIND_CONSUMER)).isNotNull(); assertThat(getOneByTag(finished, Tags.SPAN_KIND, Tags.SPAN_KIND_PRODUCER)).isNotNull(); - assertThat(tracer.activeSpan()).isNull(); + assertThat(tracer.scopeManager().active()).isNull(); } } @@ -97,12 +101,12 @@ public void testActorAsk() throws ExecutionException, InterruptedException { try (Actor actor = new Actor(tracer, phaser)) { phaser.register(); Future future; - try (ActiveSpan parent = + try (Scope parent = tracer .buildSpan("actorAsk") .withTag(Tags.SPAN_KIND.getKey(), Tags.SPAN_KIND_PRODUCER) .withTag(Tags.COMPONENT.getKey(), "example-actor") - .startActive()) { + .startActive(false)) { future = actor.ask("my message"); } phaser.arriveAndAwaitAdvance(); // child tracer started @@ -126,7 +130,7 @@ public void testActorAsk() throws ExecutionException, InterruptedException { .isEqualTo(finished.get(1).context().traceId()); assertThat(getOneByTag(finished, Tags.SPAN_KIND, Tags.SPAN_KIND_CONSUMER)).isNotNull(); assertThat(getOneByTag(finished, Tags.SPAN_KIND, Tags.SPAN_KIND_PRODUCER)).isNotNull(); - assertThat(tracer.activeSpan()).isNull(); + assertThat(tracer.scopeManager().active()).isNull(); } } @@ -136,13 +140,13 @@ public void testPromiseCallback() { final AtomicReference successResult = new AtomicReference<>(); final AtomicReference errorResult = new AtomicReference<>(); try (PromiseContext context = new PromiseContext(phaser, 2)) { - try (ActiveSpan parent = - tracer + try (Scope parent = + autoTracer .buildSpan("promises") .withTag(Tags.COMPONENT.getKey(), "example-promises") .startActive()) { - Promise promise1 = new Promise<>(context, tracer); + Promise promise1 = new Promise<>(context, autoTracer); promise1.onSuccess( new Promise.SuccessCallback() { @@ -153,7 +157,7 @@ public void accept(String s) { } }); - Promise promise2 = new Promise(context, tracer); + Promise promise2 = new Promise(context, autoTracer); promise2.onError( new Promise.ErrorCallback() { @@ -163,7 +167,7 @@ public void accept(Throwable t) { phaser.arriveAndAwaitAdvance(); // result set } }); - assertThat(tracer.finishedSpans().size()).isEqualTo(0); + assertThat(autoTracer.finishedSpans().size()).isEqualTo(0); promise1.success("success!"); promise2.error(new Exception("some error.")); } @@ -173,7 +177,7 @@ public void accept(Throwable t) { assertThat(errorResult.get()).hasMessage("some error."); phaser.arriveAndAwaitAdvance(); // wait for traces to be reported - List finished = tracer.finishedSpans(); + List finished = autoTracer.finishedSpans(); assertThat(finished.size()).isEqualTo(3); assertThat(getOneByTag(finished, Tags.COMPONENT, "example-promises")).isNotNull(); assertThat(getOneByTag(finished, Tags.COMPONENT, "example-promises").parentId()).isEqualTo(0); diff --git a/opentracing-examples/src/test/java/io/opentracing/examples/async_propagation/Promise.java b/opentracing-examples/src/test/java/io/opentracing/examples/async_propagation/Promise.java index 80eb491b..7919d7c4 100644 --- a/opentracing-examples/src/test/java/io/opentracing/examples/async_propagation/Promise.java +++ b/opentracing-examples/src/test/java/io/opentracing/examples/async_propagation/Promise.java @@ -13,7 +13,9 @@ */ package io.opentracing.examples.async_propagation; -import io.opentracing.ActiveSpan; +import io.opentracing.Scope; +import io.opentracing.examples.AutoFinishScope; +import io.opentracing.examples.AutoFinishScope.Continuation; import io.opentracing.mock.MockTracer; import io.opentracing.tag.Tags; @@ -24,7 +26,7 @@ public class Promise { private final PromiseContext context; private final MockTracer tracer; - private final ActiveSpan activeSpan; + private final Scope scope; private final Collection>> successCallbacks = new LinkedList<>(); private final Collection> errorCallbacks = new LinkedList<>(); @@ -34,16 +36,16 @@ public Promise(PromiseContext context, MockTracer tracer) { // Passed along here for testing. Normally should be referenced via GlobalTracer.get(). this.tracer = tracer; - activeSpan = tracer.activeSpan(); + scope = tracer.scopeManager().active(); } public void onSuccess(SuccessCallback successCallback) { - ActiveSpan.Continuation capture = activeSpan.capture(); + Continuation capture = ((AutoFinishScope)scope).capture(); successCallbacks.add(new Pair<>(capture, successCallback)); } public void onError(ErrorCallback errorCallback) { - ActiveSpan.Continuation capture = activeSpan.capture(); + Continuation capture = ((AutoFinishScope)scope).capture(); errorCallbacks.add(new Pair<>(capture, errorCallback)); } @@ -53,12 +55,12 @@ public void success(final T result) { new Runnable() { @Override public void run() { - try (ActiveSpan parent = pair.capture.activate()) { - try (ActiveSpan child = + try (Scope parent = pair.capture.activate()) { + try (Scope child = tracer .buildSpan("success") .withTag(Tags.COMPONENT.getKey(), "success") - .asChildOf(parent) + .asChildOf(parent.span()) .startActive()) { pair.callback.accept(result); } @@ -75,12 +77,12 @@ public void error(final Throwable error) { new Runnable() { @Override public void run() { - try (ActiveSpan parent = pair.capture.activate()) { - try (ActiveSpan child = + try (Scope parent = pair.capture.activate()) { + try (Scope child = tracer .buildSpan("error") .withTag(Tags.COMPONENT.getKey(), "error") - .asChildOf(parent) + .asChildOf(parent.span()) .startActive()) { pair.callback.accept(error); } @@ -103,10 +105,10 @@ public interface ErrorCallback { private class Pair { - final ActiveSpan.Continuation capture; + final Continuation capture; final C callback; - public Pair(ActiveSpan.Continuation capture, C callback) { + public Pair(Continuation capture, C callback) { this.capture = capture; this.callback = callback; } diff --git a/opentracing-examples/src/test/java/io/opentracing/examples/async_propagation/SuspendResume.java b/opentracing-examples/src/test/java/io/opentracing/examples/async_propagation/SuspendResume.java index 47293308..02cb87c9 100644 --- a/opentracing-examples/src/test/java/io/opentracing/examples/async_propagation/SuspendResume.java +++ b/opentracing-examples/src/test/java/io/opentracing/examples/async_propagation/SuspendResume.java @@ -13,7 +13,8 @@ */ package io.opentracing.examples.async_propagation; -import io.opentracing.ActiveSpan; +import io.opentracing.Scope; +import io.opentracing.Span; import io.opentracing.mock.MockTracer; import io.opentracing.tag.Tags; @@ -22,7 +23,7 @@ public class SuspendResume { private final int id; private final MockTracer tracer; - private ActiveSpan.Continuation continuation; + private Span span; public SuspendResume(int id, MockTracer tracer) { this.id = id; @@ -30,23 +31,22 @@ public SuspendResume(int id, MockTracer tracer) { // Passed along here for testing. Normally should be referenced via GlobalTracer.get(). this.tracer = tracer; - try (ActiveSpan span = + try (Scope scope = tracer .buildSpan("job " + id) .withTag(Tags.COMPONENT.getKey(), "suspend-resume") - .startActive()) { - continuation = span.capture(); + .startActive(false)) { + span = scope.span(); } } public void doPart(String name) { - try (ActiveSpan span = continuation.activate()) { - continuation = span.capture(); // prepare for the next part. - span.log("part: " + name); + try (Scope scope = tracer.scopeManager().activate(span, false)) { + scope.span().log("part: " + name); } } public void done() { - continuation.activate().deactivate(); + span.finish(); } }