From f52e7c299f85990c3c2346bd380377f0ec161edc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=90=B4=E6=99=9F=20Wu=20Sheng?= Date: Mon, 18 Sep 2017 10:12:40 +0800 Subject: [PATCH 1/7] Provide a new Tag for PEER_HOST_IPV4 (#184) --- .../io/opentracing/tag/IntOrStringTag.java | 26 +++++++++++++++++++ .../main/java/io/opentracing/tag/Tags.java | 2 +- 2 files changed, 27 insertions(+), 1 deletion(-) create mode 100644 opentracing-api/src/main/java/io/opentracing/tag/IntOrStringTag.java diff --git a/opentracing-api/src/main/java/io/opentracing/tag/IntOrStringTag.java b/opentracing-api/src/main/java/io/opentracing/tag/IntOrStringTag.java new file mode 100644 index 00000000..e173b842 --- /dev/null +++ b/opentracing-api/src/main/java/io/opentracing/tag/IntOrStringTag.java @@ -0,0 +1,26 @@ +/* + * 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.tag; + +import io.opentracing.BaseSpan; + +public class IntOrStringTag extends IntTag { + public IntOrStringTag(String key) { + super(key); + } + + public void set(BaseSpan span, String tagValue) { + span.setTag(super.key, tagValue); + } +} diff --git a/opentracing-api/src/main/java/io/opentracing/tag/Tags.java b/opentracing-api/src/main/java/io/opentracing/tag/Tags.java index 407ba5b8..6e7dfdad 100644 --- a/opentracing-api/src/main/java/io/opentracing/tag/Tags.java +++ b/opentracing-api/src/main/java/io/opentracing/tag/Tags.java @@ -63,7 +63,7 @@ private Tags() { /** * PEER_HOST_IPV4 records IPv4 host address of the peer. */ - public static final IntTag PEER_HOST_IPV4 = new IntTag("peer.ipv4"); + public static final IntOrStringTag PEER_HOST_IPV4 = new IntOrStringTag("peer.ipv4"); /** * PEER_HOST_IPV6 records the IPv6 host address of the peer. From 4ae4656919181255d70fc67e9ddacc12d94a77a2 Mon Sep 17 00:00:00 2001 From: Carlos Alberto Cortez Date: Tue, 26 Sep 2017 01:23:11 +0900 Subject: [PATCH 2/7] Implement a simpler Span propagation without lifetime handling. (#188) - Scope replaces ActiveSpan, without sharing a common ancestor with Span. - ScopeManager replaces ActiveSpanSource. - No reference-count to handle Span's lifetime. - A simple thread-local based ScopeManager. --- .../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 | 57 +++++++ .../src/main/java/io/opentracing/Span.java | 130 ++++++++++++++- .../src/main/java/io/opentracing/Tracer.java | 87 +++++++--- .../java/io/opentracing/tag/AbstractTag.java | 4 +- .../java/io/opentracing/tag/BooleanTag.java | 4 +- .../io/opentracing/tag/IntOrStringTag.java | 4 +- .../main/java/io/opentracing/tag/IntTag.java | 4 +- .../java/io/opentracing/tag/StringTag.java | 6 +- .../io/opentracing/tag/AbstractTagTest.java | 16 +- .../opentracing/examples/AutoFinishScope.java | 66 ++++++++ .../examples/AutoFinishScopeManager.java | 29 ++-- .../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 ++- .../java/io/opentracing/mock/MockTracer.java | 70 ++++---- .../noop/NoopActiveSpanSource.java | 120 -------------- .../io/opentracing/noop/NoopScopeManager.java | 56 +++++++ .../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 | 58 +++++++ .../util/ThreadLocalScopeManager.java | 42 +++++ .../util/ThreadLocalActiveSpanSourceTest.java | 60 ------- .../util/ThreadLocalScopeManagerTest.java | 102 ++++++++++++ ...panTest.java => ThreadLocalScopeTest.java} | 58 ++----- 39 files changed, 785 insertions(+), 901 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 create mode 100644 opentracing-examples/src/test/java/io/opentracing/examples/AutoFinishScope.java rename opentracing-util/src/main/java/io/opentracing/util/ThreadLocalActiveSpanSource.java => opentracing-examples/src/test/java/io/opentracing/examples/AutoFinishScopeManager.java (51%) 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 create mode 100644 opentracing-util/src/main/java/io/opentracing/util/ThreadLocalScopeManager.java delete mode 100644 opentracing-util/src/test/java/io/opentracing/util/ThreadLocalActiveSpanSourceTest.java create mode 100644 opentracing-util/src/test/java/io/opentracing/util/ThreadLocalScopeManagerTest.java 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..bcd6e922 --- /dev/null +++ b/opentracing-api/src/main/java/io/opentracing/ScopeManager.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; + +/** + * 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}. + * Span will automatically be finished when {@link Scope#close()} is called. It is a + * programming error to neglect to call {@link Scope#close()} on the returned instance. + */ + Scope activate(Span span); + + /** + * Make a {@link Span} instance active. + * + * @param span the {@link Span} that should become the {@link #active()} + * @param finishSpanOnClose whether span should automatically be finished when {@link Scope#close()} is called + * @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, boolean finishSpanOnClose); + + /** + * 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..bb3c0d16 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,78 @@ 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
+         *     }
+         *     // Span finishes automatically when the Scope is closed,
+         *     // following the default behavior of ScopeManager.activate(Span)
+         * 
+ * + *

+ * For detailed information, see {@link SpanBuilder#startActive(boolean)} + * + *

+ * Note: {@link SpanBuilder#startActive()} is a shorthand for + * {@code tracer.scopeManager().activate(spanBuilder.startManual())}. + * + * @return a {@link Scope}, already registered via the {@link ScopeManager} + * + * @see ScopeManager + * @see Scope + * @see SpanBuilder#startActive(boolean) + */ + Scope startActive(); + + /** + * Returns a newly started and activated {@link Scope}. + * + *

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


+         *     try (Scope scope = tracer.buildSpan("...").startActive(false)) {
+         *         // (Do work)
+         *         scope.span().setTag( ... );  // etc, etc
+         *     }
+         *     // Span does not finish automatically when the Scope is closed as
+         *     // 'finishOnClose' is false
          * 
* *

* 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())}. + * Note: {@link SpanBuilder#startActive(boolean)} is a shorthand for + * {@code tracer.scopeManager().activate(spanBuilder.startManual(), finishSpanOnClose)}. * - * @return an {@link ActiveSpan}, already registered via the {@link ActiveSpanSource} + * @param finishSpanOnClose whether span should automatically be finished when {@link Scope#close()} is called + * @return a {@link Scope}, already registered via the {@link ScopeManager} * - * @see ActiveSpanSource - * @see ActiveSpan + * @see ScopeManager + * @see Scope */ - ActiveSpan startActive(); + Scope startActive(boolean finishSpanOnClose); /** * 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/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); } } 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-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-util/src/main/java/io/opentracing/util/ThreadLocalActiveSpanSource.java b/opentracing-examples/src/test/java/io/opentracing/examples/AutoFinishScopeManager.java similarity index 51% rename from opentracing-util/src/main/java/io/opentracing/util/ThreadLocalActiveSpanSource.java rename to opentracing-examples/src/test/java/io/opentracing/examples/AutoFinishScopeManager.java index 2cd7e6e2..bfb578bd 100644 --- a/opentracing-util/src/main/java/io/opentracing/util/ThreadLocalActiveSpanSource.java +++ b/opentracing-examples/src/test/java/io/opentracing/examples/AutoFinishScopeManager.java @@ -11,32 +11,29 @@ * or implied. See the License for the specific language governing permissions and limitations under * the License. */ -package io.opentracing.util; +package io.opentracing.examples; -import io.opentracing.ActiveSpan; -import io.opentracing.ActiveSpanSource; +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. - * - * @see ThreadLocalActiveSpan - * @see Tracer#activeSpan() - */ -public class ThreadLocalActiveSpanSource implements ActiveSpanSource { - final ThreadLocal tlsSnapshot = new ThreadLocal(); +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 ThreadLocalActiveSpan activeSpan() { - return tlsSnapshot.get(); + public AutoFinishScope activate(Span span, boolean finishOnClose) { + return new AutoFinishScope(this, new AtomicInteger(1), span); } @Override - public ActiveSpan makeActive(Span span) { - return new ThreadLocalActiveSpan(this, span, new AtomicInteger(1)); + 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"); } } 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/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..3fb63804 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 NoopScopeManager.INSTANCE; + } + @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..45ab6d5f --- /dev/null +++ b/opentracing-util/src/main/java/io/opentracing/util/ThreadLocalScope.java @@ -0,0 +1,58 @@ +/* + * 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/ThreadLocalScopeManager.java b/opentracing-util/src/main/java/io/opentracing/util/ThreadLocalScopeManager.java new file mode 100644 index 00000000..095c4c8f --- /dev/null +++ b/opentracing-util/src/main/java/io/opentracing/util/ThreadLocalScopeManager.java @@ -0,0 +1,42 @@ +/* + * 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; + +/** + * A simple {@link ScopeManager} implementation built on top of Java's thread-local storage primitive. + * + * @see ThreadLocalScope + */ +public class ThreadLocalScopeManager implements ScopeManager { + final ThreadLocal tlsScope = new ThreadLocal(); + + @Override + public Scope activate(Span span) { + return new ThreadLocalScope(this, span, true); + } + + @Override + 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/ThreadLocalActiveSpanSourceTest.java deleted file mode 100644 index 180662ee..00000000 --- a/opentracing-util/src/test/java/io/opentracing/util/ThreadLocalActiveSpanSourceTest.java +++ /dev/null @@ -1,60 +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 io.opentracing.ActiveSpan; -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.verify; - -public class ThreadLocalActiveSpanSourceTest { - private ThreadLocalActiveSpanSource source; - @Before - public void before() throws Exception { - source = new ThreadLocalActiveSpanSource(); - } - - @Test - public void missingActiveSpan() throws Exception { - ActiveSpan missingSpan = source.activeSpan(); - assertNull(missingSpan); - } - - @Test - public void makeActiveSpan() 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); - try { - assertNotNull(activeSpan); - ActiveSpan otherActiveSpan = source.activeSpan(); - assertEquals(otherActiveSpan, activeSpan); - } finally { - activeSpan.close(); - } - - // Make sure the Span got finish()ed. - verify(span).finish(); - - // And now it's gone: - ActiveSpan missingSpan = source.activeSpan(); - assertNull(missingSpan); - } - -} \ No newline at end of file diff --git a/opentracing-util/src/test/java/io/opentracing/util/ThreadLocalScopeManagerTest.java b/opentracing-util/src/test/java/io/opentracing/util/ThreadLocalScopeManagerTest.java new file mode 100644 index 00000000..c5e2fc30 --- /dev/null +++ b/opentracing-util/src/test/java/io/opentracing/util/ThreadLocalScopeManagerTest.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.util; + +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.never; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; + +public class ThreadLocalScopeManagerTest { + private ThreadLocalScopeManager source; + + @Before + public void before() throws Exception { + source = new ThreadLocalScopeManager(); + } + + @Test + public void missingActiveScope() throws Exception { + Scope missingScope = source.active(); + assertNull(missingScope); + } + + @Test + 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. + Scope scope = source.activate(span); + try { + assertNotNull(scope); + Scope otherScope = source.active(); + assertEquals(otherScope, scope); + } finally { + scope.close(); + } + + // Make sure the Span got finish()ed. + verify(span, times(1)).finish(); + + // And now it's gone: + Scope missingScope = source.active(); + assertNull(missingScope); + } + + @Test + public void activateSpanClose() 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. + Scope scope = source.activate(span, true); + try { + assertNotNull(scope); + assertNotNull(source.active()); + } finally { + scope.close(); + } + + // Make sure the Span got finish()ed. + verify(span, times(1)).finish(); + + // Verify it's gone. + assertNull(source.active()); + } + + @Test + public void activateSpanNoClose() 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. + Scope scope = source.activate(span, false); + try { + assertNotNull(scope); + assertNotNull(source.active()); + } finally { + scope.close(); + } + + // Make sure the Span did *not* get finish()ed. + verify(span, never()).finish(); + + // Verify it's gone. + assertNull(source.active()); + } +} 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 0182e63ae9e51b441a75d9d69d1b35ba2d96b709 Mon Sep 17 00:00:00 2001 From: Pavol Loffay Date: Tue, 26 Sep 2017 09:13:37 +0200 Subject: [PATCH 3/7] travis publish.sh allow releases from branches (#191) --- travis/publish.sh | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/travis/publish.sh b/travis/publish.sh index 10701263..584fb8b0 100755 --- a/travis/publish.sh +++ b/travis/publish.sh @@ -35,12 +35,12 @@ is_pull_request() { fi } -is_travis_branch_master() { - if [ "${TRAVIS_BRANCH}" = master ]; then - echo "[Publishing] Travis branch is master" +is_travis_branch_master_or_release() { + if [[ "${TRAVIS_BRANCH}" == "master" || "${TRAVIS_BRANCH}" =~ ^[0-9]+\.[0-9]+\.[0-9]+$ ]]; then + echo "[Publishing] Travis branch is ${TRAVIS_BRANCH}" return 0 else - echo "[Not Publishing] Travis branch is not master" + echo "[Not Publishing] Travis branch is not master or 0.0.0" return 1 fi } @@ -60,12 +60,12 @@ check_travis_branch_equals_travis_tag() { check_release_tag() { tag="${TRAVIS_TAG}" - if [[ "$tag" =~ ^[[:digit:]]+\.[[:digit:]]+\.[[:digit:]]+(\.RC[[:digit:]]+)?$ ]]; then + if [[ "$tag" =~ ^[[:digit:]]+\.[[:digit:]]+\.[[:digit:]]+(\-RC[[:digit:]]+)?$ ]]; then echo "Build started by version tag $tag. During the release process tags like this" echo "are created by the 'release' Maven plugin. Nothing to do here." exit 0 - elif [[ ! "$tag" =~ ^release-[[:digit:]]+\.[[:digit:]]+\.[[:digit:]]+(\.RC[[:digit:]]+)?$ ]]; then - echo "You must specify a tag of the format 'release-0.0.0' or 'release-0.0.0.RC0' to release this project." + elif [[ ! "$tag" =~ ^release-[[:digit:]]+\.[[:digit:]]+\.[[:digit:]]+(\-RC[[:digit:]]+)?$ ]]; then + echo "You must specify a tag of the format 'release-0.0.0' or 'release-0.0.0-RC0' to release this project." echo "The provided tag ${tag} doesn't match that. Aborting." exit 1 fi @@ -73,7 +73,7 @@ check_release_tag() { is_release_commit() { project_version=$(./mvnw help:evaluate -N -Dexpression=project.version|sed -n '/^[0-9]/p') - if [[ "$project_version" =~ ^[[:digit:]]+\.[[:digit:]]+\.[[:digit:]]+(\.RC[[:digit:]]+)?$ ]]; then + if [[ "$project_version" =~ ^[[:digit:]]+\.[[:digit:]]+\.[[:digit:]]+(\-RC[[:digit:]]+)?$ ]]; then echo "Build started by release commit $project_version. Will synchronize to maven central." return 0 else @@ -115,7 +115,7 @@ if is_pull_request; then true # If we are on master, we will deploy the latest snapshot or release version # - If a release commit fails to deploy for a transient reason, delete the broken version from bintray and click rebuild -elif is_travis_branch_master; then +elif is_travis_branch_master_or_release; then ./mvnw --batch-mode -s ./.settings.xml -Prelease -nsu -DskipTests deploy # If the deployment succeeded, sync it to Maven Central. Note: this needs to be done once per project, not module, hence -N From aa4cc0915989019b9c7b2947be1afe1f17cb3882 Mon Sep 17 00:00:00 2001 From: Pavol Loffay Date: Tue, 26 Sep 2017 11:32:07 +0200 Subject: [PATCH 4/7] Travis allow release from non master branches (#192) * Travis allow release from non master branches Publis script compares remote branch with current checkout. This passes travis_branch into git checkout command so it will compare the same branches. * Fix comments --- travis/publish.sh | 23 ++++++++++++----------- 1 file changed, 12 insertions(+), 11 deletions(-) diff --git a/travis/publish.sh b/travis/publish.sh index 584fb8b0..d7968447 100755 --- a/travis/publish.sh +++ b/travis/publish.sh @@ -85,16 +85,17 @@ release_version() { echo "${TRAVIS_TAG}" | sed 's/^release-//' } -safe_checkout_master() { - # We need to be on a branch for release:perform to be able to create commits, and we want that branch to be master. - # But we also want to make sure that we build and release exactly the tagged version, so we verify that the remote - # master is where our tag is. - git checkout -B master - git fetch origin master:origin/master - commit_local_master="$(git show --pretty='format:%H' master)" - commit_remote_master="$(git show --pretty='format:%H' origin/master)" - if [ "$commit_local_master" != "$commit_remote_master" ]; then - echo "Master on remote 'origin' has commits since the version under release, aborting" +safe_checkout_remote_branch() { + # We need to be on a branch for release:perform to be able to create commits, + # and we want that branch to be master or 0.0.0. which has been checked before. + # But we also want to make sure that we build and release exactly the tagged version, + # so we verify that the remote branch is where our tag is. + git checkout -B "${TRAVIS_BRANCH}" + git fetch origin "${TRAVIS_BRANCH}":origin/"${TRAVIS_BRANCH}" + commit_local="$(git show --pretty='format:%H' ${TRAVIS_BRANCH})" + commit_remote="$(git show --pretty='format:%H' origin/${TRAVIS_BRANCH})" + if [ "$commit_local" != "$commit_remote" ]; then + echo "${TRAVIS_BRANCH} on remote 'origin' has commits since the version under release, aborting" exit 1 fi } @@ -125,7 +126,7 @@ elif is_travis_branch_master_or_release; then # If we are on a release tag, the following will update any version references and push a version tag for deployment. elif build_started_by_tag; then - safe_checkout_master + safe_checkout_remote_branch ./mvnw --batch-mode -s ./.settings.xml -Prelease -nsu -DreleaseVersion="$(release_version)" -Darguments="-DskipTests" release:prepare fi From 10d3c2133258c9bf1d5bfa4ee8a74852ec24ac2b Mon Sep 17 00:00:00 2001 From: Pavol Loffay Date: Tue, 26 Sep 2017 14:47:22 +0200 Subject: [PATCH 5/7] Travis publish script, remove -RC on git checkout (#193) --- travis/publish.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/travis/publish.sh b/travis/publish.sh index d7968447..23366a01 100755 --- a/travis/publish.sh +++ b/travis/publish.sh @@ -90,7 +90,7 @@ safe_checkout_remote_branch() { # and we want that branch to be master or 0.0.0. which has been checked before. # But we also want to make sure that we build and release exactly the tagged version, # so we verify that the remote branch is where our tag is. - git checkout -B "${TRAVIS_BRANCH}" + git checkout -B `release_version | sed 's/-RC[[:digit:]]\+//'` git fetch origin "${TRAVIS_BRANCH}":origin/"${TRAVIS_BRANCH}" commit_local="$(git show --pretty='format:%H' ${TRAVIS_BRANCH})" commit_remote="$(git show --pretty='format:%H' origin/${TRAVIS_BRANCH})" From 27327e91ba30b2280ed86afe9f65583c5c3db95f Mon Sep 17 00:00:00 2001 From: Carlos Alberto Cortez Date: Thu, 28 Sep 2017 22:48:48 +0900 Subject: [PATCH 6/7] Update the Travis script to allow publishing from v.0.0.0 branches. (#195) Thing is, we cannot publish from 0.0.0-style branches as they are excluded, based on the current global Travis configuration, thus we try to publish from branches following a v.0.0.0 style, if any. --- travis/publish.sh | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/travis/publish.sh b/travis/publish.sh index 23366a01..6837e433 100755 --- a/travis/publish.sh +++ b/travis/publish.sh @@ -36,11 +36,11 @@ is_pull_request() { } is_travis_branch_master_or_release() { - if [[ "${TRAVIS_BRANCH}" == "master" || "${TRAVIS_BRANCH}" =~ ^[0-9]+\.[0-9]+\.[0-9]+$ ]]; then + if [[ "${TRAVIS_BRANCH}" == "master" || "${TRAVIS_BRANCH}" =~ ^v[0-9]+\.[0-9]+\.[0-9]+$ ]]; then echo "[Publishing] Travis branch is ${TRAVIS_BRANCH}" return 0 else - echo "[Not Publishing] Travis branch is not master or 0.0.0" + echo "[Not Publishing] Travis branch is not master or v0.0.0" return 1 fi } @@ -87,10 +87,10 @@ release_version() { safe_checkout_remote_branch() { # We need to be on a branch for release:perform to be able to create commits, - # and we want that branch to be master or 0.0.0. which has been checked before. + # and we want that branch to be master or v0.0.0. which has been checked before. # But we also want to make sure that we build and release exactly the tagged version, # so we verify that the remote branch is where our tag is. - git checkout -B `release_version | sed 's/-RC[[:digit:]]\+//'` + git checkout -B v`release_version | sed 's/-RC[[:digit:]]\+//'` git fetch origin "${TRAVIS_BRANCH}":origin/"${TRAVIS_BRANCH}" commit_local="$(git show --pretty='format:%H' ${TRAVIS_BRANCH})" commit_remote="$(git show --pretty='format:%H' origin/${TRAVIS_BRANCH})" From c0c4669536ae12aa7367b6817135d331b2378761 Mon Sep 17 00:00:00 2001 From: Carlos Alberto Cortez Date: Sat, 30 Sep 2017 01:45:06 +0900 Subject: [PATCH 7/7] Update async tests to use the new Scope API. * actor_propagation * promise_propagation * suspend_resume_propagation --- .../examples/actor_propagation/Actor.java | 19 ++++++++------- .../ActorPropagationTest.java | 18 +++++++------- .../examples/promise_propagation/Promise.java | 24 ++++++++++--------- .../PromisePropagationTest.java | 8 +++---- .../SuspendResume.java | 18 +++++++------- .../SuspendResumePropagationTest.java | 4 ++-- 6 files changed, 47 insertions(+), 44 deletions(-) diff --git a/opentracing-examples/src/test/java/io/opentracing/examples/actor_propagation/Actor.java b/opentracing-examples/src/test/java/io/opentracing/examples/actor_propagation/Actor.java index e1b03d1b..2246d147 100644 --- a/opentracing-examples/src/test/java/io/opentracing/examples/actor_propagation/Actor.java +++ b/opentracing-examples/src/test/java/io/opentracing/examples/actor_propagation/Actor.java @@ -13,7 +13,8 @@ */ package io.opentracing.examples.actor_propagation; -import io.opentracing.ActiveSpan; +import io.opentracing.Scope; +import io.opentracing.Span; import io.opentracing.mock.MockTracer; import io.opentracing.tag.Tags; import java.util.concurrent.Callable; @@ -42,21 +43,21 @@ public void close() { } public void tell(final String message) { - final ActiveSpan.Continuation continuation = tracer.activeSpan().capture(); + 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("received") - .asChildOf(parent) + .asChildOf(parent.span()) .withTag(Tags.SPAN_KIND.getKey(), Tags.SPAN_KIND_CONSUMER) .startActive()) { phaser.arriveAndAwaitAdvance(); // child tracer started - child.log("received " + message); + child.span().log("received " + message); phaser.arriveAndAwaitAdvance(); // assert size } phaser.arriveAndAwaitAdvance(); // child tracer finished @@ -69,15 +70,15 @@ public void run() { } public Future ask(final String message) { - final ActiveSpan.Continuation continuation = tracer.activeSpan().capture(); + 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("received") .withTag(Tags.SPAN_KIND.getKey(), Tags.SPAN_KIND_CONSUMER) diff --git a/opentracing-examples/src/test/java/io/opentracing/examples/actor_propagation/ActorPropagationTest.java b/opentracing-examples/src/test/java/io/opentracing/examples/actor_propagation/ActorPropagationTest.java index 91f87056..fc7a9a4b 100644 --- a/opentracing-examples/src/test/java/io/opentracing/examples/actor_propagation/ActorPropagationTest.java +++ b/opentracing-examples/src/test/java/io/opentracing/examples/actor_propagation/ActorPropagationTest.java @@ -13,12 +13,12 @@ */ package io.opentracing.examples.actor_propagation; -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; @@ -42,7 +42,7 @@ public class ActorPropagationTest { private final MockTracer tracer = - new MockTracer(new ThreadLocalActiveSpanSource(), Propagator.TEXT_MAP); + new MockTracer(new ThreadLocalScopeManager(), Propagator.TEXT_MAP); private Phaser phaser; @Before @@ -54,12 +54,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 @@ -81,7 +81,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(); } } @@ -90,12 +90,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 @@ -119,7 +119,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(); } } } diff --git a/opentracing-examples/src/test/java/io/opentracing/examples/promise_propagation/Promise.java b/opentracing-examples/src/test/java/io/opentracing/examples/promise_propagation/Promise.java index b55faf4c..ecfc243b 100644 --- a/opentracing-examples/src/test/java/io/opentracing/examples/promise_propagation/Promise.java +++ b/opentracing-examples/src/test/java/io/opentracing/examples/promise_propagation/Promise.java @@ -13,7 +13,9 @@ */ package io.opentracing.examples.promise_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; import java.util.Collection; @@ -23,7 +25,7 @@ public class Promise { private final PromiseContext context; private final MockTracer tracer; - private final ActiveSpan activeSpan; + private final AutoFinishScope activeScope; private final Collection>> successCallbacks = new LinkedList<>(); private final Collection> errorCallbacks = new LinkedList<>(); @@ -33,16 +35,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(); + activeScope = (AutoFinishScope)tracer.scopeManager().active(); } public void onSuccess(SuccessCallback successCallback) { - ActiveSpan.Continuation capture = activeSpan.capture(); + Continuation capture = activeScope.capture(); successCallbacks.add(new Pair<>(capture, successCallback)); } public void onError(ErrorCallback errorCallback) { - ActiveSpan.Continuation capture = activeSpan.capture(); + Continuation capture = activeScope.capture(); errorCallbacks.add(new Pair<>(capture, errorCallback)); } @@ -52,8 +54,8 @@ 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") @@ -73,8 +75,8 @@ 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") @@ -100,10 +102,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/promise_propagation/PromisePropagationTest.java b/opentracing-examples/src/test/java/io/opentracing/examples/promise_propagation/PromisePropagationTest.java index 49e7d8e0..669c6785 100644 --- a/opentracing-examples/src/test/java/io/opentracing/examples/promise_propagation/PromisePropagationTest.java +++ b/opentracing-examples/src/test/java/io/opentracing/examples/promise_propagation/PromisePropagationTest.java @@ -13,12 +13,12 @@ */ package io.opentracing.examples.promise_propagation; -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.tag.Tags; -import io.opentracing.util.ThreadLocalActiveSpanSource; import org.junit.Before; import org.junit.Test; @@ -41,7 +41,7 @@ public class PromisePropagationTest { private final MockTracer tracer = - new MockTracer(new ThreadLocalActiveSpanSource(), Propagator.TEXT_MAP); + new MockTracer(new AutoFinishScopeManager(), Propagator.TEXT_MAP); private Phaser phaser; @Before @@ -55,7 +55,7 @@ public void testPromiseCallback() { final AtomicReference successResult = new AtomicReference<>(); final AtomicReference errorResult = new AtomicReference<>(); try (PromiseContext context = new PromiseContext(phaser, 2)) { - try (ActiveSpan parent = + try (Scope parent = tracer .buildSpan("promises") .withTag(Tags.COMPONENT.getKey(), "example-promises") diff --git a/opentracing-examples/src/test/java/io/opentracing/examples/suspend_resume_propagation/SuspendResume.java b/opentracing-examples/src/test/java/io/opentracing/examples/suspend_resume_propagation/SuspendResume.java index 50dcfadb..e799d5d6 100644 --- a/opentracing-examples/src/test/java/io/opentracing/examples/suspend_resume_propagation/SuspendResume.java +++ b/opentracing-examples/src/test/java/io/opentracing/examples/suspend_resume_propagation/SuspendResume.java @@ -13,7 +13,8 @@ */ package io.opentracing.examples.suspend_resume_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(); } } diff --git a/opentracing-examples/src/test/java/io/opentracing/examples/suspend_resume_propagation/SuspendResumePropagationTest.java b/opentracing-examples/src/test/java/io/opentracing/examples/suspend_resume_propagation/SuspendResumePropagationTest.java index 2e07bbd9..727f0c3c 100644 --- a/opentracing-examples/src/test/java/io/opentracing/examples/suspend_resume_propagation/SuspendResumePropagationTest.java +++ b/opentracing-examples/src/test/java/io/opentracing/examples/suspend_resume_propagation/SuspendResumePropagationTest.java @@ -16,7 +16,7 @@ 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.Before; import org.junit.Test; @@ -37,7 +37,7 @@ public class SuspendResumePropagationTest { private final MockTracer tracer = - new MockTracer(new ThreadLocalActiveSpanSource(), Propagator.TEXT_MAP); + new MockTracer(new ThreadLocalScopeManager(), Propagator.TEXT_MAP); private Phaser phaser; @Before