diff --git a/README.md b/README.md index 824962fc..d3f22d62 100644 --- a/README.md +++ b/README.md @@ -35,9 +35,9 @@ Access to the active span is straightforward: ```java io.opentracing.Tracer tracer = ...; ... -Scope scope = tracer.scopeManager().active(); -if (scope != null) { - scope.span().log("..."); +Span span = tracer.scopeManager().activeSpan(); +if (span != null) { + span.log("..."); } ``` diff --git a/opentracing-api/src/main/java/io/opentracing/ScopeManager.java b/opentracing-api/src/main/java/io/opentracing/ScopeManager.java index 64676bc0..90e7ff7e 100644 --- a/opentracing-api/src/main/java/io/opentracing/ScopeManager.java +++ b/opentracing-api/src/main/java/io/opentracing/ScopeManager.java @@ -17,8 +17,8 @@ /** * The {@link ScopeManager} interface abstracts both the activation of {@link Span} instances via - * {@link ScopeManager#activate(Span, boolean)} and access to an active {@link Span}/{@link Scope} - * via {@link ScopeManager#active()}. + * {@link ScopeManager#activate(Span)} and access to an active {@link Span} + * via {@link ScopeManager#activeSpan()}. * * @see Scope * @see Tracer#scopeManager() @@ -37,10 +37,7 @@ public interface ScopeManager { * is called. * *

- * This {@link Scope} instance can be accessed at any time through {@link #active()}, - * in case it is not possible for the user to store it (when used through middleware - * or start/finish event hooks, for example). The corresponding {@link Span} can be - * accessed through {@link #activeSpan()} likewise. + * The corresponding {@link Span} can be accessed at any time through {@link #activeSpan()}. * *

* Usage: @@ -65,6 +62,7 @@ public interface ScopeManager { Scope activate(Span span); /** + * @deprecated use {@link #activeSpan()} instead. * Return the currently active {@link Scope} which can be used to deactivate the currently active * {@link Span}. * @@ -78,6 +76,7 @@ public interface ScopeManager { * * @return the {@link Scope active scope}, or null if none could be found. */ + @Deprecated Scope active(); /** diff --git a/opentracing-api/src/main/java/io/opentracing/Tracer.java b/opentracing-api/src/main/java/io/opentracing/Tracer.java index 966dc02c..eedca044 100644 --- a/opentracing-api/src/main/java/io/opentracing/Tracer.java +++ b/opentracing-api/src/main/java/io/opentracing/Tracer.java @@ -143,12 +143,12 @@ interface SpanBuilder { *

* If *

* ... then an inferred {@link References#CHILD_OF} reference is created to the - * {@link ScopeManager#active()} {@link SpanContext} when either {@link SpanBuilder#startActive(boolean)} or + * {@link ScopeManager#activeSpan()} {@link SpanContext} when either {@link SpanBuilder#startActive(boolean)} or * {@link SpanBuilder#start} is invoked. * * @param referenceType the reference type, typically one of the constants defined in References @@ -161,7 +161,7 @@ interface SpanBuilder { SpanBuilder addReference(String referenceType, SpanContext referencedContext); /** - * Do not create an implicit {@link References#CHILD_OF} reference to the {@link ScopeManager#active()}). + * Do not create an implicit {@link References#CHILD_OF} reference to the {@link ScopeManager#activeSpan()}). */ SpanBuilder ignoreActiveSpan(); 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 d8d17c8d..4ce9cfe5 100644 --- a/opentracing-mock/src/main/java/io/opentracing/mock/MockTracer.java +++ b/opentracing-mock/src/main/java/io/opentracing/mock/MockTracer.java @@ -272,8 +272,7 @@ public SpanContext extract(Format format, C carrier) { @Override public Span activeSpan() { - Scope scope = this.scopeManager.active(); - return scope == null ? null : scope.span(); + return this.scopeManager.activeSpan(); } @Override diff --git a/opentracing-testbed/README.md b/opentracing-testbed/README.md index 9ebfdbc7..62f36c18 100644 --- a/opentracing-testbed/README.md +++ b/opentracing-testbed/README.md @@ -12,7 +12,7 @@ It shows continuation as a solution to finish span when last action is completed - [active_span_replacement](src/test/java/io/opentracing/testbed/active_span_replacement) - start an isolated task and query for its result in another task/thread - [actor_propagation](src/test/java/io/opentracing/testbed/actor_propagation) - tracing for blocking and non-blocking actor based tracing - [client_server](src/test/java/io/opentracing/testbed/client_server) - typical client-server example -- [common_request_handler](src/test/java/io/opentracing/testbed/common_request_handler) - one request handler for all requests +- [concurrent_common_request_handler](src/test/java/io/opentracing/testbed/concurrent_common_request_handler) - one request handler for concurrent requests - [error_reporting](src/test/java/io/opentracing/testbed/error_reporting) - a few common cases of error reporting - [late_span_finish](src/test/java/io/opentracing/testbed/late_span_finish) - late parent span finish - [listener_per_request](src/test/java/io/opentracing/testbed/listener_per_request) - one listener per request @@ -20,3 +20,4 @@ It shows continuation as a solution to finish span when last action is completed - [nested_callbacks](src/test/java/io/opentracing/testbed/nested_callbacks) - one callback at the time, defined in a pipeline fashion - [promise_propagation](src/test/java/io/opentracing/testbed/promise_propagation) - tracing patterns for promises with callbacks - [suspend_resume_propagation](src/test/java/io/opentracing/testbed/suspend_resume_propagation) - tracing pattern for interleaving of spans +- [stateless_common_request_handler](src/test/java/io/opentracing/testbed/stateless_common_request_handler) - one stateless request handler for requests diff --git a/opentracing-testbed/src/test/java/io/opentracing/testbed/active_span_replacement/ActiveSpanReplacementTest.java b/opentracing-testbed/src/test/java/io/opentracing/testbed/active_span_replacement/ActiveSpanReplacementTest.java index 74e0ef63..2976da75 100644 --- a/opentracing-testbed/src/test/java/io/opentracing/testbed/active_span_replacement/ActiveSpanReplacementTest.java +++ b/opentracing-testbed/src/test/java/io/opentracing/testbed/active_span_replacement/ActiveSpanReplacementTest.java @@ -66,7 +66,7 @@ public void test() throws Exception { assertNotEquals(spans.get(0).context().traceId(), spans.get(1).context().traceId()); assertEquals(0, spans.get(0).parentId()); - assertNull(tracer.scopeManager().active()); + assertNull(tracer.scopeManager().activeSpan()); } private void submitAnotherTask(final Span initialSpan) { diff --git a/opentracing-testbed/src/test/java/io/opentracing/testbed/actor_propagation/ActorPropagationTest.java b/opentracing-testbed/src/test/java/io/opentracing/testbed/actor_propagation/ActorPropagationTest.java index 4aee337d..c40c31b7 100644 --- a/opentracing-testbed/src/test/java/io/opentracing/testbed/actor_propagation/ActorPropagationTest.java +++ b/opentracing-testbed/src/test/java/io/opentracing/testbed/actor_propagation/ActorPropagationTest.java @@ -84,7 +84,7 @@ public void testActorTell() { .isEqualTo(finished.get(1).context().traceId()); assertThat(getByTag(finished, Tags.SPAN_KIND, Tags.SPAN_KIND_CONSUMER)).hasSize(2); assertThat(getOneByTag(finished, Tags.SPAN_KIND, Tags.SPAN_KIND_PRODUCER)).isNotNull(); - assertThat(tracer.scopeManager().active()).isNull(); + assertThat(tracer.scopeManager().activeSpan()).isNull(); } } @@ -126,7 +126,7 @@ public void testActorAsk() throws ExecutionException, InterruptedException { .isEqualTo(finished.get(1).context().traceId()); assertThat(getByTag(finished, Tags.SPAN_KIND, Tags.SPAN_KIND_CONSUMER)).hasSize(2); assertThat(getOneByTag(finished, Tags.SPAN_KIND, Tags.SPAN_KIND_PRODUCER)).isNotNull(); - assertThat(tracer.scopeManager().active()).isNull(); + assertThat(tracer.scopeManager().activeSpan()).isNull(); } } } diff --git a/opentracing-testbed/src/test/java/io/opentracing/testbed/client_server/TestClientServerTest.java b/opentracing-testbed/src/test/java/io/opentracing/testbed/client_server/TestClientServerTest.java index 266f9751..56aaccec 100644 --- a/opentracing-testbed/src/test/java/io/opentracing/testbed/client_server/TestClientServerTest.java +++ b/opentracing-testbed/src/test/java/io/opentracing/testbed/client_server/TestClientServerTest.java @@ -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.scopeManager().active()); + assertNull(tracer.scopeManager().activeSpan()); } } diff --git a/opentracing-testbed/src/test/java/io/opentracing/testbed/common_request_handler/Client.java b/opentracing-testbed/src/test/java/io/opentracing/testbed/concurrent_common_request_handler/Client.java similarity index 97% rename from opentracing-testbed/src/test/java/io/opentracing/testbed/common_request_handler/Client.java rename to opentracing-testbed/src/test/java/io/opentracing/testbed/concurrent_common_request_handler/Client.java index 60004dff..076b7ea9 100644 --- a/opentracing-testbed/src/test/java/io/opentracing/testbed/common_request_handler/Client.java +++ b/opentracing-testbed/src/test/java/io/opentracing/testbed/concurrent_common_request_handler/Client.java @@ -11,7 +11,7 @@ * or implied. See the License for the specific language governing permissions and limitations under * the License. */ -package io.opentracing.testbed.common_request_handler; +package io.opentracing.testbed.concurrent_common_request_handler; import io.opentracing.testbed.TestUtils; import org.slf4j.Logger; diff --git a/opentracing-testbed/src/test/java/io/opentracing/testbed/common_request_handler/Context.java b/opentracing-testbed/src/test/java/io/opentracing/testbed/concurrent_common_request_handler/Context.java similarity index 91% rename from opentracing-testbed/src/test/java/io/opentracing/testbed/common_request_handler/Context.java rename to opentracing-testbed/src/test/java/io/opentracing/testbed/concurrent_common_request_handler/Context.java index 75ad49db..52fc1b93 100644 --- a/opentracing-testbed/src/test/java/io/opentracing/testbed/common_request_handler/Context.java +++ b/opentracing-testbed/src/test/java/io/opentracing/testbed/concurrent_common_request_handler/Context.java @@ -11,7 +11,7 @@ * or implied. See the License for the specific language governing permissions and limitations under * the License. */ -package io.opentracing.testbed.common_request_handler; +package io.opentracing.testbed.concurrent_common_request_handler; import java.util.HashMap; diff --git a/opentracing-testbed/src/test/java/io/opentracing/testbed/common_request_handler/HandlerTest.java b/opentracing-testbed/src/test/java/io/opentracing/testbed/concurrent_common_request_handler/HandlerTest.java similarity index 97% rename from opentracing-testbed/src/test/java/io/opentracing/testbed/common_request_handler/HandlerTest.java rename to opentracing-testbed/src/test/java/io/opentracing/testbed/concurrent_common_request_handler/HandlerTest.java index ae8f939a..eadf9b83 100644 --- a/opentracing-testbed/src/test/java/io/opentracing/testbed/common_request_handler/HandlerTest.java +++ b/opentracing-testbed/src/test/java/io/opentracing/testbed/concurrent_common_request_handler/HandlerTest.java @@ -11,7 +11,7 @@ * or implied. See the License for the specific language governing permissions and limitations under * the License. */ -package io.opentracing.testbed.common_request_handler; +package io.opentracing.testbed.concurrent_common_request_handler; import io.opentracing.Scope; import io.opentracing.Span; @@ -68,7 +68,7 @@ public void two_requests() throws Exception { assertEquals(0, finished.get(0).parentId()); assertEquals(0, finished.get(1).parentId()); - assertNull(tracer.scopeManager().active()); + assertNull(tracer.scopeManager().activeSpan()); } /** diff --git a/opentracing-testbed/src/test/java/io/opentracing/testbed/common_request_handler/README.md b/opentracing-testbed/src/test/java/io/opentracing/testbed/concurrent_common_request_handler/README.md similarity index 83% rename from opentracing-testbed/src/test/java/io/opentracing/testbed/common_request_handler/README.md rename to opentracing-testbed/src/test/java/io/opentracing/testbed/concurrent_common_request_handler/README.md index 001daa2c..2c50489f 100644 --- a/opentracing-testbed/src/test/java/io/opentracing/testbed/common_request_handler/README.md +++ b/opentracing-testbed/src/test/java/io/opentracing/testbed/concurrent_common_request_handler/README.md @@ -1,6 +1,6 @@ -# Common Request Handler example. +# Concurrent common Request Handler example. -This example shows a `Span` used with `RequestHandler`, which is used as a middleware (as in web frameworks) to manage a new `Span` per operation through its `beforeRequest()`/`afterResponse()` methods. +This example shows a `Span` used with `RequestHandler`, which is used as a middleware (as in web frameworks) to concurrently manage a new `Span` per operation through its `beforeRequest()`/`afterResponse()` methods. Since its methods are not guaranteed to be run in the same thread, activation of such `Span`s is not done. diff --git a/opentracing-testbed/src/test/java/io/opentracing/testbed/common_request_handler/RequestHandler.java b/opentracing-testbed/src/test/java/io/opentracing/testbed/concurrent_common_request_handler/RequestHandler.java similarity index 97% rename from opentracing-testbed/src/test/java/io/opentracing/testbed/common_request_handler/RequestHandler.java rename to opentracing-testbed/src/test/java/io/opentracing/testbed/concurrent_common_request_handler/RequestHandler.java index cdde25ff..b53205cb 100644 --- a/opentracing-testbed/src/test/java/io/opentracing/testbed/common_request_handler/RequestHandler.java +++ b/opentracing-testbed/src/test/java/io/opentracing/testbed/concurrent_common_request_handler/RequestHandler.java @@ -11,7 +11,7 @@ * or implied. See the License for the specific language governing permissions and limitations under * the License. */ -package io.opentracing.testbed.common_request_handler; +package io.opentracing.testbed.concurrent_common_request_handler; import io.opentracing.Span; import io.opentracing.SpanContext; diff --git a/opentracing-testbed/src/test/java/io/opentracing/testbed/error_reporting/ErrorReportingTest.java b/opentracing-testbed/src/test/java/io/opentracing/testbed/error_reporting/ErrorReportingTest.java index 2bb6b622..2679697c 100644 --- a/opentracing-testbed/src/test/java/io/opentracing/testbed/error_reporting/ErrorReportingTest.java +++ b/opentracing-testbed/src/test/java/io/opentracing/testbed/error_reporting/ErrorReportingTest.java @@ -52,7 +52,6 @@ public void testSimpleError() { span.finish(); } - assertNull(tracer.scopeManager().active()); assertNull(tracer.scopeManager().activeSpan()); List spans = tracer.finishedSpans(); @@ -112,7 +111,6 @@ public void testErrorRecovery() { } span.finish(); - assertNull(tracer.scopeManager().active()); assertNull(tracer.scopeManager().activeSpan()); List spans = tracer.finishedSpans(); diff --git a/opentracing-testbed/src/test/java/io/opentracing/testbed/late_span_finish/LateSpanFinishTest.java b/opentracing-testbed/src/test/java/io/opentracing/testbed/late_span_finish/LateSpanFinishTest.java index 812466b6..12dd2828 100644 --- a/opentracing-testbed/src/test/java/io/opentracing/testbed/late_span_finish/LateSpanFinishTest.java +++ b/opentracing-testbed/src/test/java/io/opentracing/testbed/late_span_finish/LateSpanFinishTest.java @@ -58,7 +58,7 @@ public void test() throws Exception { assertSameTrace(spans); - assertNull(tracer.scopeManager().active()); + assertNull(tracer.scopeManager().activeSpan()); } diff --git a/opentracing-testbed/src/test/java/io/opentracing/testbed/listener_per_request/ListenerTest.java b/opentracing-testbed/src/test/java/io/opentracing/testbed/listener_per_request/ListenerTest.java index 455f84ee..6cd14c0c 100644 --- a/opentracing-testbed/src/test/java/io/opentracing/testbed/listener_per_request/ListenerTest.java +++ b/opentracing-testbed/src/test/java/io/opentracing/testbed/listener_per_request/ListenerTest.java @@ -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.scopeManager().active()); + assertNull(tracer.scopeManager().activeSpan()); } } diff --git a/opentracing-testbed/src/test/java/io/opentracing/testbed/multiple_callbacks/Client.java b/opentracing-testbed/src/test/java/io/opentracing/testbed/multiple_callbacks/Client.java index 0c50f4e0..a36718ec 100644 --- a/opentracing-testbed/src/test/java/io/opentracing/testbed/multiple_callbacks/Client.java +++ b/opentracing-testbed/src/test/java/io/opentracing/testbed/multiple_callbacks/Client.java @@ -18,6 +18,7 @@ import io.opentracing.Tracer; import io.opentracing.util.AutoFinishScope; import io.opentracing.util.AutoFinishScope.Continuation; +import io.opentracing.util.AutoFinishScopeManager; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -40,8 +41,7 @@ public Client(Tracer tracer) { } public Future send(final Object message, final long milliseconds) { - Scope scope = tracer.scopeManager().active(); - final Continuation cont = ((AutoFinishScope)scope).capture(); + final Continuation cont = ((AutoFinishScopeManager)tracer.scopeManager()).captureScope(); return executor.submit(new Callable() { @Override diff --git a/opentracing-testbed/src/test/java/io/opentracing/testbed/multiple_callbacks/MultipleCallbacksTest.java b/opentracing-testbed/src/test/java/io/opentracing/testbed/multiple_callbacks/MultipleCallbacksTest.java index dfd5f32b..da516595 100644 --- a/opentracing-testbed/src/test/java/io/opentracing/testbed/multiple_callbacks/MultipleCallbacksTest.java +++ b/opentracing-testbed/src/test/java/io/opentracing/testbed/multiple_callbacks/MultipleCallbacksTest.java @@ -58,6 +58,6 @@ public void test() throws Exception { assertEquals(parentSpan.context().spanId(), spans.get(i).parentId()); } - assertNull(tracer.scopeManager().active()); + assertNull(tracer.scopeManager().activeSpan()); } } diff --git a/opentracing-testbed/src/test/java/io/opentracing/testbed/multiple_callbacks/README.md b/opentracing-testbed/src/test/java/io/opentracing/testbed/multiple_callbacks/README.md index fe1d411f..d45887e5 100644 --- a/opentracing-testbed/src/test/java/io/opentracing/testbed/multiple_callbacks/README.md +++ b/opentracing-testbed/src/test/java/io/opentracing/testbed/multiple_callbacks/README.md @@ -6,8 +6,7 @@ This example shows a `Span` created for a top-level operation, covering a set of ```java // Client.send() -Scope scope = tracer.scopeManager().active(); -final Continuation cont = ((AutoFinishScope)scope).capture(); +final Continuation cont = ((AutoFinishScopeManager)tracer.scopeManager()).captureScope(); return executor.submit(new Callable() { @Override diff --git a/opentracing-testbed/src/test/java/io/opentracing/testbed/nested_callbacks/NestedCallbacksTest.java b/opentracing-testbed/src/test/java/io/opentracing/testbed/nested_callbacks/NestedCallbacksTest.java index e3c3bd27..c8e803be 100644 --- a/opentracing-testbed/src/test/java/io/opentracing/testbed/nested_callbacks/NestedCallbacksTest.java +++ b/opentracing-testbed/src/test/java/io/opentracing/testbed/nested_callbacks/NestedCallbacksTest.java @@ -57,7 +57,7 @@ public void test() throws Exception { assertEquals(Integer.toString(i), tags.get("key" + i)); } - assertNull(tracer.scopeManager().active()); + assertNull(tracer.scopeManager().activeSpan()); } private void submitCallbacks(final Span span) { diff --git a/opentracing-testbed/src/test/java/io/opentracing/testbed/stateless_common_request_handler/Client.java b/opentracing-testbed/src/test/java/io/opentracing/testbed/stateless_common_request_handler/Client.java new file mode 100644 index 00000000..ee1b4578 --- /dev/null +++ b/opentracing-testbed/src/test/java/io/opentracing/testbed/stateless_common_request_handler/Client.java @@ -0,0 +1,54 @@ +/* + * Copyright 2016-2019 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.testbed.stateless_common_request_handler; + +import io.opentracing.testbed.TestUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.concurrent.Callable; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.Future; + +public class Client { + + private static final Logger logger = LoggerFactory.getLogger(Client.class); + + private final ExecutorService executor = Executors.newCachedThreadPool(); + + private final RequestHandler requestHandler; + + public Client(RequestHandler requestHandler) { + this.requestHandler = requestHandler; + } + + public Future send(final Object message) { + + return executor.submit(new Callable() { + @Override + public String call() throws Exception { + logger.info("send {}", message); + TestUtils.sleep(); + requestHandler.beforeRequest(message); + + TestUtils.sleep(); + requestHandler.afterResponse(message); + + return message + ":response"; + } + }); + + } +} diff --git a/opentracing-testbed/src/test/java/io/opentracing/testbed/stateless_common_request_handler/HandlerTest.java b/opentracing-testbed/src/test/java/io/opentracing/testbed/stateless_common_request_handler/HandlerTest.java new file mode 100644 index 00000000..d2a6c451 --- /dev/null +++ b/opentracing-testbed/src/test/java/io/opentracing/testbed/stateless_common_request_handler/HandlerTest.java @@ -0,0 +1,57 @@ +/* + * Copyright 2016-2019 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.testbed.stateless_common_request_handler; + +import io.opentracing.mock.MockSpan; +import io.opentracing.mock.MockTracer; +import io.opentracing.mock.MockTracer.Propagator; +import io.opentracing.util.ThreadLocalScopeManager; +import org.junit.Before; +import org.junit.Test; + +import java.util.List; +import java.util.concurrent.Future; +import java.util.concurrent.TimeUnit; + +import static org.junit.Assert.assertEquals; + +/** + * There is only one instance of 'RequestHandler' per 'Client'. Methods of 'RequestHandler' are + * executed in the same thread (beforeRequest() and its resulting afterRequest(), that is). + */ +public class HandlerTest { + + private final MockTracer tracer = new MockTracer(new ThreadLocalScopeManager(), + Propagator.TEXT_MAP); + private final Client client = new Client(new RequestHandler(tracer)); + + @Before + public void before() { + tracer.reset(); + } + + @Test + public void test_requests() throws Exception { + Future responseFuture = client.send("message"); + Future responseFuture2 = client.send("message2"); + Future responseFuture3 = client.send("message3"); + + assertEquals("message3:response", responseFuture3.get(5, TimeUnit.SECONDS)); + assertEquals("message2:response", responseFuture2.get(5, TimeUnit.SECONDS)); + assertEquals("message:response", responseFuture.get(5, TimeUnit.SECONDS)); + + List finished = tracer.finishedSpans(); + assertEquals(3, finished.size()); + } +} \ No newline at end of file diff --git a/opentracing-testbed/src/test/java/io/opentracing/testbed/stateless_common_request_handler/README.md b/opentracing-testbed/src/test/java/io/opentracing/testbed/stateless_common_request_handler/README.md new file mode 100644 index 00000000..a989241f --- /dev/null +++ b/opentracing-testbed/src/test/java/io/opentracing/testbed/stateless_common_request_handler/README.md @@ -0,0 +1,22 @@ +# Stateless common Request Handler example. + +This example shows a `Span` used with `RequestHandler`, which is used as common, *stateless* middleware (as in web frameworks) to manage a new `Span` per operation through its `beforeRequest()`/`afterResponse()` methods. As these methods do not expose any object storing state, a thread-local field in `RequestHandler` itself is used to contain the `Scope` related to `Span` activation. + +```java + public void beforeRequest(Object request) { + logger.info("before send {}", request); + + Span span = tracer.buildSpan(OPERATION_NAME).start(); + tlsScope.set(tracer.activateSpan(span)); + } + + public void afterResponse(Object response) { + logger.info("after response {}", response); + + // Finish the Span + tracer.scopeManager().activeSpan().finish(); + + // Deactivate the Span + tlsScope.get().close(); + } +``` diff --git a/opentracing-testbed/src/test/java/io/opentracing/testbed/stateless_common_request_handler/RequestHandler.java b/opentracing-testbed/src/test/java/io/opentracing/testbed/stateless_common_request_handler/RequestHandler.java new file mode 100644 index 00000000..e4046e77 --- /dev/null +++ b/opentracing-testbed/src/test/java/io/opentracing/testbed/stateless_common_request_handler/RequestHandler.java @@ -0,0 +1,59 @@ +/* + * Copyright 2016-2019 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.testbed.stateless_common_request_handler; + +import io.opentracing.Scope; +import io.opentracing.Span; +import io.opentracing.Tracer; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * One instance per Client. 'beforeRequest' and 'afterResponse' + * are executed in the same thread for one 'send', + * but as these methods do not expose any object storing state, + * a thread-local field in 'RequestHandler' itself is used + * to contain the Scope related to Span activation. + */ +public class RequestHandler { + + private static final Logger logger = LoggerFactory.getLogger(RequestHandler.class); + + static final String OPERATION_NAME = "send"; + + private final Tracer tracer; + + private final ThreadLocal tlsScope = new ThreadLocal(); + + public RequestHandler(Tracer tracer) { + this.tracer = tracer; + } + + public void beforeRequest(Object request) { + logger.info("before send {}", request); + + Span span = tracer.buildSpan(OPERATION_NAME).start(); + tlsScope.set(tracer.activateSpan(span)); + } + + public void afterResponse(Object response) { + logger.info("after response {}", response); + + // Finish the Span + tracer.scopeManager().activeSpan().finish(); + + // Deactivate the Span + tlsScope.get().close(); + } +} \ No newline at end of file diff --git a/opentracing-util/src/main/java/io/opentracing/util/AutoFinishScopeManager.java b/opentracing-util/src/main/java/io/opentracing/util/AutoFinishScopeManager.java index bc6c4500..d186cf00 100644 --- a/opentracing-util/src/main/java/io/opentracing/util/AutoFinishScopeManager.java +++ b/opentracing-util/src/main/java/io/opentracing/util/AutoFinishScopeManager.java @@ -41,4 +41,9 @@ public Span activeSpan() { AutoFinishScope scope = tlsScope.get(); return scope == null ? null : scope.span(); } + + public AutoFinishScope.Continuation captureScope() { + AutoFinishScope scope = tlsScope.get(); + return scope == null ? null : scope.capture(); + } } diff --git a/opentracing-util/src/test/java/io/opentracing/util/AutoFinishScopeManagerTest.java b/opentracing-util/src/test/java/io/opentracing/util/AutoFinishScopeManagerTest.java index c60aafdb..0e9f5b91 100644 --- a/opentracing-util/src/test/java/io/opentracing/util/AutoFinishScopeManagerTest.java +++ b/opentracing-util/src/test/java/io/opentracing/util/AutoFinishScopeManagerTest.java @@ -36,6 +36,12 @@ public void missingScope() throws Exception { assertNull(missingSpan); } + @Test + public void missingCapturedScope() throws Exception { + AutoFinishScope.Continuation missingContinuation = source.captureScope(); + assertNull(missingContinuation); + } + @Test public void activateSpan() throws Exception { Span span = mock(Span.class); @@ -57,4 +63,36 @@ public void activateSpan() throws Exception { Scope missingSpan = source.active(); assertNull(missingSpan); } + + @Test + public void captureScope() 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 active = source.activate(span); + AutoFinishScope.Continuation cont = source.captureScope(); + try { + assertNotNull(active); + assertNotNull(cont); + } finally { + active.close(); + } + + verify(span, never()).finish(); + assertNull(source.activeSpan()); + assertNull(source.captureScope()); + + active = cont.activate(); + try { + assertNotNull(active); + assertNotNull(source.activeSpan()); + } finally { + active.close(); + } + + // Finally finished. + verify(span).finish(); + assertNull(source.activeSpan()); + assertNull(source.captureScope()); + } }