diff --git a/opentracing-api/pom.xml b/opentracing-api/pom.xml
index f747157f..0c44e104 100644
--- a/opentracing-api/pom.xml
+++ b/opentracing-api/pom.xml
@@ -29,8 +29,8 @@
${project.basedir}/..
- 1.6
- java16
+ 1.7
+ java17
@@ -40,5 +40,20 @@
1.10.19
test
+
+ org.slf4j
+ slf4j-api
+ 1.7.23
+
+
+ log4j
+ log4j
+ 1.2.17
+
+
+ org.slf4j
+ slf4j-log4j12
+ 1.7.23
+
diff --git a/opentracing-api/src/main/java/io/opentracing/SpanManager.java b/opentracing-api/src/main/java/io/opentracing/SpanManager.java
new file mode 100644
index 00000000..7bf45355
--- /dev/null
+++ b/opentracing-api/src/main/java/io/opentracing/SpanManager.java
@@ -0,0 +1,78 @@
+package io.opentracing;
+
+/**
+ * SpanManager allows an existing (possibly thread-local-aware) execution context provider to also manage the current
+ * active OpenTracing span.
+ */
+public interface SpanManager {
+
+ /**
+ * A SpanClosure can be used *once* to make a Span active within a SpanManager, then deactivate it once the
+ * "closure" (or period of Span activity) has finished.
+ *
+ * Most users do not directly interact with SpanClosure, activate(), or deactivate(), but rather use
+ * SpanManager-aware Runnables/Callables/Executors. Those higher-level primitives need not be defined within the
+ * OpenTracing core API.
+ *
+ * @see SpanManager#captureActive()
+ */
+ interface SpanClosure extends AutoCloseable {
+
+ /**
+ * Make the Span encapsulated by this SpanClosure active and return it.
+ *
+ * NOTE: It is an error to call activate() more than once on a single SpanClosure instance.
+ *
+ * @see SpanManager#captureActive()
+ * @return the newly-activated Span
+ */
+ Span activate();
+
+ /**
+ * @return the encapsulated Span, or null if there isn't one.
+ */
+ Span span();
+
+ /**
+ * End this active period for the Span previously returned by activate(). Finish the span iff finish=true.
+ *
+ * NOTE: It is an error to call deactivate() more than once on a single SpanClosure instance.
+ */
+ void deactivate(boolean finishSpan);
+
+ }
+
+ /**
+ * @return the currently active Span for this SpanManager, or null if no such Span could be found
+ */
+ Span active();
+
+ /**
+ * Capture any SpanManager-specific context (e.g., MDC context) along with the active Span (even if null) and
+ * encapsulate it in a SpanClosure for activation in the future, perhaps in a different thread or on a different
+ * executor.
+ *
+ * If the active Span is null, the implementation must still return a valid SpanClosure; when the closure activates,
+ * it will clear any active Span.
+ *
+ * @see SpanManager.SpanClosure
+ *
+ * @return a SpanClosure that represents the active Span and any other SpanManager-specific context, even if the
+ * active Span is null.
+ */
+ SpanClosure captureActive();
+
+ /**
+ * Explicitly capture the given Span and any active state (e.g., MDC state) about the current execution context.
+ *
+ * @param span
+ * @return a SpanClosure that represents the active Span and any other SpanManager-specific context, even if the
+ * active Span is null.
+ */
+ SpanClosure capture(Span span);
+
+ /**
+ * Tell the SpanManager that a particular Span has finished (and update any structures accordingly).
+ */
+ void onFinish(Span span);
+}
diff --git a/opentracing-api/src/main/java/io/opentracing/Tracer.java b/opentracing-api/src/main/java/io/opentracing/Tracer.java
index 26b3d001..74206c0e 100644
--- a/opentracing-api/src/main/java/io/opentracing/Tracer.java
+++ b/opentracing-api/src/main/java/io/opentracing/Tracer.java
@@ -23,6 +23,9 @@ public interface Tracer {
/**
* Return a new SpanBuilder for a Span with the given `operationName`.
*
+ *
If there is an active Span according to the activeSpanManager(),
+ * buildSpan will automatically have an asChildOf() reference to same.
+ *
*
You can override the operationName later via {@link Span#setOperationName(String)}.
*
*
A contrived example:
@@ -41,6 +44,8 @@ public interface Tracer {
*/
SpanBuilder buildSpan(String operationName);
+ SpanManager activeSpanManager();
+
/**
* Inject a SpanContext into a `carrier` of a given type, presumably for propagation across process boundaries.
*
@@ -128,5 +133,7 @@ interface SpanBuilder extends SpanContext {
/** Returns the started Span. */
Span start();
+ SpanManager.SpanClosure startAndActivate();
+
}
}
diff --git a/opentracing-api/src/main/java/io/opentracing/propagation/Format.java b/opentracing-api/src/main/java/io/opentracing/propagation/Format.java
index 29d71d6c..894ed906 100644
--- a/opentracing-api/src/main/java/io/opentracing/propagation/Format.java
+++ b/opentracing-api/src/main/java/io/opentracing/propagation/Format.java
@@ -1,5 +1,5 @@
/**
- * Copyright 2016 The OpenTracing Authors
+ * 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
@@ -35,6 +35,12 @@
*/
public interface Format {
final class Builtin implements Format {
+ private final String name;
+
+ private Builtin(String name) {
+ this.name = name;
+ }
+
/**
* The TEXT_MAP format allows for arbitrary String->String map encoding of SpanContext state for Tracer.inject
* and Tracer.extract.
@@ -46,7 +52,7 @@ final class Builtin implements Format {
* @see Format
* @see Builtin#HTTP_HEADERS
*/
- public final static Format TEXT_MAP = new Builtin();
+ public final static Format TEXT_MAP = new Builtin("TEXT_MAP");
/**
* The HTTP_HEADERS format allows for HTTP-header-compatible String->String map encoding of SpanContext state
@@ -60,7 +66,7 @@ final class Builtin implements Format {
* @see Format
* @see Builtin#TEXT_MAP
*/
- public final static Format HTTP_HEADERS = new Builtin();
+ public final static Format HTTP_HEADERS = new Builtin("HTTP_HEADERS");
/**
* The BINARY format allows for unconstrained binary encoding of SpanContext state for Tracer.inject and
@@ -70,6 +76,14 @@ final class Builtin implements Format {
* @see io.opentracing.Tracer#extract(Format, Object)
* @see Format
*/
- public final static Format BINARY = new Builtin();
+ public final static Format BINARY = new Builtin("BINARY");
+
+ /**
+ * @return Short name for built-in formats as they tend to show up in exception messages.
+ */
+ @Override
+ public String toString() {
+ return Builtin.class.getSimpleName() + "." + name;
+ }
}
}
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 9da1118a..aa18777d 100644
--- a/opentracing-api/src/main/java/io/opentracing/tag/Tags.java
+++ b/opentracing-api/src/main/java/io/opentracing/tag/Tags.java
@@ -22,11 +22,12 @@
*/
public final class Tags {
- private Tags(){}
+ private Tags() {
+ }
/**
- * A constant for setting the span kind to indicate that it represents a server span.
- */
+ * A constant for setting the span kind to indicate that it represents a server span.
+ */
public static final String SPAN_KIND_SERVER = "server";
/**
@@ -35,32 +36,32 @@ private Tags(){}
public static final String SPAN_KIND_CLIENT = "client";
/**
- * HTTP_URL records the url of the incoming request.
+ * HTTP_URL records the url of the incoming request.
*/
public static final StringTag HTTP_URL = new StringTag("http.url");
/**
- * HTTP_STATUS records the http status code of the response.
+ * HTTP_STATUS records the http status code of the response.
*/
public static final IntTag HTTP_STATUS = new IntTag("http.status_code");
/**
- * HTTP_METHOD records the http method. Case-insensitive.
+ * HTTP_METHOD records the http method. Case-insensitive.
*/
public static final StringTag HTTP_METHOD = new StringTag("http.method");
/**
- * PEER_HOST_IPV4 records IPv4 host address of the peer.
+ * PEER_HOST_IPV4 records IPv4 host address of the peer.
*/
public static final IntTag PEER_HOST_IPV4 = new IntTag("peer.ipv4");
/**
- * PEER_HOST_IPV6 records the IPv6 host address of the peer.
+ * PEER_HOST_IPV6 records the IPv6 host address of the peer.
*/
public static final StringTag PEER_HOST_IPV6 = new StringTag("peer.ipv6");
/**
- * PEER_SERVICE records the service name of the peer.
+ * PEER_SERVICE records the service name of the peer.
*/
public static final StringTag PEER_SERVICE = new StringTag("peer.service");
@@ -70,27 +71,50 @@ private Tags(){}
public static final StringTag PEER_HOSTNAME = new StringTag("peer.hostname");
/**
- * PEER_PORT records the port number of the peer.
+ * PEER_PORT records the port number of the peer.
*/
public static final ShortTag PEER_PORT = new ShortTag("peer.port");
/**
- * SAMPLING_PRIORITY determines the priority of sampling this Span.
+ * SAMPLING_PRIORITY determines the priority of sampling this Span.
*/
public static final ShortTag SAMPLING_PRIORITY = new ShortTag("sampling.priority");
/**
- * SPAN_KIND hints at the relationship between spans, e.g. client/server.
+ * SPAN_KIND hints at the relationship between spans, e.g. client/server.
*/
public static final StringTag SPAN_KIND = new StringTag("span.kind");
/**
- * COMPONENT is a low-cardinality identifier of the module, library, or package that is instrumented.
+ * COMPONENT is a low-cardinality identifier of the module, library, or package that is instrumented.
*/
- public static final StringTag COMPONENT = new StringTag("component");
+ public static final StringTag COMPONENT = new StringTag("component");
/**
* ERROR indicates whether a Span ended in an error state.
*/
public static final BooleanTag ERROR = new BooleanTag("error");
+
+ /**
+ * DB_TYPE indicates the type of Database.
+ * For any SQL database, "sql". For others, the lower-case database category, e.g. "cassandra", "hbase", or "redis"
+ */
+ public static final StringTag DB_TYPE = new StringTag("db.type");
+
+ /**
+ * DB_INSTANCE indicates the instance name of Database.
+ * If the jdbc.url="jdbc:mysql://127.0.0.1:3306/customers", instance name is "customers".
+ */
+ public static final StringTag DB_INSTANCE = new StringTag("db.instance");
+
+ /**
+ * DB_USER indicates the user name of Database, e.g. "readonly_user" or "reporting_user"
+ */
+ public static final StringTag DB_USER = new StringTag("db.user");
+
+ /**
+ * DB_STATEMENT records a database statement for the given database type.
+ * For db.type="SQL", "SELECT * FROM wuser_table". For db.type="redis", "SET mykey "WuValue".
+ */
+ public static final StringTag DB_STATEMENT = new StringTag("db.statement");
}
diff --git a/opentracing-api/src/test/java/io/opentracing/propagation/BuiltinFormatTest.java b/opentracing-api/src/test/java/io/opentracing/propagation/BuiltinFormatTest.java
new file mode 100644
index 00000000..200ff196
--- /dev/null
+++ b/opentracing-api/src/test/java/io/opentracing/propagation/BuiltinFormatTest.java
@@ -0,0 +1,37 @@
+/**
+ * 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.propagation;
+
+import org.junit.Test;
+
+import static org.junit.Assert.assertEquals;
+
+public class BuiltinFormatTest {
+
+ @Test
+ public void test_HTTP_HEADERS_toString() {
+ assertEquals("Builtin.HTTP_HEADERS", Format.Builtin.HTTP_HEADERS.toString());
+ }
+
+ @Test
+ public void test_TEXT_MAP_toString() {
+ assertEquals("Builtin.TEXT_MAP", Format.Builtin.TEXT_MAP.toString());
+ }
+
+ @Test
+ public void test_BINARY_toString() {
+ assertEquals("Builtin.BINARY", Format.Builtin.BINARY.toString());
+ }
+
+}
diff --git a/opentracing-impl/src/main/java/io/opentracing/impl/AbstractSpan.java b/opentracing-impl/src/main/java/io/opentracing/impl/AbstractSpan.java
index 4305684d..49fc5e59 100644
--- a/opentracing-impl/src/main/java/io/opentracing/impl/AbstractSpan.java
+++ b/opentracing-impl/src/main/java/io/opentracing/impl/AbstractSpan.java
@@ -23,6 +23,7 @@
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicLong;
abstract class AbstractSpan implements Span, SpanContext {
@@ -34,6 +35,7 @@ abstract class AbstractSpan implements Span, SpanContext {
private Duration duration;
private final Map tags = new HashMap<>();
private final List logs = new ArrayList<>();
+ private final AtomicLong refCount = new AtomicLong(0); // XXX
AbstractSpan(String operationName ) {
this(operationName, Instant.now());
diff --git a/opentracing-impl/src/main/java/io/opentracing/impl/AbstractSpanBuilder.java b/opentracing-impl/src/main/java/io/opentracing/impl/AbstractSpanBuilder.java
index 4c04b29a..70fcca0f 100644
--- a/opentracing-impl/src/main/java/io/opentracing/impl/AbstractSpanBuilder.java
+++ b/opentracing-impl/src/main/java/io/opentracing/impl/AbstractSpanBuilder.java
@@ -13,10 +13,8 @@
*/
package io.opentracing.impl;
-import io.opentracing.References;
-import io.opentracing.Span;
-import io.opentracing.SpanContext;
-import io.opentracing.Tracer;
+import io.opentracing.*;
+
import java.time.Instant;
import java.util.ArrayList;
import java.util.HashMap;
@@ -122,6 +120,11 @@ public final Span start() {
return span;
}
+ @Override
+ public SpanManager.SpanClosure startAndActivate() {
+ return null; // XXX: not correct... we'd need access to the AbstractTracer's SpanManager.
+ }
+
private void withBaggageFrom(SpanContext from) {
for (Entry baggageItem : from.baggageItems()) {
this.withBaggageItem(baggageItem.getKey(), baggageItem.getValue());
diff --git a/opentracing-impl/src/main/java/io/opentracing/impl/AbstractTracer.java b/opentracing-impl/src/main/java/io/opentracing/impl/AbstractTracer.java
index 9b0c8169..0a5aa59b 100644
--- a/opentracing-impl/src/main/java/io/opentracing/impl/AbstractTracer.java
+++ b/opentracing-impl/src/main/java/io/opentracing/impl/AbstractTracer.java
@@ -13,6 +13,7 @@
*/
package io.opentracing.impl;
+import io.opentracing.SpanManager;
import io.opentracing.SpanContext;
import io.opentracing.Tracer;
import io.opentracing.propagation.Extractor;
@@ -28,14 +29,26 @@ abstract class AbstractTracer implements Tracer {
static final boolean BAGGAGE_ENABLED = !Boolean.getBoolean("opentracing.propagation.dropBaggage");
private final PropagationRegistry registry = new PropagationRegistry();
+ private SpanManager manager;
+
protected AbstractTracer() {
+ this(null); // SpanManager is optional for this spike
+ }
+
+ protected AbstractTracer(SpanManager manager) {
+ this.manager = manager;
registry.register(Format.Builtin.TEXT_MAP, new TextMapInjectorImpl(this));
registry.register(Format.Builtin.TEXT_MAP, new TextMapExtractorImpl(this));
}
abstract AbstractSpanBuilder createSpanBuilder(String operationName);
+ @Override
+ public SpanManager activeSpanManager() {
+ return this.manager;
+ }
+
@Override
public SpanBuilder buildSpan(String operationName){
return createSpanBuilder(operationName);
diff --git a/opentracing-impl/src/main/java/io/opentracing/impl/GlobalTracer.java b/opentracing-impl/src/main/java/io/opentracing/impl/GlobalTracer.java
new file mode 100644
index 00000000..bbcdcf56
--- /dev/null
+++ b/opentracing-impl/src/main/java/io/opentracing/impl/GlobalTracer.java
@@ -0,0 +1,155 @@
+package io.opentracing.impl;
+
+/**
+ * Copyright 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.
+ */
+
+import io.opentracing.*;
+import io.opentracing.propagation.Format;
+
+import java.util.Iterator;
+import java.util.ServiceLoader;
+import java.util.concurrent.atomic.AtomicReference;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+/**
+ * Forwards all methods to another tracer that can be configured in one of two ways:
+ *
+ * - Explicitly, calling {@link #register(Tracer)} with a configured tracer, or:
+ * - Automatically using the Java {@link ServiceLoader} SPI mechanism to load a {@link Tracer} from the classpath.
+ *
+ *
+ * When the tracer is needed it is lazily looked up using the following rules:
+ *
+ * - The last-{@link #register(Tracer) registered} tracer always takes precedence.
+ * - If no tracer was registered, one is looked up from the {@link ServiceLoader}.
+ * The {@linkplain GlobalTracer} will not attempt to choose between implementations:
+ * - If no single tracer service is found, the {@link io.opentracing.NoopTracer NoopTracer} will be used.
+ *
+ */
+public final class GlobalTracer implements Tracer {
+ private static final Logger LOGGER = Logger.getLogger(GlobalTracer.class.getName());
+
+ /**
+ * Singleton instance.
+ *
+ * Since we cannot prevent people using {@linkplain #get() GlobalTracer.get()} as a constant,
+ * this guarantees that references obtained before, during or after initialization
+ * all behave as if obtained after initialization once properly initialized.
+ * As a minor additional benefit it makes it harder to circumvent the {@link Tracer} API.
+ */
+ private static final GlobalTracer INSTANCE = new GlobalTracer();
+
+ /**
+ * The resolved {@link Tracer} to delegate to.
+ *
+ * This can be either an {@link #register(Tracer) explicitly registered} or
+ * the {@link #loadSingleSpiImplementation() automatically resolved} Tracer
+ * (or null during initialization).
+ */
+ private final AtomicReference globalTracer = new AtomicReference();
+
+ private GlobalTracer() {
+ }
+
+ private Tracer lazyTracer() {
+ Tracer tracer = globalTracer.get();
+ if (tracer == null) {
+ final Tracer resolved = loadSingleSpiImplementation();
+ while (tracer == null && resolved != null) { // handle rare race condition
+ globalTracer.compareAndSet(null, resolved);
+ tracer = globalTracer.get();
+ }
+ LOGGER.log(Level.INFO, "Using GlobalTracer: {0}.", tracer);
+ }
+ return tracer;
+ }
+
+ /**
+ * Returns the constant {@linkplain GlobalTracer}.
+ *
+ * All methods are forwarded to the currently configured tracer.
+ * Until a tracer is {@link #register(Tracer) explicitly configured},
+ * one is looked up from the {@link ServiceLoader},
+ * falling back to the {@link io.opentracing.NoopTracer NoopTracer}.
+ * A tracer can be re-configured at any time.
+ * For example, the tracer used to extract a span may be different than the one that injects it.
+ *
+ * @return The global tracer constant.
+ * @see #register(Tracer)
+ */
+ public static Tracer get() {
+ return INSTANCE;
+ }
+
+ /**
+ * Explicitly configures a {@link Tracer} to back the behaviour of the {@link #get() global tracer}.
+ *
+ * The previous global tracer is returned so it can be restored later if necessary.
+ *
+ * @param tracer Tracer to use as global tracer.
+ * @return The previous global tracer or null if there was none.
+ */
+ public static Tracer register(final Tracer tracer) {
+ if (tracer instanceof GlobalTracer) {
+ LOGGER.log(Level.FINE, "Attempted to register the GlobalTracer as delegate of itself.");
+ return INSTANCE.globalTracer.get(); // no-op, return 'previous' tracer.
+ }
+ Tracer previous = INSTANCE.globalTracer.getAndSet(tracer);
+ LOGGER.log(Level.INFO, "Registered GlobalTracer {0} (previously {1}).", new Object[]{tracer, previous});
+ return previous;
+ }
+
+ @Override
+ public SpanBuilder buildSpan(String operationName) {
+ return lazyTracer().buildSpan(operationName);
+ }
+
+ @Override
+ public SpanManager activeSpanManager() {
+ return lazyTracer().activeSpanManager();
+ }
+
+ @Override
+ public void inject(SpanContext spanContext, Format format, C carrier) {
+ lazyTracer().inject(spanContext, format, carrier);
+ }
+
+ @Override
+ public SpanContext extract(Format format, C carrier) {
+ return lazyTracer().extract(format, carrier);
+ }
+
+ /**
+ * Loads a single service implementation from {@link ServiceLoader}.
+ *
+ * @return The single service or a NoopTracer.
+ */
+ private static Tracer loadSingleSpiImplementation() {
+ // Use the ServiceLoader to find the declared Tracer implementation.
+ Iterator spiImplementations =
+ ServiceLoader.load(Tracer.class, Tracer.class.getClassLoader()).iterator();
+ if (spiImplementations.hasNext()) {
+ Tracer foundImplementation = spiImplementations.next();
+ if (!spiImplementations.hasNext()) {
+ return foundImplementation;
+ }
+ LOGGER.log(Level.WARNING, "More than one Tracer service found. " +
+ "Falling back to NoopTracer implementation.");
+ }
+ return NoopTracerFactory.create();
+ }
+
+}
+
diff --git a/opentracing-impl/src/main/java/io/opentracing/impl/NoopSpan.java b/opentracing-impl/src/main/java/io/opentracing/impl/NoopSpan.java
index de0f832b..2820dc0b 100644
--- a/opentracing-impl/src/main/java/io/opentracing/impl/NoopSpan.java
+++ b/opentracing-impl/src/main/java/io/opentracing/impl/NoopSpan.java
@@ -13,8 +13,7 @@
*/
package io.opentracing.impl;
-import io.opentracing.NoopSpanContext;
-import io.opentracing.Span;
+import io.opentracing.*;
final class NoopSpan extends AbstractSpan implements io.opentracing.NoopSpan, NoopSpanContext {
diff --git a/opentracing-impl/src/main/java/io/opentracing/impl/NoopSpanBuilder.java b/opentracing-impl/src/main/java/io/opentracing/impl/NoopSpanBuilder.java
index 08976fc6..77b0e8a2 100644
--- a/opentracing-impl/src/main/java/io/opentracing/impl/NoopSpanBuilder.java
+++ b/opentracing-impl/src/main/java/io/opentracing/impl/NoopSpanBuilder.java
@@ -15,6 +15,8 @@
import io.opentracing.NoopSpanContext;
+import java.util.Map;
+
final class NoopSpanBuilder extends AbstractSpanBuilder implements io.opentracing.NoopSpanBuilder, NoopSpanContext {
static final NoopSpanBuilder INSTANCE = new NoopSpanBuilder("noop");
diff --git a/opentracing-impl/src/main/java/io/opentracing/impl/NoopTracer.java b/opentracing-impl/src/main/java/io/opentracing/impl/NoopTracer.java
index e990d019..95012645 100644
--- a/opentracing-impl/src/main/java/io/opentracing/impl/NoopTracer.java
+++ b/opentracing-impl/src/main/java/io/opentracing/impl/NoopTracer.java
@@ -13,7 +13,7 @@
*/
package io.opentracing.impl;
-import io.opentracing.SpanContext;
+import io.opentracing.*;
import io.opentracing.propagation.Format;
import java.util.Collections;
import java.util.Map;
@@ -22,6 +22,9 @@ final class NoopTracer extends AbstractTracer implements io.opentracing.NoopTrac
private static final NoopTracer INSTANCE = new NoopTracer();
+ @Override
+ public SpanManager activeSpanManager() { return null; }
+
@Override
public void inject(SpanContext spanContext, Format format, C carrier) {}
@@ -40,5 +43,4 @@ Map getTraceState(SpanContext spanContext) {
return Collections.emptyMap();
}
-
}
diff --git a/opentracing-impl/src/main/java/io/opentracing/impl/TextMapExtractorImpl.java b/opentracing-impl/src/main/java/io/opentracing/impl/TextMapExtractorImpl.java
index 4e80ab87..53b29c1a 100644
--- a/opentracing-impl/src/main/java/io/opentracing/impl/TextMapExtractorImpl.java
+++ b/opentracing-impl/src/main/java/io/opentracing/impl/TextMapExtractorImpl.java
@@ -41,4 +41,4 @@ public Tracer.SpanBuilder extract(TextMap carrier) {
return builder;
}
-}
\ No newline at end of file
+}
diff --git a/opentracing-impl/src/test/java/io/opentracing/impl/AbstractTracerTest.java b/opentracing-impl/src/test/java/io/opentracing/impl/AbstractTracerTest.java
index c45a2fac..bd0aa7f3 100644
--- a/opentracing-impl/src/test/java/io/opentracing/impl/AbstractTracerTest.java
+++ b/opentracing-impl/src/test/java/io/opentracing/impl/AbstractTracerTest.java
@@ -133,6 +133,7 @@ public void propagatesBaggageFromSpanContext() {
final class TestTracerImpl extends AbstractTracer {
static final String OPERATION_NAME = "operation-name";
+ Span activeSpan;
@Override
public AbstractSpanBuilder createSpanBuilder(String operationName) {
diff --git a/opentracing-impl/src/test/java/io/opentracing/impl/TestSpanImpl.java b/opentracing-impl/src/test/java/io/opentracing/impl/TestSpanImpl.java
index 634fbb34..0db93dc8 100644
--- a/opentracing-impl/src/test/java/io/opentracing/impl/TestSpanImpl.java
+++ b/opentracing-impl/src/test/java/io/opentracing/impl/TestSpanImpl.java
@@ -16,7 +16,6 @@
import io.opentracing.impl.AbstractSpan;
public class TestSpanImpl extends AbstractSpan {
-
TestSpanImpl(String operationName) {
super(operationName);
}
diff --git a/opentracing-mdc-demo/pom.xml b/opentracing-mdc-demo/pom.xml
new file mode 100644
index 00000000..3b5ccd53
--- /dev/null
+++ b/opentracing-mdc-demo/pom.xml
@@ -0,0 +1,45 @@
+
+
+
+ 4.0.0
+
+
+ io.opentracing
+ parent
+ 0.20.8-SNAPSHOT
+
+
+ opentracing-mdc-demo
+ OpenTracing-mdc-demo
+ OpenTracing MDC Demo
+
+
+ ${project.basedir}/..
+
+
+
+
+ ${project.groupId}
+ opentracing-api
+
+
+ ${project.groupId}
+ opentracing-mock
+
+
+
+
diff --git a/opentracing-mdc-demo/src/main/java/io/opentracing/mdcdemo/MDCDemo.java b/opentracing-mdc-demo/src/main/java/io/opentracing/mdcdemo/MDCDemo.java
new file mode 100644
index 00000000..59b080b3
--- /dev/null
+++ b/opentracing-mdc-demo/src/main/java/io/opentracing/mdcdemo/MDCDemo.java
@@ -0,0 +1,120 @@
+package io.opentracing.mdcdemo;
+
+import io.opentracing.Span;
+import io.opentracing.SpanManager;
+import io.opentracing.Tracer;
+import io.opentracing.mock.MockSpan;
+import io.opentracing.mock.MockTracer;
+import org.slf4j.Logger;
+import org.slf4j.MDC;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.concurrent.*;
+
+public class MDCDemo {
+ Tracer tracer;
+
+ private MDCDemo(Tracer tracer) {
+ this.tracer = tracer;
+ }
+
+ public void trivialSpan() {
+ Span span = this.tracer.buildSpan("trivial").start();
+ span.finish();
+ }
+
+ public void trivialChild() {
+ Span parent = this.tracer.buildSpan("trivialParent").start();
+ // The child will automatically know about the parent.
+ Span child = this.tracer.buildSpan("trivialChild").start();
+ child.finish();
+ parent.finish();
+ }
+
+ public void asyncSpans() {
+ final Tracer tracer = this.tracer; // save typing
+
+ // Create an ExecutorService and wrap it in a TracedExecutorService.
+ ExecutorService realExecutor = Executors.newFixedThreadPool(500);
+ final ExecutorService otExecutor = new TracedExecutorService(realExecutor, tracer.activeSpanManager());
+
+ // Hacky lists of futures we wait for before exiting asyncSpans.
+ final List> futures = new ArrayList<>();
+ final List> subfutures = new ArrayList<>();
+
+ // Create a parent SpanClosure for all of the async activity.
+ try (SpanManager.SpanClosure parentSpanClosure = tracer.buildSpan("parent").startAndActivate();) {
+
+ // Create 10 async children.
+ for (int i = 0; i < 10; i++) {
+ final int j = i;
+ futures.add(otExecutor.submit(new Runnable() {
+ @Override
+ public void run() {
+ // START child body
+
+ try (SpanManager.SpanClosure childSpanClosure =
+ tracer.buildSpan("child_" + j).startAndActivate();) {
+ Thread.currentThread().sleep(1000);
+ childSpanClosure.span().log("awoke");
+ Runnable r = new Runnable() {
+ @Override
+ public void run() {
+ Span active = tracer.activeSpanManager().active();
+ active.log("awoke again");
+ // Create a grandchild for each child.
+ Span grandchild = tracer.buildSpan("grandchild_" + j).start();
+ grandchild.finish();
+ active.finish();
+ }
+ };
+ subfutures.add(otExecutor.submit(r));
+ } catch (Exception e) { }
+
+ // END child body
+ }
+ }));
+ }
+ } catch (Exception e) { }
+
+ try {
+ for (Future> f : futures) {
+ f.get();
+ }
+ for (Future> f : subfutures) {
+ f.get();
+ }
+ } catch (Exception e) { }
+
+ otExecutor.shutdown();
+ try {
+ otExecutor.awaitTermination(3, TimeUnit.SECONDS);
+ } catch (InterruptedException e) {
+ e.printStackTrace();
+ }
+ }
+
+ public static void main(String[] args) {
+ org.apache.log4j.BasicConfigurator.configure();
+ final Logger logger = org.slf4j.LoggerFactory.getLogger("hack");
+ MDC.put("mdcKey", "mdcVal");
+
+ final MockTracer tracer = new MockTracer(new MDCSpanManager());
+
+ // Do stuff with the MockTracer.
+ {
+ MDCDemo demo = new MDCDemo(tracer);
+ demo.trivialSpan();
+ demo.trivialChild();
+ demo.asyncSpans();
+ }
+
+ // Print out all mock-Spans
+ List finishedSpans = tracer.finishedSpans();
+ for (MockSpan span : finishedSpans) {
+ logger.info("finished Span '{}'. trace={}, span={}, parent={}", span.operationName(), span.context().traceId(), span.context().spanId(), span.parentId());
+ }
+
+ }
+}
diff --git a/opentracing-mdc-demo/src/main/java/io/opentracing/mdcdemo/MDCSpanManager.java b/opentracing-mdc-demo/src/main/java/io/opentracing/mdcdemo/MDCSpanManager.java
new file mode 100644
index 00000000..5fff078d
--- /dev/null
+++ b/opentracing-mdc-demo/src/main/java/io/opentracing/mdcdemo/MDCSpanManager.java
@@ -0,0 +1,94 @@
+package io.opentracing.mdcdemo;
+
+import io.opentracing.Span;
+import io.opentracing.SpanManager;
+import org.slf4j.MDC;
+
+import java.util.Map;
+
+/**
+ * MDCSpanManager illustrates the core SpanManager concepts and capabilities to a first approximation. Not
+ * production-quality code.
+ */
+public class MDCSpanManager implements SpanManager {
+ private final ThreadLocal tlsSnapshot = new ThreadLocal();
+
+ class MDCSnapshot implements SpanClosure {
+ private final Map mdcContext;
+ private final Span span;
+ private MDCSnapshot toRestore = null;
+
+ MDCSnapshot(Span span) {
+ this.mdcContext = MDC.getCopyOfContextMap();
+ this.span = span;
+ }
+
+ @Override
+ public Span activate() {
+ toRestore = tlsSnapshot.get();
+ tlsSnapshot.set(this);
+ return span;
+ }
+
+ @Override
+ public void close() {
+ this.deactivate(true);
+ }
+
+ @Override
+ public Span span() {
+ return span;
+ }
+
+ @Override
+ public void deactivate(boolean finishSpan) {
+ if (span != null && finishSpan) {
+ span.finish();
+ }
+
+ if (tlsSnapshot.get() != this) {
+ // This probably shouldn't happen.
+ //
+ // XXX: log or throw something here?
+ return;
+ }
+ tlsSnapshot.set(toRestore);
+ }
+ }
+
+ @Override
+ public MDCSnapshot captureActive() {
+ return new MDCSnapshot(active());
+ }
+
+ @Override
+ public SpanClosure capture(Span span) {
+ return new MDCSnapshot(span);
+ }
+
+ @Override
+ public Span active() {
+ MDCSnapshot snapshot = tlsSnapshot.get();
+ if (snapshot == null) {
+ return null;
+ }
+ return snapshot.span;
+ }
+
+ @Override
+ public void onFinish(Span span) {
+ MDCSnapshot snapshot = tlsSnapshot.get();
+ MDCSnapshot prevSnapshot = null;
+ while (snapshot != null) {
+ if (snapshot.span == span) {
+ if (prevSnapshot == null) {
+ tlsSnapshot.set(snapshot.toRestore);
+ } else {
+ prevSnapshot.toRestore = snapshot.toRestore;
+ }
+ }
+ prevSnapshot = snapshot;
+ snapshot = snapshot.toRestore;
+ }
+ }
+}
diff --git a/opentracing-mdc-demo/src/main/java/io/opentracing/mdcdemo/TracedCallable.java b/opentracing-mdc-demo/src/main/java/io/opentracing/mdcdemo/TracedCallable.java
new file mode 100644
index 00000000..beae2b2a
--- /dev/null
+++ b/opentracing-mdc-demo/src/main/java/io/opentracing/mdcdemo/TracedCallable.java
@@ -0,0 +1,37 @@
+package io.opentracing.mdcdemo;
+
+import io.opentracing.SpanManager;
+import io.opentracing.Span;
+import io.opentracing.impl.GlobalTracer;
+
+import java.util.concurrent.Callable;
+
+public class TracedCallable implements Callable {
+ private SpanManager.SpanClosure spanClosure;
+ private SpanManager manager;
+ private Callable callable;
+
+ public TracedCallable(Callable callable) {
+ this(callable, GlobalTracer.get().activeSpanManager());
+ }
+
+ public TracedCallable(Callable callable, SpanManager manager) {
+ this(callable, manager.active(), manager);
+ }
+
+ public TracedCallable(Callable callable, Span span, SpanManager manager) {
+ if (callable == null) throw new NullPointerException("Callable is .");
+ this.callable = callable;
+ this.manager = manager;
+ this.spanClosure = manager.captureActive();
+ }
+
+ public T call() throws Exception {
+ final Span span = spanClosure.activate();
+ try {
+ return callable.call();
+ } finally {
+ spanClosure.deactivate(false);
+ }
+ }
+}
diff --git a/opentracing-mdc-demo/src/main/java/io/opentracing/mdcdemo/TracedExecutorService.java b/opentracing-mdc-demo/src/main/java/io/opentracing/mdcdemo/TracedExecutorService.java
new file mode 100644
index 00000000..4f7168b6
--- /dev/null
+++ b/opentracing-mdc-demo/src/main/java/io/opentracing/mdcdemo/TracedExecutorService.java
@@ -0,0 +1,100 @@
+package io.opentracing.mdcdemo;
+
+import io.opentracing.SpanManager;
+import io.opentracing.impl.GlobalTracer;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+import java.util.concurrent.*;
+
+public class TracedExecutorService implements ExecutorService {
+ private ExecutorService executor;
+ private SpanManager manager;
+
+ public TracedExecutorService(ExecutorService executor){
+ this(executor, GlobalTracer.get().activeSpanManager());
+ }
+
+ public TracedExecutorService(ExecutorService executor, SpanManager manager) {
+ if (executor == null) throw new NullPointerException("Executor is .");
+ if (manager == null) throw new NullPointerException("SpanManager is .");
+ this.executor = executor;
+ this.manager = manager;
+ }
+
+ @Override
+ public void execute(Runnable command) {
+ executor.execute(new TracedRunnable(command, manager));
+ }
+
+ @Override
+ public Future> submit(Runnable task) {
+ return executor.submit(new TracedRunnable(task, manager));
+ }
+
+ @Override
+ public Future submit(Runnable task, T result) {
+ return executor.submit(new TracedRunnable(task, manager), result);
+ }
+
+ @Override
+ public Future submit(Callable task) {
+ return executor.submit(new TracedCallable(task, manager));
+ }
+
+ @Override
+ public List> invokeAll(Collection extends Callable> tasks) throws InterruptedException {
+ return executor.invokeAll(tasksWithTracing(tasks));
+ }
+
+ @Override
+ public List> invokeAll(Collection extends Callable> tasks, long timeout, TimeUnit unit)
+ throws InterruptedException {
+ return executor.invokeAll(tasksWithTracing(tasks), timeout, unit);
+ }
+
+ @Override
+ public T invokeAny(Collection extends Callable> tasks) throws InterruptedException, ExecutionException {
+ return executor.invokeAny(tasksWithTracing(tasks));
+ }
+
+ @Override
+ public T invokeAny(Collection extends Callable> tasks, long timeout, TimeUnit unit)
+ throws InterruptedException, ExecutionException, TimeoutException {
+ return executor.invokeAny(tasksWithTracing(tasks), timeout, unit);
+ }
+
+ @Override
+ public void shutdown() {
+ executor.shutdown();
+ }
+
+ @Override
+ public List shutdownNow() {
+ return executor.shutdownNow();
+ }
+
+ @Override
+ public boolean isShutdown() {
+ return executor.isShutdown();
+ }
+
+ @Override
+ public boolean isTerminated() {
+ return executor.isTerminated();
+ }
+
+ @Override
+ public boolean awaitTermination(long timeout, TimeUnit unit) throws InterruptedException {
+ return executor.awaitTermination(timeout, unit);
+ }
+
+ private Collection extends Callable> tasksWithTracing(
+ Collection extends Callable> tasks) {
+ if (tasks == null) throw new NullPointerException("Collection of tasks is .");
+ Collection> result = new ArrayList>(tasks.size());
+ for (Callable task : tasks) result.add(new TracedCallable(task, manager));
+ return result;
+ }
+}
diff --git a/opentracing-mdc-demo/src/main/java/io/opentracing/mdcdemo/TracedRunnable.java b/opentracing-mdc-demo/src/main/java/io/opentracing/mdcdemo/TracedRunnable.java
new file mode 100644
index 00000000..fae446ea
--- /dev/null
+++ b/opentracing-mdc-demo/src/main/java/io/opentracing/mdcdemo/TracedRunnable.java
@@ -0,0 +1,41 @@
+package io.opentracing.mdcdemo;
+
+import io.opentracing.SpanManager;
+import io.opentracing.Span;
+import io.opentracing.impl.GlobalTracer;
+
+
+public class TracedRunnable implements Runnable {
+ private Runnable runnable;
+ private SpanManager manager;
+ private SpanManager.SpanClosure spanClosure;
+
+ public TracedRunnable(Runnable runnable) {
+ this(runnable, GlobalTracer.get().activeSpanManager());
+ }
+
+ public TracedRunnable(Runnable runnable, Span span) {
+ this(runnable, span, GlobalTracer.get().activeSpanManager());
+ }
+
+ public TracedRunnable(Runnable runnable, SpanManager manager) {
+ this(runnable, manager.active(), manager);
+ }
+
+ public TracedRunnable(Runnable runnable, Span span, SpanManager manager) {
+ if (runnable == null) throw new NullPointerException("Runnable is .");
+ this.runnable = runnable;
+ this.manager = manager;
+ this.spanClosure = manager.captureActive();
+ }
+
+ @Override
+ public void run() {
+ final Span span = this.spanClosure.activate();
+ try {
+ runnable.run();
+ } finally {
+ this.spanClosure.deactivate(false);
+ }
+ }
+}
diff --git a/opentracing-mock/pom.xml b/opentracing-mock/pom.xml
index 7c3dbffa..86964e41 100644
--- a/opentracing-mock/pom.xml
+++ b/opentracing-mock/pom.xml
@@ -36,6 +36,11 @@
${project.groupId}
opentracing-api
+
+ io.opentracing
+ opentracing-impl
+ test
+
diff --git a/opentracing-mock/src/main/java/io/opentracing/mock/MockSpan.java b/opentracing-mock/src/main/java/io/opentracing/mock/MockSpan.java
index c432090d..46f2c9bd 100644
--- a/opentracing-mock/src/main/java/io/opentracing/mock/MockSpan.java
+++ b/opentracing-mock/src/main/java/io/opentracing/mock/MockSpan.java
@@ -106,9 +106,13 @@ public void finish() {
@Override
public synchronized void finish(long finishMicros) {
finishedCheck("Finishing already finished span");
+
this.finishMicros = finishMicros;
this.mockTracer.appendFinishedSpan(this);
this.finished = true;
+ if (this.mockTracer.activeSpanManager() != null) {
+ this.mockTracer.activeSpanManager().onFinish(this);
+ }
}
@Override
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 27ca15ff..f3d9e6dc 100644
--- a/opentracing-mock/src/main/java/io/opentracing/mock/MockTracer.java
+++ b/opentracing-mock/src/main/java/io/opentracing/mock/MockTracer.java
@@ -20,10 +20,7 @@
import java.util.List;
import java.util.Map;
-import io.opentracing.References;
-import io.opentracing.Span;
-import io.opentracing.SpanContext;
-import io.opentracing.Tracer;
+import io.opentracing.*;
import io.opentracing.propagation.Format;
import io.opentracing.propagation.TextMap;
@@ -38,11 +35,17 @@
public class MockTracer implements Tracer {
private List finishedSpans = new ArrayList<>();
private final Propagator propagator;
+ private SpanManager spanManager;
public MockTracer() {
this(Propagator.PRINTER);
}
+ public MockTracer(SpanManager manager) {
+ this(Propagator.PRINTER);
+ this.spanManager = manager;
+ }
+
/**
* Create a new MockTracer that passes through any calls to inject() and/or extract().
*/
@@ -145,8 +148,20 @@ public MockSpan.MockContext extract(Format format, C carrier) {
}
@Override
- public Tracer.SpanBuilder buildSpan(String operationName) {
- return new SpanBuilder(operationName);
+ public SpanBuilder buildSpan(String operationName) {
+ SpanBuilder sb = new SpanBuilder(operationName);
+ if (this.spanManager != null) {
+ Span active = this.spanManager.active();
+ if (active != null) {
+ sb.asChildOf(active.context());
+ }
+ }
+ return sb;
+ }
+
+ @Override
+ public SpanManager activeSpanManager() {
+ return spanManager;
}
@Override
@@ -164,7 +179,7 @@ synchronized void appendFinishedSpan(MockSpan mockSpan) {
this.onSpanFinished(mockSpan);
}
- final class SpanBuilder implements Tracer.SpanBuilder {
+ public final class SpanBuilder implements Tracer.SpanBuilder {
private final String operationName;
private long startMicros;
private MockSpan.MockContext firstParent;
@@ -174,17 +189,17 @@ final class SpanBuilder implements Tracer.SpanBuilder {
this.operationName = operationName;
}
@Override
- public Tracer.SpanBuilder asChildOf(SpanContext parent) {
+ public SpanBuilder asChildOf(SpanContext parent) {
return addReference(References.CHILD_OF, parent);
}
@Override
- public Tracer.SpanBuilder asChildOf(Span parent) {
+ public SpanBuilder asChildOf(Span parent) {
return addReference(References.CHILD_OF, parent.context());
}
@Override
- public Tracer.SpanBuilder addReference(String referenceType, SpanContext referencedContext) {
+ public SpanBuilder addReference(String referenceType, SpanContext referencedContext) {
if (firstParent == null && (
referenceType.equals(References.CHILD_OF) || referenceType.equals(References.FOLLOWS_FROM))) {
this.firstParent = (MockSpan.MockContext)referencedContext;
@@ -193,35 +208,45 @@ public Tracer.SpanBuilder addReference(String referenceType, SpanContext referen
}
@Override
- public Tracer.SpanBuilder withTag(String key, String value) {
+ public SpanBuilder withTag(String key, String value) {
this.initialTags.put(key, value);
return this;
}
@Override
- public Tracer.SpanBuilder withTag(String key, boolean value) {
+ public SpanBuilder withTag(String key, boolean value) {
this.initialTags.put(key, value);
return this;
}
@Override
- public Tracer.SpanBuilder withTag(String key, Number value) {
+ public SpanBuilder withTag(String key, Number value) {
this.initialTags.put(key, value);
return this;
}
@Override
- public Tracer.SpanBuilder withStartTimestamp(long microseconds) {
+ public SpanBuilder withStartTimestamp(long microseconds) {
this.startMicros = microseconds;
return this;
}
@Override
- public Span start() {
+ public MockSpan start() {
if (this.startMicros == 0) {
this.startMicros = MockSpan.nowMicros();
}
- return new MockSpan(MockTracer.this, this.operationName, this.startMicros, initialTags, this.firstParent);
+ MockSpan rval = new MockSpan(MockTracer.this, this.operationName, this.startMicros, initialTags, this.firstParent);
+ if (MockTracer.this.spanManager != null) {
+ MockTracer.this.spanManager.capture(rval).activate();
+ }
+ return rval;
+ }
+
+ @Override
+ public SpanManager.SpanClosure startAndActivate() {
+ MockSpan span = this.start();
+ return MockTracer.this.spanManager.capture(span);
}
@Override
diff --git a/opentracing-mock/src/test/java/io/opentracing/mock/MockTracerTest.java b/opentracing-mock/src/test/java/io/opentracing/mock/MockTracerTest.java
index c24959c6..562a42e5 100644
--- a/opentracing-mock/src/test/java/io/opentracing/mock/MockTracerTest.java
+++ b/opentracing-mock/src/test/java/io/opentracing/mock/MockTracerTest.java
@@ -16,20 +16,24 @@
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotEquals;
+import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
+import java.util.concurrent.*;
+import io.opentracing.*;
+import io.opentracing.mock.MockTracer;
import org.junit.Assert;
import org.junit.Test;
-import io.opentracing.Span;
-import io.opentracing.Tracer;
-import io.opentracing.SpanContext;
import io.opentracing.propagation.Format;
import io.opentracing.propagation.TextMapExtractAdapter;
import io.opentracing.propagation.TextMapInjectAdapter;
+import org.slf4j.Logger;
+import org.slf4j.MDC;
+
public class MockTracerTest {
@Test
public void testRootSpan() {
diff --git a/opentracing-noop/src/main/java/io/opentracing/NoopSpan.java b/opentracing-noop/src/main/java/io/opentracing/NoopSpan.java
index 8e971804..1a5e20c5 100644
--- a/opentracing-noop/src/main/java/io/opentracing/NoopSpan.java
+++ b/opentracing-noop/src/main/java/io/opentracing/NoopSpan.java
@@ -21,7 +21,6 @@ public interface NoopSpan extends Span {
final class NoopSpanImpl implements NoopSpan {
-
@Override
public SpanContext context() { return NoopSpanContextImpl.INSTANCE; }
diff --git a/opentracing-noop/src/main/java/io/opentracing/NoopSpanBuilder.java b/opentracing-noop/src/main/java/io/opentracing/NoopSpanBuilder.java
index 30c5e20c..85e85979 100644
--- a/opentracing-noop/src/main/java/io/opentracing/NoopSpanBuilder.java
+++ b/opentracing-noop/src/main/java/io/opentracing/NoopSpanBuilder.java
@@ -62,6 +62,9 @@ public Span start() {
return NoopSpanImpl.INSTANCE;
}
+ @Override
+ public SpanManager.SpanClosure startAndActivate() { return null; } // XXX: not correct
+
@Override
public Iterable> baggageItems() {
return Collections.EMPTY_MAP.entrySet();
diff --git a/opentracing-noop/src/main/java/io/opentracing/NoopSpanSnapshot.java b/opentracing-noop/src/main/java/io/opentracing/NoopSpanSnapshot.java
new file mode 100644
index 00000000..a484a72d
--- /dev/null
+++ b/opentracing-noop/src/main/java/io/opentracing/NoopSpanSnapshot.java
@@ -0,0 +1,9 @@
+package io.opentracing;
+
+public interface NoopSpanSnapshot {
+ static final NoopSpanSnapshotImpl INSTANCE = new NoopSpanSnapshotImpl();
+}
+
+final class NoopSpanSnapshotImpl implements NoopSpanSnapshot {
+
+}
\ No newline at end of file
diff --git a/opentracing-noop/src/main/java/io/opentracing/NoopTracer.java b/opentracing-noop/src/main/java/io/opentracing/NoopTracer.java
index 40d17a9a..11a9aec6 100644
--- a/opentracing-noop/src/main/java/io/opentracing/NoopTracer.java
+++ b/opentracing-noop/src/main/java/io/opentracing/NoopTracer.java
@@ -24,6 +24,11 @@ final class NoopTracerImpl implements NoopTracer {
@Override
public SpanBuilder buildSpan(String operationName) { return NoopSpanBuilderImpl.INSTANCE; }
+ public void setSpanManager(SpanManager mgr) {}
+
+ @Override
+ public SpanManager activeSpanManager() { return null; }
+
@Override
public void inject(SpanContext spanContext, Format format, C carrier) {}
diff --git a/pom.xml b/pom.xml
index 047c24c3..132c335b 100644
--- a/pom.xml
+++ b/pom.xml
@@ -238,7 +238,7 @@
true
-
+
maven-release-plugin
${maven-release-plugin.version}