diff --git a/opentracing-util/src/main/java/io/opentracing/util/NoopScopeListener.java b/opentracing-util/src/main/java/io/opentracing/util/NoopScopeListener.java new file mode 100644 index 00000000..c8f044ec --- /dev/null +++ b/opentracing-util/src/main/java/io/opentracing/util/NoopScopeListener.java @@ -0,0 +1,34 @@ +/* + * 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.util; + +import io.opentracing.Span; + +public interface NoopScopeListener extends ScopeListener { + NoopScopeListener INSTANCE = new NoopScopeListenerImpl(); +} + +/** + * A noop (i.e., cheap-as-possible) implementation of a ScopeListener. + */ +class NoopScopeListenerImpl implements NoopScopeListener { + + @Override + public void onActivated(Span span) { + } + + @Override + public void onClosed() { + } +} diff --git a/opentracing-util/src/main/java/io/opentracing/util/ScopeListener.java b/opentracing-util/src/main/java/io/opentracing/util/ScopeListener.java new file mode 100644 index 00000000..4ce34a81 --- /dev/null +++ b/opentracing-util/src/main/java/io/opentracing/util/ScopeListener.java @@ -0,0 +1,44 @@ +/* + * 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.util; + +import io.opentracing.Scope; +import io.opentracing.ScopeManager; +import io.opentracing.Span; + +/** + * Listener that can react on changes of currently active {@link Span}. + *
+ * The {@link #onActivated} method will be called, whenever scope changes - that can be both + * as result of a {@link ScopeManager#activate(Span, boolean)} call or when {@link Scope#close()} + * is closed on a nested scope. + *
+ * {@link #onClosed} is called when closing outermost scope - meaning no scope is currently active. + * + * @see ThreadLocalScopeManager + */ +public interface ScopeListener { + + /** + * Called whenever a scope was activated (changed). + * + * @param span Activated span. Never null. + */ + void onActivated(Span span); + + /** + * Called when outermost scope was deactivated. + */ + void onClosed(); +} diff --git a/opentracing-util/src/main/java/io/opentracing/util/ThreadLocalScope.java b/opentracing-util/src/main/java/io/opentracing/util/ThreadLocalScope.java index e3a2f2dd..d98b425c 100644 --- a/opentracing-util/src/main/java/io/opentracing/util/ThreadLocalScope.java +++ b/opentracing-util/src/main/java/io/opentracing/util/ThreadLocalScope.java @@ -35,6 +35,7 @@ public class ThreadLocalScope implements Scope { this.finishOnClose = finishOnClose; this.toRestore = scopeManager.tlsScope.get(); scopeManager.tlsScope.set(this); + scopeManager.listener.onActivated(wrapped); } @Override @@ -48,7 +49,13 @@ public void close() { wrapped.finish(); } - scopeManager.tlsScope.set(toRestore); + if (toRestore != null) { + scopeManager.tlsScope.set(toRestore); + scopeManager.listener.onActivated(toRestore.wrapped); + } else { + scopeManager.tlsScope.remove(); + scopeManager.listener.onClosed(); + } } @Override diff --git a/opentracing-util/src/main/java/io/opentracing/util/ThreadLocalScopeManager.java b/opentracing-util/src/main/java/io/opentracing/util/ThreadLocalScopeManager.java index 7ed13f59..76e1f44a 100644 --- a/opentracing-util/src/main/java/io/opentracing/util/ThreadLocalScopeManager.java +++ b/opentracing-util/src/main/java/io/opentracing/util/ThreadLocalScopeManager.java @@ -19,11 +19,33 @@ /** * A simple {@link ScopeManager} implementation built on top of Java's thread-local storage primitive. + *
+ * Optionally supports {@link ScopeListener}, to perform additional actions when scope is changed for given thread.
+ * Listener methods are always called synchronously on the same thread, right after activation (meaning {@link #active()}
+ * already returns new a scope).
*
* @see ThreadLocalScope
*/
public class ThreadLocalScopeManager implements ScopeManager {
+
final ThreadLocal