diff --git a/opentracing-api/src/main/java/io/opentracing/Span.java b/opentracing-api/src/main/java/io/opentracing/Span.java
index 7a670c46..870a0241 100644
--- a/opentracing-api/src/main/java/io/opentracing/Span.java
+++ b/opentracing-api/src/main/java/io/opentracing/Span.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
@@ -22,16 +22,21 @@
*
Spans are created by the {@link Tracer#buildSpan} interface.
*/
public interface Span extends Closeable {
+
+ SpanManager.Visibility visibility();
+
/**
* Retrieve the associated SpanContext.
*
- * This may be called at any time, including after calls to finish().
+ * This may be called at any time, including after calls to markAsFinished().
*
* @return the SpanContext that encapsulates Span state that should propagate across process boundaries.
*/
SpanContext context();
/**
+ * Deactivates spans from spanManager.
+ *
* Sets the end timestamp to now and records the span.
*
*
With the exception of calls to Span.context(), this should be the last call made to the span instance, and to
@@ -42,12 +47,14 @@ public interface Span extends Closeable {
void finish();
/**
+ * Deactivates spans from spanManager.
+ *
* Sets an explicit end timestamp and records the span.
*
*
With the exception of calls to Span.context(), this should be the last call made to the span instance, and to
* do otherwise leads to undefined behavior.
*
- * @param finishMicros an explicit finish time, in microseconds since the epoch
+ * @param finishMicros an explicit markAsFinished time, in microseconds since the epoch
*
* @see Span#context()
*/
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..bd4c7f60
--- /dev/null
+++ b/opentracing-api/src/main/java/io/opentracing/SpanManager.java
@@ -0,0 +1,41 @@
+/**
+ * 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;
+
+/**
+ * @author Pavol Loffay
+ */
+public interface SpanManager {
+
+ /**
+ * @param span span to bundle into visibility
+ * @return visibility
+ */
+ Visibility bundle(Span span);
+
+ /**
+ * @return not finished active span or null
+ */
+ Visibility active();
+
+ interface Visibility {
+ void activate();
+ void deactivate();
+
+ Span span();
+ SpanContext context();
+ // should be called by span#finish();
+ void markAsFinished();
+ }
+}
diff --git a/opentracing-api/src/main/java/io/opentracing/ThreadLocalSpanManager.java b/opentracing-api/src/main/java/io/opentracing/ThreadLocalSpanManager.java
new file mode 100644
index 00000000..a2d25e0d
--- /dev/null
+++ b/opentracing-api/src/main/java/io/opentracing/ThreadLocalSpanManager.java
@@ -0,0 +1,74 @@
+/**
+ * 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;
+
+/**
+ * @author Pavol Loffay
+ */
+public class ThreadLocalSpanManager implements SpanManager {
+
+ private final ThreadLocal activeContext = new ThreadLocal();
+
+ public ThreadLocalSpanManager() {}
+
+ @Override
+ public Visibility bundle(Span span) {
+ return span.visibility() == null ? new ThreadLocalVisibility(span) : span.visibility();
+ }
+
+ @Override
+ public Visibility active() {
+ return activeContext.get() == null ? null : activeContext.get();
+ }
+
+ class ThreadLocalVisibility implements Visibility {
+ private final Span span;
+ private ThreadLocalVisibility previous;
+ private boolean finished;
+
+ public ThreadLocalVisibility(Span span) {
+ this.span = span;
+ }
+
+ @Override
+ public Span span() {
+ return finished ? null : span;
+ }
+
+ @Override
+ public SpanContext context() {
+ return span.context();
+ }
+
+ @Override
+ public void activate() {
+ previous = activeContext.get();
+ activeContext.set(this);
+ }
+
+ @Override
+ public void deactivate() {
+ if (this != activeContext.get()) {
+ // should not happen
+ return;
+ }
+ activeContext.set(previous);
+ }
+
+ @Override
+ public void markAsFinished() {
+ this.finished = true;
+ }
+ }
+}
diff --git a/opentracing-api/src/main/java/io/opentracing/Tracer.java b/opentracing-api/src/main/java/io/opentracing/Tracer.java
index 10f23b5e..c9983d4d 100644
--- a/opentracing-api/src/main/java/io/opentracing/Tracer.java
+++ b/opentracing-api/src/main/java/io/opentracing/Tracer.java
@@ -20,6 +20,9 @@
*/
public interface Tracer {
+ // span could be directly returned
+ SpanManager spanManager();
+
/**
* Return a new SpanBuilder for a Span with the given `operationName`.
*
@@ -113,6 +116,8 @@ interface SpanBuilder extends SpanContext {
*/
SpanBuilder addReference(String referenceType, SpanContext referencedContext);
+ SpanBuilder asRoot();
+
/** Same as {@link Span#setTag(String, String)}, but for the span being built. */
SpanBuilder withTag(String key, String value);
@@ -128,5 +133,6 @@ interface SpanBuilder extends SpanContext {
/** Returns the started Span. */
Span start();
+ Span startAndActivate();
}
}
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 2bfac906..7bbfccfb 100644
--- a/opentracing-api/src/main/java/io/opentracing/tag/Tags.java
+++ b/opentracing-api/src/main/java/io/opentracing/tag/Tags.java
@@ -14,7 +14,7 @@
package io.opentracing.tag;
/**
- * The following span tags are recommended for instrumentors who are trying to capture more
+ * The following span tags are recommended for instrumentors who are trying to bundle more
* semantic information about the spans. Tracers may expose additional features based on these
* standardized data points. Tag names follow a general structure of namespacing.
*
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 8685764d..ed1d615a 100644
--- a/opentracing-mock/src/main/java/io/opentracing/mock/MockSpan.java
+++ b/opentracing-mock/src/main/java/io/opentracing/mock/MockSpan.java
@@ -18,6 +18,7 @@
import io.opentracing.Span;
import io.opentracing.SpanContext;
+import io.opentracing.SpanManager;
/**
* MockSpans are created via MockTracer.buildSpan(...), but they are also returned via calls to
@@ -29,6 +30,8 @@ public final class MockSpan implements Span {
// A simple-as-possible (consecutive for repeatability) id generator.
private static AtomicLong nextId = new AtomicLong(0);
+ private final SpanManager.Visibility visibility;
+
private final MockTracer mockTracer;
private MockContext context;
private final long parentId; // 0 if there's no parent.
@@ -66,10 +69,10 @@ public long startMicros() {
return startMicros;
}
/**
- * @return the finish time of the Span; only valid after a call to finish().
+ * @return the markAsFinished time of the Span; only valid after a call to markAsFinished().
*/
public long finishMicros() {
- assert finishMicros > 0 : "must call finish() before finishMicros()";
+ assert finishMicros > 0 : "must call markAsFinished() before finishMicros()";
return finishMicros;
}
@@ -93,6 +96,11 @@ public List generatedErrors() {
return new ArrayList<>(errors);
}
+ @Override
+ public SpanManager.Visibility visibility() {
+ return visibility;
+ }
+
@Override
public synchronized MockContext context() {
return this.context;
@@ -107,6 +115,7 @@ public void finish() {
public synchronized void finish(long finishMicros) {
finishedCheck("Finishing already finished span");
this.finishMicros = finishMicros;
+ visibility.markAsFinished();
this.mockTracer.appendFinishedSpan(this);
this.finished = true;
}
@@ -248,10 +257,17 @@ public long timestampMicros() {
}
}
- MockSpan(MockTracer tracer, String operationName, long startMicros, Map initialTags, MockContext parent) {
+ MockSpan(MockTracer tracer, String operationName, long startMicros, Map initialTags, MockContext
+ parent, boolean activate) {
this.mockTracer = tracer;
this.operationName = operationName;
this.startMicros = startMicros;
+
+ this.visibility = tracer.spanManager().bundle(this);
+ if (activate) {
+ this.visibility.activate();
+ }
+
if (initialTags == null) {
this.tags = new HashMap<>();
} else {
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 f41bebbd..5896a4e1 100644
--- a/opentracing-mock/src/main/java/io/opentracing/mock/MockTracer.java
+++ b/opentracing-mock/src/main/java/io/opentracing/mock/MockTracer.java
@@ -23,6 +23,8 @@
import io.opentracing.References;
import io.opentracing.Span;
import io.opentracing.SpanContext;
+import io.opentracing.SpanManager;
+import io.opentracing.ThreadLocalSpanManager;
import io.opentracing.Tracer;
import io.opentracing.propagation.Format;
import io.opentracing.propagation.TextMap;
@@ -38,30 +40,36 @@
public class MockTracer implements Tracer {
private List finishedSpans = new ArrayList<>();
private final Propagator propagator;
+ private final SpanManager spanManager;
public MockTracer() {
- this(Propagator.PRINTER);
+ this(Propagator.PRINTER, new ThreadLocalSpanManager());
}
/**
* Create a new MockTracer that passes through any calls to inject() and/or extract().
*/
public MockTracer(Propagator propagator) {
+ this(propagator, new ThreadLocalSpanManager());
+ }
+
+ public MockTracer(Propagator propagator, SpanManager spanManager) {
this.propagator = propagator;
+ this.spanManager = spanManager;
}
/**
* Clear the finishedSpans() queue.
*
- * Note that this does *not* have any effect on Spans created by MockTracer that have not finish()ed yet; those
- * will still be enqueued in finishedSpans() when they finish().
+ * Note that this does *not* have any effect on Spans created by MockTracer that have not markAsFinished()ed yet; those
+ * will still be enqueued in finishedSpans() when they markAsFinished().
*/
public synchronized void reset() {
this.finishedSpans.clear();
}
/**
- * @return a copy of all finish()ed MockSpans started by this MockTracer (since construction or the last call to
+ * @return a copy of all markAsFinished()ed MockSpans started by this MockTracer (since construction or the last call to
* MockTracer.reset()).
*
* @see MockTracer#reset()
@@ -144,9 +152,14 @@ public MockSpan.MockContext extract(Format format, C carrier) {
};
}
+ @Override
+ public SpanManager spanManager() {
+ return spanManager;
+ }
+
@Override
public SpanBuilder buildSpan(String operationName) {
- return new SpanBuilder(operationName);
+ return new SpanBuilder(operationName, spanManager);
}
@Override
@@ -170,8 +183,14 @@ public final class SpanBuilder implements Tracer.SpanBuilder {
private MockSpan.MockContext firstParent;
private Map initialTags = new HashMap<>();
- SpanBuilder(String operationName) {
+ SpanBuilder(String operationName, SpanManager spanManager) {
this.operationName = operationName;
+
+ SpanManager.Visibility inferredParent = spanManager.active();
+ if (inferredParent != null) {
+ addReference(inferredParent.span() == null ? References.FOLLOWS_FROM : References.CHILD_OF,
+ inferredParent.context());
+ }
}
@Override
public SpanBuilder asChildOf(SpanContext parent) {
@@ -192,6 +211,12 @@ public SpanBuilder addReference(String referenceType, SpanContext referencedCont
return this;
}
+ @Override
+ public Tracer.SpanBuilder asRoot() {
+ firstParent = null;
+ return this;
+ }
+
@Override
public SpanBuilder withTag(String key, String value) {
this.initialTags.put(key, value);
@@ -221,7 +246,17 @@ public MockSpan start() {
if (this.startMicros == 0) {
this.startMicros = MockSpan.nowMicros();
}
- return new MockSpan(MockTracer.this, this.operationName, this.startMicros, initialTags, this.firstParent);
+ return new MockSpan(MockTracer.this, this.operationName, this.startMicros, initialTags,
+ this.firstParent, false);
+ }
+
+ @Override
+ public MockSpan startAndActivate() {
+ if (this.startMicros == 0) {
+ this.startMicros = MockSpan.nowMicros();
+ }
+ return new MockSpan(MockTracer.this, this.operationName, this.startMicros, initialTags,
+ this.firstParent, true);
}
@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..dadf57fa 100644
--- a/opentracing-mock/src/test/java/io/opentracing/mock/MockTracerTest.java
+++ b/opentracing-mock/src/test/java/io/opentracing/mock/MockTracerTest.java
@@ -33,7 +33,7 @@
public class MockTracerTest {
@Test
public void testRootSpan() {
- // Create and finish a root Span.
+ // Create and markAsFinished a root Span.
MockTracer tracer = new MockTracer();
{
Span span = tracer.buildSpan("tester").withStartTimestamp(1000).start();
@@ -87,7 +87,7 @@ public void testRootSpan() {
@Test
public void testChildSpan() {
- // Create and finish a root Span.
+ // Create and markAsFinished a root Span.
MockTracer tracer = new MockTracer();
{
Span parent = tracer.buildSpan("parent").withStartTimestamp(1000).start();
diff --git a/opentracing-mock/src/test/java/io/opentracing/mock/Sandbox.java b/opentracing-mock/src/test/java/io/opentracing/mock/Sandbox.java
new file mode 100644
index 00000000..1fc4dcca
--- /dev/null
+++ b/opentracing-mock/src/test/java/io/opentracing/mock/Sandbox.java
@@ -0,0 +1,40 @@
+/**
+ * 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.mock;
+
+import org.junit.Assert;
+import org.junit.Test;
+
+/**
+ * @author Pavol Loffay
+ */
+public class Sandbox {
+
+ @Test
+ public void test() {
+ MockTracer mockTracer = new MockTracer();
+ MockSpan root = mockTracer.buildSpan("root").start();
+ Assert.assertTrue(mockTracer.spanManager().active() == null);
+
+ root.visibility().activate();
+ Assert.assertEquals(root, mockTracer.spanManager().active());
+
+ MockSpan child = mockTracer.buildSpan("child").start();
+
+ child.finish();
+ root.finish();
+
+ Assert.assertEquals(root.context().spanId(), child.parentId());
+ }
+}
diff --git a/pom.xml b/pom.xml
index fe932431..92d68b87 100644
--- a/pom.xml
+++ b/pom.xml
@@ -24,8 +24,8 @@
opentracing-api
- opentracing-noop
- opentracing-impl
+
+
opentracing-mock