From e000eb0c62ee3149ae272c6c197bfc039d2c2749 Mon Sep 17 00:00:00 2001 From: Mike Cumings Date: Mon, 2 Oct 2017 08:05:04 -0700 Subject: [PATCH 01/19] Code cleanup (#199) - Propagate @deprecated annotation to implementations - Remove redundant "static final" definition from interface - Use Collections.emptyMap instead of Collections.EMPTY_MAP to preserve type --- .../src/main/java/io/opentracing/mock/MockTracer.java | 1 + .../src/main/java/io/opentracing/noop/NoopSpanBuilder.java | 5 +++-- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/opentracing-mock/src/main/java/io/opentracing/mock/MockTracer.java b/opentracing-mock/src/main/java/io/opentracing/mock/MockTracer.java index 8d01144e..97de5ebc 100644 --- a/opentracing-mock/src/main/java/io/opentracing/mock/MockTracer.java +++ b/opentracing-mock/src/main/java/io/opentracing/mock/MockTracer.java @@ -263,6 +263,7 @@ public SpanBuilder withStartTimestamp(long microseconds) { } @Override + @Deprecated public MockSpan start() { return startManual(); } diff --git a/opentracing-noop/src/main/java/io/opentracing/noop/NoopSpanBuilder.java b/opentracing-noop/src/main/java/io/opentracing/noop/NoopSpanBuilder.java index 06129830..3b033833 100644 --- a/opentracing-noop/src/main/java/io/opentracing/noop/NoopSpanBuilder.java +++ b/opentracing-noop/src/main/java/io/opentracing/noop/NoopSpanBuilder.java @@ -23,7 +23,7 @@ import java.util.Map; public interface NoopSpanBuilder extends Tracer.SpanBuilder, NoopSpanContext { - static final NoopSpanBuilder INSTANCE = new NoopSpanBuilderImpl(); + NoopSpanBuilder INSTANCE = new NoopSpanBuilderImpl(); } final class NoopSpanBuilderImpl implements NoopSpanBuilder { @@ -67,6 +67,7 @@ public Tracer.SpanBuilder withStartTimestamp(long microseconds) { } @Override + @Deprecated public Span start() { return startManual(); } @@ -83,7 +84,7 @@ public Span startManual() { @Override public Iterable> baggageItems() { - return Collections.EMPTY_MAP.entrySet(); + return Collections.emptyMap().entrySet(); } @Override From dd75c9dc3bb887ae90533ba22bba8d0ed51c94a3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois=20JACQUES?= Date: Tue, 7 Nov 2017 16:10:42 +0100 Subject: [PATCH 02/19] Add support for multi reference and expose references context and type from MockSpan. (#213) --- .../java/io/opentracing/mock/MockSpan.java | 76 +++++++++++++++++-- .../java/io/opentracing/mock/MockTracer.java | 14 ++-- .../io/opentracing/mock/MockTracerTest.java | 70 +++++++++++++++++ 3 files changed, 148 insertions(+), 12 deletions(-) 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 859513aa..ce637381 100644 --- a/opentracing-mock/src/main/java/io/opentracing/mock/MockSpan.java +++ b/opentracing-mock/src/main/java/io/opentracing/mock/MockSpan.java @@ -13,11 +13,13 @@ */ package io.opentracing.mock; +import io.opentracing.References; import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.Objects; import java.util.concurrent.atomic.AtomicLong; import io.opentracing.Span; @@ -42,6 +44,7 @@ public final class MockSpan implements Span { private final Map tags; private final List logEntries = new ArrayList<>(); private String operationName; + private final List references; private final List errors = new ArrayList<>(); @@ -57,11 +60,10 @@ public MockSpan setOperationName(String operationName) { } /** - * TODO: Support multiple parents in this API. - * - * @return the spanId of the Span's parent context, or 0 if no such parent exists. + * @return the spanId of the Span's first {@value References#CHILD_OF} reference, or the first reference of any type, or 0 if no reference exists. * * @see MockContext#spanId() + * @see MockSpan#references() */ public long parentId() { return parentId; @@ -97,6 +99,10 @@ public List generatedErrors() { return new ArrayList<>(errors); } + public List references() { + return new ArrayList<>(references); + } + @Override public synchronized MockContext context() { return this.context; @@ -232,7 +238,39 @@ public long timestampMicros() { } } - MockSpan(MockTracer tracer, String operationName, long startMicros, Map initialTags, MockContext parent) { + public static final class Reference { + private final MockContext context; + private final String referenceType; + + public Reference(MockContext context, String referenceType) { + this.context = context; + this.referenceType = referenceType; + } + + public MockContext getContext() { + return context; + } + + public String getReferenceType() { + return referenceType; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + Reference reference = (Reference) o; + return Objects.equals(context, reference.context) && + Objects.equals(referenceType, reference.referenceType); + } + + @Override + public int hashCode() { + return Objects.hash(context, referenceType); + } + } + + MockSpan(MockTracer tracer, String operationName, long startMicros, Map initialTags, List refs) { this.mockTracer = tracer; this.operationName = operationName; this.startMicros = startMicros; @@ -241,17 +279,45 @@ public long timestampMicros() { } else { this.tags = new HashMap<>(initialTags); } + if(refs == null) { + this.references = Collections.emptyList(); + } else { + this.references = new ArrayList<>(refs); + } + MockContext parent = findPreferredParentRef(this.references); if (parent == null) { // We're a root Span. this.context = new MockContext(nextId(), nextId(), new HashMap()); this.parentId = 0; } else { // We're a child Span. - this.context = new MockContext(parent.traceId, nextId(), parent.baggage); + this.context = new MockContext(parent.traceId, nextId(), mergeBaggages(this.references)); this.parentId = parent.spanId; } } + private static MockContext findPreferredParentRef(List references) { + if(references.isEmpty()) { + return null; + } + for (Reference reference : references) { + if (References.CHILD_OF.equals(reference.getReferenceType())) { + return reference.getContext(); + } + } + return references.get(0).getContext(); + } + + private static Map mergeBaggages(List references) { + Map baggage = new HashMap<>(); + for(Reference ref : references) { + if(ref.getContext().baggage != null) { + baggage.putAll(ref.getContext().baggage); + } + } + return baggage; + } + static long nextId() { return nextId.addAndGet(1); } 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 97de5ebc..042d20ad 100644 --- a/opentracing-mock/src/main/java/io/opentracing/mock/MockTracer.java +++ b/opentracing-mock/src/main/java/io/opentracing/mock/MockTracer.java @@ -205,7 +205,7 @@ synchronized void appendFinishedSpan(MockSpan mockSpan) { public final class SpanBuilder implements Tracer.SpanBuilder { private final String operationName; private long startMicros; - private MockSpan.MockContext firstParent; + private List references = new ArrayList<>(); private boolean ignoringActiveSpan; private Map initialTags = new HashMap<>(); @@ -231,9 +231,8 @@ public SpanBuilder ignoreActiveSpan() { @Override 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; + if (referencedContext != null) { + this.references.add(new MockSpan.Reference((MockSpan.MockContext) referencedContext, referenceType)); } return this; } @@ -279,10 +278,11 @@ public MockSpan startManual() { if (this.startMicros == 0) { this.startMicros = MockSpan.nowMicros(); } - if (firstParent == null && !ignoringActiveSpan) { - firstParent = (MockSpan.MockContext) activeSpanContext(); + SpanContext activeSpanContext = activeSpanContext(); + if(references.isEmpty() && !ignoringActiveSpan && activeSpanContext != null) { + references.add(new MockSpan.Reference((MockSpan.MockContext) activeSpanContext, References.CHILD_OF)); } - return new MockSpan(MockTracer.this, operationName, startMicros, initialTags, firstParent); + return new MockSpan(MockTracer.this, operationName, startMicros, initialTags, references); } } } 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 42df1bac..2f2a410b 100644 --- a/opentracing-mock/src/test/java/io/opentracing/mock/MockTracerTest.java +++ b/opentracing-mock/src/test/java/io/opentracing/mock/MockTracerTest.java @@ -16,6 +16,7 @@ import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotEquals; +import io.opentracing.References; import io.opentracing.Span; import io.opentracing.SpanContext; import io.opentracing.Tracer; @@ -209,4 +210,73 @@ public void testReset() { mockTracer.reset(); assertEquals(0, mockTracer.finishedSpans().size()); } + + @Test + public void testFollowFromReference() { + MockTracer tracer = new MockTracer(MockTracer.Propagator.TEXT_MAP); + final MockSpan precedent = tracer.buildSpan("precedent").startManual(); + + final MockSpan followingSpan = tracer.buildSpan("follows") + .addReference(References.FOLLOWS_FROM, precedent.context()) + .startManual(); + + assertEquals(precedent.context().spanId(), followingSpan.parentId()); + assertEquals(1, followingSpan.references().size()); + + final MockSpan.Reference followsFromRef = followingSpan.references().get(0); + + assertEquals(new MockSpan.Reference(precedent.context(), References.FOLLOWS_FROM), followsFromRef); + } + + @Test + public void testMultiReferences() { + MockTracer tracer = new MockTracer(MockTracer.Propagator.TEXT_MAP); + final MockSpan parent = tracer.buildSpan("parent").startManual(); + final MockSpan precedent = tracer.buildSpan("precedent").startManual(); + + final MockSpan followingSpan = tracer.buildSpan("follows") + .addReference(References.FOLLOWS_FROM, precedent.context()) + .asChildOf(parent.context()) + .startManual(); + + assertEquals(parent.context().spanId(), followingSpan.parentId()); + assertEquals(2, followingSpan.references().size()); + + final MockSpan.Reference followsFromRef = followingSpan.references().get(0); + final MockSpan.Reference parentRef = followingSpan.references().get(1); + + assertEquals(new MockSpan.Reference(precedent.context(), References.FOLLOWS_FROM), followsFromRef); + assertEquals(new MockSpan.Reference(parent.context(), References.CHILD_OF), parentRef); + } + + @Test + public void testMultiReferencesBaggage() { + MockTracer tracer = new MockTracer(MockTracer.Propagator.TEXT_MAP); + final MockSpan parent = tracer.buildSpan("parent").startManual(); + parent.setBaggageItem("parent", "foo"); + final MockSpan precedent = tracer.buildSpan("precedent").startManual(); + precedent.setBaggageItem("precedent", "bar"); + + final MockSpan followingSpan = tracer.buildSpan("follows") + .addReference(References.FOLLOWS_FROM, precedent.context()) + .asChildOf(parent.context()) + .startManual(); + + assertEquals("foo", followingSpan.getBaggageItem("parent")); + assertEquals("bar", followingSpan.getBaggageItem("precedent")); + } + + @Test + public void testNonStandardReference() { + MockTracer tracer = new MockTracer(MockTracer.Propagator.TEXT_MAP); + final MockSpan parent = tracer.buildSpan("parent").startManual(); + + final MockSpan nextSpan = tracer.buildSpan("follows") + .addReference("a_reference", parent.context()) + .startManual(); + + assertEquals(parent.context().spanId(), nextSpan.parentId()); + assertEquals(1, nextSpan.references().size()); + assertEquals(nextSpan.references().get(0), new MockSpan.Reference(parent.context(), "a_reference")); + } } From 9b34341d40dadcb489d1152c82be2b0b9f560c02 Mon Sep 17 00:00:00 2001 From: Sjoerd Talsma Date: Thu, 30 Nov 2017 16:27:26 +0100 Subject: [PATCH 03/19] Publish test artifact for Globaltracer testutil (#209) --- opentracing-util/pom.xml | 20 ++++++ .../io/opentracing/util/GlobalTracerTest.java | 15 +---- .../util/GlobalTracerTestUtil.java | 67 +++++++++++++++++++ 3 files changed, 88 insertions(+), 14 deletions(-) create mode 100644 opentracing-util/src/test/java/io/opentracing/util/GlobalTracerTestUtil.java diff --git a/opentracing-util/pom.xml b/opentracing-util/pom.xml index 846fc8b8..3ece08ea 100644 --- a/opentracing-util/pom.xml +++ b/opentracing-util/pom.xml @@ -42,4 +42,24 @@ opentracing-noop + + + + + maven-jar-plugin + + + + test-jar + + + + **/*TestUtil.* + + + + + + + diff --git a/opentracing-util/src/test/java/io/opentracing/util/GlobalTracerTest.java b/opentracing-util/src/test/java/io/opentracing/util/GlobalTracerTest.java index 9fea040e..36e136b5 100644 --- a/opentracing-util/src/test/java/io/opentracing/util/GlobalTracerTest.java +++ b/opentracing-util/src/test/java/io/opentracing/util/GlobalTracerTest.java @@ -29,9 +29,7 @@ import io.opentracing.SpanContext; import io.opentracing.Tracer; import io.opentracing.noop.NoopSpanBuilder; -import io.opentracing.noop.NoopTracerFactory; import io.opentracing.propagation.Format; -import java.lang.reflect.Field; import java.util.ArrayList; import java.util.List; import java.util.concurrent.Callable; @@ -45,21 +43,10 @@ public class GlobalTracerTest { - private static void _setGlobal(Tracer tracer) { - try { - Field globalTracerField = GlobalTracer.class.getDeclaredField("tracer"); - globalTracerField.setAccessible(true); - globalTracerField.set(null, tracer); - globalTracerField.setAccessible(false); - } catch (Exception e) { - throw new RuntimeException("Error reflecting globalTracer: " + e.getMessage(), e); - } - } - @Before @After public void clearGlobalTracer() { - _setGlobal(NoopTracerFactory.create()); + GlobalTracerTestUtil.resetGlobalTracer(); } @Test diff --git a/opentracing-util/src/test/java/io/opentracing/util/GlobalTracerTestUtil.java b/opentracing-util/src/test/java/io/opentracing/util/GlobalTracerTestUtil.java new file mode 100644 index 00000000..13080e3f --- /dev/null +++ b/opentracing-util/src/test/java/io/opentracing/util/GlobalTracerTestUtil.java @@ -0,0 +1,67 @@ +/* + * Copyright 2016-2017 The OpenTracing Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License + * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the License for the specific language governing permissions and limitations under + * the License. + */ +package io.opentracing.util; + +import io.opentracing.Tracer; +import io.opentracing.noop.NoopTracerFactory; + +import java.lang.reflect.Field; + +/** + * Utility class for manipulating the {@link GlobalTracer} when testing. + *

+ * The {@linkplain GlobalTracer} has register-once semantics, but for testing purposes it is useful to + * manipulate the globaltracer to guarantee certain preconditions. + *

+ * The {@code GlobalTracerTestUtil} can be included in your own code by adding the following dependency: + *


+ *     <dependency>
+ *         <groupId>io.opentracing</groupId>
+ *         <artifactId>opentracing-util</artifactId>
+ *         <version>version</version>
+ *         <type>test-jar</type>
+ *         <scope>test</scope>
+ *      </dependency>
+ * 
+ */ +public class GlobalTracerTestUtil { + + private GlobalTracerTestUtil() { + throw new UnsupportedOperationException("Cannot instantiate static test utility class."); + } + + /** + * Resets the {@link GlobalTracer} to its initial, unregistered state. + */ + public static void resetGlobalTracer() { + setGlobalTracerUnconditionally(NoopTracerFactory.create()); + } + + /** + * Unconditionally sets the {@link GlobalTracer} to the specified {@link Tracer tracer} instance. + * + * @param tracer The tracer to become the GlobalTracer's delegate. + */ + public static void setGlobalTracerUnconditionally(Tracer tracer) { + try { + Field globalTracerField = GlobalTracer.class.getDeclaredField("tracer"); + globalTracerField.setAccessible(true); + globalTracerField.set(null, tracer); + globalTracerField.setAccessible(false); + } catch (Exception e) { + throw new IllegalStateException("Error reflecting GlobalTracer.tracer: " + e.getMessage(), e); + } + } + +} From 22f0eae2431eddb24db6cc0e7a7e8396abc8b9a4 Mon Sep 17 00:00:00 2001 From: Ivan Kirichenko Date: Fri, 1 Dec 2017 10:34:48 +0100 Subject: [PATCH 04/19] Fix MockTracer.ChildOf not fail if there is a null argument passed (#226) * Make ChildOf not fail if there is a null argument passed * Moved tracer test to where it belongs. Fixed typo. --- .../src/main/java/io/opentracing/mock/MockTracer.java | 3 +++ .../src/test/java/io/opentracing/mock/MockTracerTest.java | 8 ++++++++ 2 files changed, 11 insertions(+) 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 042d20ad..e6af3df4 100644 --- a/opentracing-mock/src/main/java/io/opentracing/mock/MockTracer.java +++ b/opentracing-mock/src/main/java/io/opentracing/mock/MockTracer.java @@ -220,6 +220,9 @@ public SpanBuilder asChildOf(SpanContext parent) { @Override public SpanBuilder asChildOf(BaseSpan parent) { + if (parent == null) { + return this; + } return addReference(References.CHILD_OF, parent.context()); } 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 2f2a410b..b7960106 100644 --- a/opentracing-mock/src/test/java/io/opentracing/mock/MockTracerTest.java +++ b/opentracing-mock/src/test/java/io/opentracing/mock/MockTracerTest.java @@ -279,4 +279,12 @@ public void testNonStandardReference() { assertEquals(1, nextSpan.references().size()); assertEquals(nextSpan.references().get(0), new MockSpan.Reference(parent.context(), "a_reference")); } + + @Test + public void testChildOfWithNullParentDoesNotThrowException() { + MockTracer tracer = new MockTracer(); + final Span parent = null; + Span span = tracer.buildSpan("foo").asChildOf(parent).start(); + span.finish(); + } } From 473578d358a02ce1bb3aa8b990f9d0a2ab9346d6 Mon Sep 17 00:00:00 2001 From: Will Sargent Date: Tue, 12 Dec 2017 21:07:17 -0800 Subject: [PATCH 05/19] Use correct reference in Javadoc (#230) --- .../src/main/java/io/opentracing/propagation/Format.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 1daaa10a..d1b55483 100644 --- a/opentracing-api/src/main/java/io/opentracing/propagation/Format.java +++ b/opentracing-api/src/main/java/io/opentracing/propagation/Format.java @@ -27,7 +27,7 @@ *

  * Tracer tracer = ...
  * io.opentracing.propagation.HttpHeaders httpCarrier = new AnHttpHeaderCarrier(httpRequest);
- * SpanContext spanCtx = tracer.extract(Format.Builtin.HTTP_HEADERS, httpHeaderReader);
+ * SpanContext spanCtx = tracer.extract(Format.Builtin.HTTP_HEADERS, httpCarrier);
  * 
* * @see Tracer#inject(SpanContext, Format, Object) From 84e22d04158661e5fda442abba7ce72d826bd0a8 Mon Sep 17 00:00:00 2001 From: Pavol Loffay Date: Thu, 14 Dec 2017 11:32:45 -0600 Subject: [PATCH 06/19] MockTracer use text map propag in the default constructor (#179) --- .../java/io/opentracing/mock/MockTracer.java | 20 ++++++------- .../io/opentracing/mock/MockTracerTest.java | 28 +++++++++++++++---- 2 files changed, 32 insertions(+), 16 deletions(-) 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 e6af3df4..50024ab9 100644 --- a/opentracing-mock/src/main/java/io/opentracing/mock/MockTracer.java +++ b/opentracing-mock/src/main/java/io/opentracing/mock/MockTracer.java @@ -13,23 +13,23 @@ */ package io.opentracing.mock; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + import io.opentracing.ActiveSpan; import io.opentracing.ActiveSpanSource; import io.opentracing.BaseSpan; -import io.opentracing.noop.NoopActiveSpanSource; import io.opentracing.References; import io.opentracing.Span; import io.opentracing.SpanContext; import io.opentracing.Tracer; +import io.opentracing.noop.NoopActiveSpanSource; import io.opentracing.propagation.Format; import io.opentracing.propagation.TextMap; import io.opentracing.util.ThreadLocalActiveSpanSource; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - /** * MockTracer makes it easy to test the semantics of OpenTracing instrumentation. * @@ -39,16 +39,16 @@ * The MockTracerTest has simple usage examples. */ public class MockTracer implements Tracer { - private List finishedSpans = new ArrayList<>(); + private final List finishedSpans = new ArrayList<>(); private final Propagator propagator; - private ActiveSpanSource spanSource; + private final ActiveSpanSource spanSource; public MockTracer() { - this(new ThreadLocalActiveSpanSource(), Propagator.PRINTER); + this(new ThreadLocalActiveSpanSource(), Propagator.TEXT_MAP); } public MockTracer(ActiveSpanSource spanSource) { - this(spanSource, Propagator.PRINTER); + this(spanSource, Propagator.TEXT_MAP); } public MockTracer(ActiveSpanSource spanSource, Propagator propagator) { 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 b7960106..e4d8749f 100644 --- a/opentracing-mock/src/test/java/io/opentracing/mock/MockTracerTest.java +++ b/opentracing-mock/src/test/java/io/opentracing/mock/MockTracerTest.java @@ -14,20 +14,24 @@ package io.opentracing.mock; import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotEquals; import io.opentracing.References; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import org.junit.Assert; +import org.junit.Test; + +import io.opentracing.ActiveSpan; import io.opentracing.Span; import io.opentracing.SpanContext; import io.opentracing.Tracer; import io.opentracing.propagation.Format; import io.opentracing.propagation.TextMapExtractAdapter; import io.opentracing.propagation.TextMapInjectAdapter; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import org.junit.Assert; -import org.junit.Test; public class MockTracerTest { @Test @@ -277,7 +281,19 @@ public void testNonStandardReference() { assertEquals(parent.context().spanId(), nextSpan.parentId()); assertEquals(1, nextSpan.references().size()); - assertEquals(nextSpan.references().get(0), new MockSpan.Reference(parent.context(), "a_reference")); + assertEquals(nextSpan.references().get(0), + new MockSpan.Reference(parent.context(), "a_reference")); + } + + @Test + public void testDefaultConstructor() { + MockTracer mockTracer = new MockTracer(); + ActiveSpan activeSpan = mockTracer.buildSpan("foo").startActive(); + assertEquals(activeSpan, mockTracer.activeSpan()); + + Map propag = new HashMap<>(); + mockTracer.inject(activeSpan.context(), Format.Builtin.TEXT_MAP, new TextMapInjectAdapter(propag)); + assertFalse(propag.isEmpty()); } @Test From 9ef9161dbb7a98fd330d7c96b4fb97cf42d93a8b Mon Sep 17 00:00:00 2001 From: Carlos Alberto Cortez Date: Tue, 26 Sep 2017 01:23:11 +0900 Subject: [PATCH 07/19] Implement a simpler Span propagation without lifetime handling. (#188) - Scope replaces ActiveSpan, without sharing a common ancestor with Span. - ScopeManager replaces ActiveSpanSource. - No reference-count to handle Span's lifetime. - A simple thread-local based ScopeManager. --- .../main/java/io/opentracing/ActiveSpan.java | 109 ------------- .../java/io/opentracing/ActiveSpanSource.java | 50 ------ .../main/java/io/opentracing/BaseSpan.java | 143 ----------------- .../src/main/java/io/opentracing/Scope.java | 43 +++++ .../java/io/opentracing/ScopeManager.java | 57 +++++++ .../src/main/java/io/opentracing/Span.java | 130 ++++++++++++++- .../src/main/java/io/opentracing/Tracer.java | 87 +++++++--- .../java/io/opentracing/tag/AbstractTag.java | 4 +- .../java/io/opentracing/tag/BooleanTag.java | 4 +- .../io/opentracing/tag/IntOrStringTag.java | 4 +- .../main/java/io/opentracing/tag/IntTag.java | 4 +- .../java/io/opentracing/tag/StringTag.java | 6 +- .../io/opentracing/tag/AbstractTagTest.java | 16 +- .../opentracing/examples/AutoFinishScope.java | 66 ++++++++ .../examples/AutoFinishScopeManager.java | 29 ++-- .../activate_deactivate/RunnableAction.java | 14 +- .../ScheduledActionsTest.java | 17 +- .../ActiveSpanReplacementTest.java | 24 +-- .../examples/client_server/Client.java | 6 +- .../examples/client_server/Server.java | 4 +- .../client_server/TestClientServerTest.java | 6 +- .../common_request_handler/HandlerTest.java | 14 +- .../late_span_finish/LateSpanFinishTest.java | 18 +-- .../listener_per_request/ListenerTest.java | 6 +- .../examples/multiple_callbacks/Client.java | 14 +- .../MultipleCallbacksTest.java | 16 +- .../nested_callbacks/NestedCallbacksTest.java | 24 ++- .../java/io/opentracing/mock/MockTracer.java | 61 ++++--- .../io/opentracing/mock/MockTracerTest.java | 8 +- .../noop/NoopActiveSpanSource.java | 120 -------------- .../io/opentracing/noop/NoopScopeManager.java | 56 +++++++ .../io/opentracing/noop/NoopSpanBuilder.java | 21 +-- .../java/io/opentracing/noop/NoopTracer.java | 18 +-- .../io/opentracing/util/GlobalTracer.java | 18 +-- .../util/ThreadLocalActiveSpan.java | 149 ------------------ .../io/opentracing/util/ThreadLocalScope.java | 58 +++++++ .../util/ThreadLocalScopeManager.java | 42 +++++ .../util/ThreadLocalActiveSpanSourceTest.java | 60 ------- .../util/ThreadLocalScopeManagerTest.java | 102 ++++++++++++ ...panTest.java => ThreadLocalScopeTest.java} | 58 ++----- 40 files changed, 787 insertions(+), 899 deletions(-) delete mode 100644 opentracing-api/src/main/java/io/opentracing/ActiveSpan.java delete mode 100644 opentracing-api/src/main/java/io/opentracing/ActiveSpanSource.java delete mode 100644 opentracing-api/src/main/java/io/opentracing/BaseSpan.java create mode 100644 opentracing-api/src/main/java/io/opentracing/Scope.java create mode 100644 opentracing-api/src/main/java/io/opentracing/ScopeManager.java create mode 100644 opentracing-examples/src/test/java/io/opentracing/examples/AutoFinishScope.java rename opentracing-util/src/main/java/io/opentracing/util/ThreadLocalActiveSpanSource.java => opentracing-examples/src/test/java/io/opentracing/examples/AutoFinishScopeManager.java (51%) delete mode 100644 opentracing-noop/src/main/java/io/opentracing/noop/NoopActiveSpanSource.java create mode 100644 opentracing-noop/src/main/java/io/opentracing/noop/NoopScopeManager.java delete mode 100644 opentracing-util/src/main/java/io/opentracing/util/ThreadLocalActiveSpan.java create mode 100644 opentracing-util/src/main/java/io/opentracing/util/ThreadLocalScope.java create mode 100644 opentracing-util/src/main/java/io/opentracing/util/ThreadLocalScopeManager.java delete mode 100644 opentracing-util/src/test/java/io/opentracing/util/ThreadLocalActiveSpanSourceTest.java create mode 100644 opentracing-util/src/test/java/io/opentracing/util/ThreadLocalScopeManagerTest.java rename opentracing-util/src/test/java/io/opentracing/util/{ThreadLocalActiveSpanTest.java => ThreadLocalScopeTest.java} (56%) diff --git a/opentracing-api/src/main/java/io/opentracing/ActiveSpan.java b/opentracing-api/src/main/java/io/opentracing/ActiveSpan.java deleted file mode 100644 index 46e09d08..00000000 --- a/opentracing-api/src/main/java/io/opentracing/ActiveSpan.java +++ /dev/null @@ -1,109 +0,0 @@ -/* - * Copyright 2016-2017 The OpenTracing Authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except - * in compliance with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software distributed under the License - * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express - * or implied. See the License for the specific language governing permissions and limitations under - * the License. - */ -package io.opentracing; - -import java.io.Closeable; - -/** - * {@link ActiveSpan} inherits all of the OpenTracing functionality in {@link BaseSpan} and layers on in-process - * propagation capabilities. - * - *

- * In any given thread there is at most one {@link ActiveSpan "active" span} primarily responsible for the work - * accomplished by the surrounding application code. That {@link ActiveSpan} may be accessed via the - * {@link ActiveSpanSource#activeSpan()} method. If the application needs to defer work that should be part of - * the same Span, the Source provides a {@link ActiveSpan#capture} method that returns a {@link Continuation}; - * this continuation may be used to re-activate and continue the {@link Span} in that other asynchronous executor - * and/or thread. - * - *

- * {@link ActiveSpan}s are created via {@link Tracer.SpanBuilder#startActive()} or, less commonly, - * {@link ActiveSpanSource#makeActive}. Per the above, they can be {@link ActiveSpan#capture()}ed as - * {@link ActiveSpan.Continuation}s, then re-{@link Continuation#activate()}d later. - * - *

- * NOTE: {@link ActiveSpan} extends {@link Closeable} rather than {@code AutoCloseable} in order to preserve support - * for JDK1.6. - * - * @see Tracer.SpanBuilder#startActive() - * @see Continuation#activate() - * @see ActiveSpanSource - * @see BaseSpan - * @see Span - */ -public interface ActiveSpan extends Closeable, BaseSpan { - /** - * Mark the end of the active period for the current thread and {@link ActiveSpan}. When the last - * {@link ActiveSpan} is deactivated for a given {@link Span}, it is automatically {@link Span#finish()}ed. - * - *

- * NOTE: Calling {@link #deactivate} more than once on a single {@link ActiveSpan} instance leads to undefined - * behavior. - * - * @see Closeable#close() {@link ActiveSpan}s are auto-closeable and may be used in try-with-resources blocks - */ - void deactivate(); - - /** - * A synonym for {@link #deactivate()} that can be used in try-with-resources blocks. - */ - @Override - void close(); - - /** - * "Capture" a new {@link Continuation} associated with this {@link ActiveSpan} and {@link Span}, as well as any - * 3rd-party execution context of interest. The {@link Continuation} may be used as data in a closure or callback - * function where the {@link ActiveSpan} may be resumed and reactivated. - * - *

- * IMPORTANT: the caller MUST {@link Continuation#activate()} and {@link ActiveSpan#deactivate()} the - * returned {@link Continuation} or the associated {@link Span} will never automatically {@link Span#finish()}. - * That is, calling {@link #capture()} increments a refcount that must be decremented somewhere else. - * - *

- * The associated {@link Span} will not {@link Span#finish()} while a {@link Continuation} is outstanding; in - * this way, it provides a reference/pin just like an {@link ActiveSpan} does. - * - * @return a new {@link Continuation} to {@link Continuation#activate()} at the appropriate time. - */ - Continuation capture(); - - /** - * A {@link Continuation} can be used once to activate a Span along with any non-OpenTracing execution - * context (e.g., MDC), then deactivate when processing activity moves on to another Span. (In practice, this - * active period typically extends for the length of a deferred async closure invocation.) - * - *

- * Most users do not directly interact with {@link Continuation}, {@link Continuation#activate()} or - * {@link ActiveSpan#deactivate()}, but rather use {@link ActiveSpanSource}-aware Runnables/Callables/Executors. - * Those higher-level primitives do not need to be defined within the OpenTracing core API, and so - * they are not. - * - * @see ActiveSpanSource#makeActive(Span) - */ - interface Continuation { - /** - * Make the Span (and other execution context) encapsulated by this {@link Continuation} active and - * return it. - * - *

- * NOTE: It is an error to call activate() more than once on a single Continuation instance. - * - * @see ActiveSpanSource#makeActive(Span) - * @return a handle to the newly-activated {@link ActiveSpan} - */ - ActiveSpan activate(); - } - -} diff --git a/opentracing-api/src/main/java/io/opentracing/ActiveSpanSource.java b/opentracing-api/src/main/java/io/opentracing/ActiveSpanSource.java deleted file mode 100644 index 334d00e8..00000000 --- a/opentracing-api/src/main/java/io/opentracing/ActiveSpanSource.java +++ /dev/null @@ -1,50 +0,0 @@ -/* - * Copyright 2016-2017 The OpenTracing Authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except - * in compliance with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software distributed under the License - * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express - * or implied. See the License for the specific language governing permissions and limitations under - * the License. - */ -package io.opentracing; - -/** - * {@link ActiveSpanSource} allows an existing (possibly thread-local-aware) execution context provider to act as a - * source for an actively-scheduled OpenTracing Span. - * - *

- * {@link ActiveSpanSource} is a super-interface to {@link Tracer}, so note that all {@link Tracer}s fulfill the - * {@link ActiveSpanSource} contract. - * - * @see ActiveSpan - */ -public interface ActiveSpanSource { - - /** - * Return the {@link ActiveSpan active span}. This does not affect the internal reference count for the - * {@link ActiveSpan}. - * - *

- * If there is an {@link ActiveSpan active span}, it becomes an implicit parent of any newly-created - * {@link BaseSpan span} at {@link Tracer.SpanBuilder#startActive()} time (rather than at - * {@link Tracer#buildSpan(String)} time). - * - * @return the {@link ActiveSpan active span}, or null if none could be found. - */ - ActiveSpan activeSpan(); - - /** - * Wrap and "make active" a {@link Span} by encapsulating it – and any active state (e.g., MDC state) in the - * current thread – in a new {@link ActiveSpan}. - * - * @param span the Span to wrap in an {@link ActiveSpan} - * @return an {@link ActiveSpan} that encapsulates the given {@link Span} and any other - * {@link ActiveSpanSource}-specific context (e.g., the MDC context map) - */ - ActiveSpan makeActive(Span span); -} diff --git a/opentracing-api/src/main/java/io/opentracing/BaseSpan.java b/opentracing-api/src/main/java/io/opentracing/BaseSpan.java deleted file mode 100644 index b83bc190..00000000 --- a/opentracing-api/src/main/java/io/opentracing/BaseSpan.java +++ /dev/null @@ -1,143 +0,0 @@ -/* - * Copyright 2016-2017 The OpenTracing Authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except - * in compliance with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software distributed under the License - * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express - * or implied. See the License for the specific language governing permissions and limitations under - * the License. - */ -package io.opentracing; - -import java.util.Map; - -/** - * {@link BaseSpan} represents the OpenTracing specification's span contract with the exception of methods to finish - * said span. For those, either use {@link Span#finish()} or {@link ActiveSpan#deactivate()} depending on the - * programming model. - * - * @see Span - * @see ActiveSpan - * @see Tracer.SpanBuilder#startManual() - * @see Tracer.SpanBuilder#startActive() - */ -public interface BaseSpan { - /** - * Retrieve the associated SpanContext. - * - * This may be called at any time, including after calls to finish(). - * - * @return the SpanContext that encapsulates Span state that should propagate across process boundaries. - */ - SpanContext context(); - - /** - * Set a key:value tag on the Span. - */ - S setTag(String key, String value); - - /** Same as {@link #setTag(String, String)}, but for boolean values. */ - S setTag(String key, boolean value); - - /** Same as {@link #setTag(String, String)}, but for numeric values. */ - S setTag(String key, Number value); - - /** - * Log key:value pairs to the Span with the current walltime timestamp. - * - *

CAUTIONARY NOTE: not all Tracer implementations support key:value log fields end-to-end. - * Caveat emptor. - * - *

A contrived example (using Guava, which is not required): - *


-     span.log(
-     ImmutableMap.Builder()
-     .put("event", "soft error")
-     .put("type", "cache timeout")
-     .put("waited.millis", 1500)
-     .build());
-     
- * - * @param fields key:value log fields. Tracer implementations should support String, numeric, and boolean values; - * some may also support arbitrary Objects. - * @return the Span, for chaining - * @see Span#log(String) - */ - S log(Map fields); - - /** - * Like log(Map<String, Object>), but with an explicit timestamp. - * - *

CAUTIONARY NOTE: not all Tracer implementations support key:value log fields end-to-end. - * Caveat emptor. - * - * @param timestampMicroseconds The explicit timestamp for the log record. Must be greater than or equal to the - * Span's start timestamp. - * @param fields key:value log fields. Tracer implementations should support String, numeric, and boolean values; - * some may also support arbitrary Objects. - * @return the Span, for chaining - * @see Span#log(long, String) - */ - S log(long timestampMicroseconds, Map fields); - - /** - * Record an event at the current walltime timestamp. - * - * Shorthand for - * - *


-     span.log(Collections.singletonMap("event", event));
-     
- * - * @param event the event value; often a stable identifier for a moment in the Span lifecycle - * @return the Span, for chaining - */ - S log(String event); - - /** - * Record an event at a specific timestamp. - * - * Shorthand for - * - *

-     span.log(timestampMicroseconds, Collections.singletonMap("event", event));
-     
- * - * @param timestampMicroseconds The explicit timestamp for the log record. Must be greater than or equal to the - * Span's start timestamp. - * @param event the event value; often a stable identifier for a moment in the Span lifecycle - * @return the Span, for chaining - */ - S log(long timestampMicroseconds, String event); - - /** - * Sets a baggage item in the Span (and its SpanContext) as a key/value pair. - * - * Baggage enables powerful distributed context propagation functionality where arbitrary application data can be - * carried along the full path of request execution throughout the system. - * - * Note 1: Baggage is only propagated to the future (recursive) children of this SpanContext. - * - * Note 2: Baggage is sent in-band with every subsequent local and remote calls, so this feature must be used with - * care. - * - * @return this Span instance, for chaining - */ - S setBaggageItem(String key, String value); - - /** - * @return the value of the baggage item identified by the given key, or null if no such item could be found - */ - String getBaggageItem(String key); - - /** - * Sets the string name for the logical operation this span represents. - * - * @return this Span instance, for chaining - */ - S setOperationName(String operationName); -} diff --git a/opentracing-api/src/main/java/io/opentracing/Scope.java b/opentracing-api/src/main/java/io/opentracing/Scope.java new file mode 100644 index 00000000..dd997647 --- /dev/null +++ b/opentracing-api/src/main/java/io/opentracing/Scope.java @@ -0,0 +1,43 @@ +/* + * Copyright 2016-2017 The OpenTracing Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License + * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the License for the specific language governing permissions and limitations under + * the License. + */ +package io.opentracing; + +import java.io.Closeable; + +/** + * A {@link Scope} formalizes the activation and deactivation of a {@link Span}, usually from a CPU standpoint. + * + *

+ * Many times a {@link Span} will be extant (in that {@link Span#finish()} has not been called) despite being in a + * non-runnable state from a CPU/scheduler standpoint. For instance, a {@link Span} representing the client side of an + * RPC will be unfinished but blocked on IO while the RPC is still outstanding. A {@link Scope} defines when a given + * {@link Span} is scheduled and on the path. + */ +public interface Scope extends Closeable { + /** + * Mark the end of the active period for the current thread and {@link Scope}, + * updating the {@link ScopeManager#active()} in the process. + * + *

+ * NOTE: Calling {@link #close} more than once on a single {@link Scope} instance leads to undefined + * behavior. + */ + @Override + void close(); + + /** + * @return the {@link Span} that's been scoped by this {@link Scope} + */ + Span span(); +} diff --git a/opentracing-api/src/main/java/io/opentracing/ScopeManager.java b/opentracing-api/src/main/java/io/opentracing/ScopeManager.java new file mode 100644 index 00000000..bcd6e922 --- /dev/null +++ b/opentracing-api/src/main/java/io/opentracing/ScopeManager.java @@ -0,0 +1,57 @@ +/* + * Copyright 2016-2017 The OpenTracing Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License + * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the License for the specific language governing permissions and limitations under + * the License. + */ +package io.opentracing; + +/** + * The {@link ScopeManager} interface abstracts both the activation of {@link Span} instances (via + * {@link ScopeManager#activate(Span)}) and access to an active {@link Span}/{@link Scope} + * (via {@link ScopeManager#active()}). + * + * @see Scope + * @see Tracer#scopeManager() + */ +public interface ScopeManager { + /** + * Make a {@link Span} instance active. + * + * @param span the {@link Span} that should become the {@link #active()} + * @return a {@link Scope} instance to control the end of the active period for the {@link Span}. + * Span will automatically be finished when {@link Scope#close()} is called. It is a + * programming error to neglect to call {@link Scope#close()} on the returned instance. + */ + Scope activate(Span span); + + /** + * Make a {@link Span} instance active. + * + * @param span the {@link Span} that should become the {@link #active()} + * @param finishSpanOnClose whether span should automatically be finished when {@link Scope#close()} is called + * @return a {@link Scope} instance to control the end of the active period for the {@link Span}. It is a + * programming error to neglect to call {@link Scope#close()} on the returned instance. + */ + Scope activate(Span span, boolean finishSpanOnClose); + + /** + * Return the currently active {@link Scope} which can be used to access the currently active + * {@link Scope#span()}. + * + *

+ * If there is an {@link Scope non-null scope}, its wrapped {@link Span} becomes an implicit parent of any + * newly-created {@link Span} at {@link Tracer.SpanBuilder#startActive()} time (rather than at + * {@link Tracer#buildSpan(String)} time). + * + * @return the {@link Scope active scope}, or null if none could be found. + */ + Scope active(); +} diff --git a/opentracing-api/src/main/java/io/opentracing/Span.java b/opentracing-api/src/main/java/io/opentracing/Span.java index 026c4ce5..548ac4f8 100644 --- a/opentracing-api/src/main/java/io/opentracing/Span.java +++ b/opentracing-api/src/main/java/io/opentracing/Span.java @@ -13,16 +13,132 @@ */ package io.opentracing; +import java.util.Map; + /** - * Represents an in-flight Span that's manually propagated within the given process. Most of - * the API lives in {@link BaseSpan}. - * - *

{@link Span}s are created by the {@link Tracer.SpanBuilder#startManual} method; see {@link ActiveSpan} for - * a {@link BaseSpan} extension designed for automatic in-process propagation. + * {@link Span} represents the OpenTracing specification's Span contract. * - * @see ActiveSpan for automatic propagation (recommended for most intstrumentation!) + * @see Scope + * @see ScopeManager + * @see Tracer.SpanBuilder#startManual() + * @see Tracer.SpanBuilder#startActive() */ -public interface Span extends BaseSpan { +public interface Span { + /** + * Retrieve the associated SpanContext. + * + * This may be called at any time, including after calls to finish(). + * + * @return the SpanContext that encapsulates Span state that should propagate across process boundaries. + */ + SpanContext context(); + + /** + * Set a key:value tag on the Span. + */ + Span setTag(String key, String value); + + /** Same as {@link #setTag(String, String)}, but for boolean values. */ + Span setTag(String key, boolean value); + + /** Same as {@link #setTag(String, String)}, but for numeric values. */ + Span setTag(String key, Number value); + + /** + * Log key:value pairs to the Span with the current walltime timestamp. + * + *

CAUTIONARY NOTE: not all Tracer implementations support key:value log fields end-to-end. + * Caveat emptor. + * + *

A contrived example (using Guava, which is not required): + *


+     span.log(
+     ImmutableMap.Builder()
+     .put("event", "soft error")
+     .put("type", "cache timeout")
+     .put("waited.millis", 1500)
+     .build());
+     
+ * + * @param fields key:value log fields. Tracer implementations should support String, numeric, and boolean values; + * some may also support arbitrary Objects. + * @return the Span, for chaining + * @see Span#log(String) + */ + Span log(Map fields); + + /** + * Like log(Map<String, Object>), but with an explicit timestamp. + * + *

CAUTIONARY NOTE: not all Tracer implementations support key:value log fields end-to-end. + * Caveat emptor. + * + * @param timestampMicroseconds The explicit timestamp for the log record. Must be greater than or equal to the + * Span's start timestamp. + * @param fields key:value log fields. Tracer implementations should support String, numeric, and boolean values; + * some may also support arbitrary Objects. + * @return the Span, for chaining + * @see Span#log(long, String) + */ + Span log(long timestampMicroseconds, Map fields); + + /** + * Record an event at the current walltime timestamp. + * + * Shorthand for + * + *


+     span.log(Collections.singletonMap("event", event));
+     
+ * + * @param event the event value; often a stable identifier for a moment in the Span lifecycle + * @return the Span, for chaining + */ + Span log(String event); + + /** + * Record an event at a specific timestamp. + * + * Shorthand for + * + *

+     span.log(timestampMicroseconds, Collections.singletonMap("event", event));
+     
+ * + * @param timestampMicroseconds The explicit timestamp for the log record. Must be greater than or equal to the + * Span's start timestamp. + * @param event the event value; often a stable identifier for a moment in the Span lifecycle + * @return the Span, for chaining + */ + Span log(long timestampMicroseconds, String event); + + /** + * Sets a baggage item in the Span (and its SpanContext) as a key/value pair. + * + * Baggage enables powerful distributed context propagation functionality where arbitrary application data can be + * carried along the full path of request execution throughout the system. + * + * Note 1: Baggage is only propagated to the future (recursive) children of this SpanContext. + * + * Note 2: Baggage is sent in-band with every subsequent local and remote calls, so this feature must be used with + * care. + * + * @return this Span instance, for chaining + */ + Span setBaggageItem(String key, String value); + + /** + * @return the value of the baggage item identified by the given key, or null if no such item could be found + */ + String getBaggageItem(String key); + + /** + * Sets the string name for the logical operation this span represents. + * + * @return this Span instance, for chaining + */ + Span setOperationName(String operationName); + /** * Sets the end timestamp to now and records the span. * diff --git a/opentracing-api/src/main/java/io/opentracing/Tracer.java b/opentracing-api/src/main/java/io/opentracing/Tracer.java index 25d3d321..bb3c0d16 100644 --- a/opentracing-api/src/main/java/io/opentracing/Tracer.java +++ b/opentracing-api/src/main/java/io/opentracing/Tracer.java @@ -18,7 +18,12 @@ /** * Tracer is a simple, thin interface for Span creation and propagation across arbitrary transports. */ -public interface Tracer extends ActiveSpanSource { +public interface Tracer { + + /** + * @return the current {@link ScopeManager}, which may be a noop but may not be null. + */ + ScopeManager scopeManager(); /** * Return a new SpanBuilder for a Span with the given `operationName`. @@ -29,14 +34,14 @@ public interface Tracer extends ActiveSpanSource { *

      *   Tracer tracer = ...
      *
-     *   // Note: if there is a `tracer.activeSpan()`, it will be used as the target of an implicit CHILD_OF
-     *   // Reference for "workSpan" when `startActive()` is invoked.
-     *   try (ActiveSpan workSpan = tracer.buildSpan("DoWork").startActive()) {
-     *       workSpan.setTag("...", "...");
+     *   // Note: if there is a `tracer.active()` Scope, its `span()` will be used as the target
+     *   // of an implicit CHILD_OF Reference for "workScope.span()" when `startActive()` is invoked.
+     *   try (Scope workScope = tracer.buildSpan("DoWork").startActive()) {
+     *       workScope.span().setTag("...", "...");
      *       // etc, etc
      *   }
      *
-     *   // It's also possible to create Spans manually, bypassing the ActiveSpanSource activation.
+     *   // It's also possible to create Spans manually, bypassing the ScopeManager activation.
      *   Span http = tracer.buildSpan("HandleHTTPRequest")
      *                     .asChildOf(rpcSpanContext)  // an explicit parent
      *                     .withTag("user_agent", req.UserAgent)
@@ -111,7 +116,7 @@ interface SpanBuilder {
          * 

* If parent==null, this is a noop. */ - SpanBuilder asChildOf(BaseSpan parent); + SpanBuilder asChildOf(Span parent); /** * Add a reference from the Span being built to a distinct (usually parent) Span. May be called multiple times @@ -120,12 +125,12 @@ interface SpanBuilder { *

* If *

    - *
  • the {@link Tracer}'s {@link ActiveSpanSource#activeSpan()} is not null, and + *
  • the {@link Tracer}'s {@link ScopeManager#active()} is not null, and *
  • no explicit references are added via {@link SpanBuilder#addReference}, and *
  • {@link SpanBuilder#ignoreActiveSpan()} is not invoked, *
* ... then an inferred {@link References#CHILD_OF} reference is created to the - * {@link ActiveSpanSource#activeSpan()} {@link SpanContext} when either {@link SpanBuilder#startActive()} or + * {@link ScopeManager#active()} {@link SpanContext} when either {@link SpanBuilder#startActive()} or * {@link SpanBuilder#startManual} is invoked. * * @param referenceType the reference type, typically one of the constants defined in References @@ -138,7 +143,7 @@ interface SpanBuilder { SpanBuilder addReference(String referenceType, SpanContext referencedContext); /** - * Do not create an implicit {@link References#CHILD_OF} reference to the {@link ActiveSpanSource#activeSpan}). + * Do not create an implicit {@link References#CHILD_OF} reference to the {@link ScopeManager#active()}). */ SpanBuilder ignoreActiveSpan(); @@ -155,46 +160,78 @@ interface SpanBuilder { SpanBuilder withStartTimestamp(long microseconds); /** - * Returns a newly started and activated {@link ActiveSpan}. + * Returns a newly started and activated {@link Scope}. * *

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


-         *     try (ActiveSpan span = tracer.buildSpan("...").startActive()) {
+         *     try (Scope scope = tracer.buildSpan("...").startActive()) {
          *         // (Do work)
-         *         span.setTag( ... );  // etc, etc
-         *     }  // Span finishes automatically unless deferred via {@link ActiveSpan#capture}
+         *         scope.span().setTag( ... );  // etc, etc
+         *     }
+         *     // Span finishes automatically when the Scope is closed,
+         *     // following the default behavior of ScopeManager.activate(Span)
+         * 
+ * + *

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

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

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


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

* If *

    - *
  • the {@link Tracer}'s {@link ActiveSpanSource#activeSpan()} is not null, and + *
  • the {@link Tracer}'s {@link ScopeManager#active()} is not null, and *
  • no explicit references are added via {@link SpanBuilder#addReference}, and *
  • {@link SpanBuilder#ignoreActiveSpan()} is not invoked, *
* ... then an inferred {@link References#CHILD_OF} reference is created to the - * {@link ActiveSpanSource#activeSpan()}'s {@link SpanContext} when either + * {@link ScopeManager#active()}'s {@link SpanContext} when either * {@link SpanBuilder#startManual()} or {@link SpanBuilder#startActive} is invoked. * *

- * Note: {@link SpanBuilder#startActive()} is a shorthand for - * {@code tracer.makeActive(spanBuilder.startManual())}. + * Note: {@link SpanBuilder#startActive(boolean)} is a shorthand for + * {@code tracer.scopeManager().activate(spanBuilder.startManual(), finishSpanOnClose)}. * - * @return an {@link ActiveSpan}, already registered via the {@link ActiveSpanSource} + * @param finishSpanOnClose whether span should automatically be finished when {@link Scope#close()} is called + * @return a {@link Scope}, already registered via the {@link ScopeManager} * - * @see ActiveSpanSource - * @see ActiveSpan + * @see ScopeManager + * @see Scope */ - ActiveSpan startActive(); + Scope startActive(boolean finishSpanOnClose); /** * Like {@link #startActive()}, but the returned {@link Span} has not been registered via the - * {@link ActiveSpanSource}. + * {@link ScopeManager}. * * @see SpanBuilder#startActive() * @return the newly-started Span instance, which has *not* been automatically registered - * via the {@link ActiveSpanSource} + * via the {@link ScopeManager} */ Span startManual(); diff --git a/opentracing-api/src/main/java/io/opentracing/tag/AbstractTag.java b/opentracing-api/src/main/java/io/opentracing/tag/AbstractTag.java index 4fed5c18..792ca636 100644 --- a/opentracing-api/src/main/java/io/opentracing/tag/AbstractTag.java +++ b/opentracing-api/src/main/java/io/opentracing/tag/AbstractTag.java @@ -13,7 +13,7 @@ */ package io.opentracing.tag; -import io.opentracing.BaseSpan; +import io.opentracing.Span; public abstract class AbstractTag { protected final String key; @@ -26,5 +26,5 @@ public String getKey() { return key; } - protected abstract void set(BaseSpan span, T tagValue); + protected abstract void set(Span span, T tagValue); } diff --git a/opentracing-api/src/main/java/io/opentracing/tag/BooleanTag.java b/opentracing-api/src/main/java/io/opentracing/tag/BooleanTag.java index f9be1ee3..8168d422 100644 --- a/opentracing-api/src/main/java/io/opentracing/tag/BooleanTag.java +++ b/opentracing-api/src/main/java/io/opentracing/tag/BooleanTag.java @@ -13,7 +13,7 @@ */ package io.opentracing.tag; -import io.opentracing.BaseSpan; +import io.opentracing.Span; public class BooleanTag extends AbstractTag { public BooleanTag(String key) { @@ -21,7 +21,7 @@ public BooleanTag(String key) { } @Override - public void set(BaseSpan span, Boolean tagValue) { + public void set(Span span, Boolean tagValue) { span.setTag(super.key, tagValue); } } diff --git a/opentracing-api/src/main/java/io/opentracing/tag/IntOrStringTag.java b/opentracing-api/src/main/java/io/opentracing/tag/IntOrStringTag.java index e173b842..1ea09cbf 100644 --- a/opentracing-api/src/main/java/io/opentracing/tag/IntOrStringTag.java +++ b/opentracing-api/src/main/java/io/opentracing/tag/IntOrStringTag.java @@ -13,14 +13,14 @@ */ package io.opentracing.tag; -import io.opentracing.BaseSpan; +import io.opentracing.Span; public class IntOrStringTag extends IntTag { public IntOrStringTag(String key) { super(key); } - public void set(BaseSpan span, String tagValue) { + public void set(Span span, String tagValue) { span.setTag(super.key, tagValue); } } diff --git a/opentracing-api/src/main/java/io/opentracing/tag/IntTag.java b/opentracing-api/src/main/java/io/opentracing/tag/IntTag.java index 48f4ae71..cb126492 100644 --- a/opentracing-api/src/main/java/io/opentracing/tag/IntTag.java +++ b/opentracing-api/src/main/java/io/opentracing/tag/IntTag.java @@ -13,7 +13,7 @@ */ package io.opentracing.tag; -import io.opentracing.BaseSpan; +import io.opentracing.Span; public class IntTag extends AbstractTag { public IntTag(String key) { @@ -21,7 +21,7 @@ public IntTag(String key) { } @Override - public void set(BaseSpan span, Integer tagValue) { + public void set(Span span, Integer tagValue) { span.setTag(super.key, tagValue); } } diff --git a/opentracing-api/src/main/java/io/opentracing/tag/StringTag.java b/opentracing-api/src/main/java/io/opentracing/tag/StringTag.java index 1fdba21a..65cfd59e 100644 --- a/opentracing-api/src/main/java/io/opentracing/tag/StringTag.java +++ b/opentracing-api/src/main/java/io/opentracing/tag/StringTag.java @@ -13,7 +13,7 @@ */ package io.opentracing.tag; -import io.opentracing.BaseSpan; +import io.opentracing.Span; public class StringTag extends AbstractTag { public StringTag(String key) { @@ -21,11 +21,11 @@ public StringTag(String key) { } @Override - public void set(BaseSpan span, String tagValue) { + public void set(Span span, String tagValue) { span.setTag(super.key, tagValue); } - public void set(BaseSpan span, StringTag tag) { + public void set(Span span, StringTag tag) { span.setTag(super.key, tag.key); } } diff --git a/opentracing-api/src/test/java/io/opentracing/tag/AbstractTagTest.java b/opentracing-api/src/test/java/io/opentracing/tag/AbstractTagTest.java index 816e259f..f327851e 100644 --- a/opentracing-api/src/test/java/io/opentracing/tag/AbstractTagTest.java +++ b/opentracing-api/src/test/java/io/opentracing/tag/AbstractTagTest.java @@ -17,10 +17,8 @@ import static org.mockito.Mockito.mock; import static org.mockito.Mockito.verify; -import org.junit.Test; - -import io.opentracing.ActiveSpan; import io.opentracing.Span; +import org.junit.Test; /** * @author Pavol Loffay @@ -45,16 +43,4 @@ public void testSetTagOnSpan() { verify(activeSpan).setTag(key, value); } - - @Test - public void testSetTagOnActiveSpan() { - String value = "foo"; - String key = "bar"; - - ActiveSpan activeSpan = mock(ActiveSpan.class); - StringTag tag = new StringTag(key); - tag.set(activeSpan, value); - - verify(activeSpan).setTag(key, value); - } } diff --git a/opentracing-examples/src/test/java/io/opentracing/examples/AutoFinishScope.java b/opentracing-examples/src/test/java/io/opentracing/examples/AutoFinishScope.java new file mode 100644 index 00000000..0010a54e --- /dev/null +++ b/opentracing-examples/src/test/java/io/opentracing/examples/AutoFinishScope.java @@ -0,0 +1,66 @@ +/* + * Copyright 2016-2017 The OpenTracing Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License + * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the License for the specific language governing permissions and limitations under + * the License. + */ +package io.opentracing.examples; + +import io.opentracing.Scope; +import io.opentracing.Span; + +import java.util.concurrent.atomic.AtomicInteger; + +public class AutoFinishScope implements Scope { + final AutoFinishScopeManager manager; + final AtomicInteger refCount; + private final Span wrapped; + private final AutoFinishScope toRestore; + + AutoFinishScope(AutoFinishScopeManager manager, AtomicInteger refCount, Span wrapped) { + this.manager = manager; + this.refCount = refCount; + this.wrapped = wrapped; + this.toRestore = manager.tlsScope.get(); + manager.tlsScope.set(this); + } + + public class Continuation { + public Continuation() { + refCount.incrementAndGet(); + } + + public AutoFinishScope activate() { + return new AutoFinishScope(manager, refCount, wrapped); + } + } + + public Continuation capture() { + return new Continuation(); + } + + @Override + public void close() { + if (manager.tlsScope.get() != this) { + return; + } + + if (refCount.decrementAndGet() == 0) { + wrapped.finish(); + } + + manager.tlsScope.set(toRestore); + } + + @Override + public Span span() { + return wrapped; + } +} diff --git a/opentracing-util/src/main/java/io/opentracing/util/ThreadLocalActiveSpanSource.java b/opentracing-examples/src/test/java/io/opentracing/examples/AutoFinishScopeManager.java similarity index 51% rename from opentracing-util/src/main/java/io/opentracing/util/ThreadLocalActiveSpanSource.java rename to opentracing-examples/src/test/java/io/opentracing/examples/AutoFinishScopeManager.java index 2cd7e6e2..bfb578bd 100644 --- a/opentracing-util/src/main/java/io/opentracing/util/ThreadLocalActiveSpanSource.java +++ b/opentracing-examples/src/test/java/io/opentracing/examples/AutoFinishScopeManager.java @@ -11,32 +11,29 @@ * or implied. See the License for the specific language governing permissions and limitations under * the License. */ -package io.opentracing.util; +package io.opentracing.examples; -import io.opentracing.ActiveSpan; -import io.opentracing.ActiveSpanSource; +import io.opentracing.ScopeManager; import io.opentracing.Span; -import io.opentracing.Tracer; import java.util.concurrent.atomic.AtomicInteger; -/** - * A simple {@link ActiveSpanSource} implementation built on top of Java's thread-local storage primitive. - * - * @see ThreadLocalActiveSpan - * @see Tracer#activeSpan() - */ -public class ThreadLocalActiveSpanSource implements ActiveSpanSource { - final ThreadLocal tlsSnapshot = new ThreadLocal(); +public class AutoFinishScopeManager implements ScopeManager { + final ThreadLocal tlsScope = new ThreadLocal(); + + @Override + public AutoFinishScope activate(Span span) { + return new AutoFinishScope(this, new AtomicInteger(1), span); + } @Override - public ThreadLocalActiveSpan activeSpan() { - return tlsSnapshot.get(); + public AutoFinishScope activate(Span span, boolean finishOnClose) { + return new AutoFinishScope(this, new AtomicInteger(1), span); } @Override - public ActiveSpan makeActive(Span span) { - return new ThreadLocalActiveSpan(this, span, new AtomicInteger(1)); + public AutoFinishScope active() { + return tlsScope.get(); } } diff --git a/opentracing-examples/src/test/java/io/opentracing/examples/activate_deactivate/RunnableAction.java b/opentracing-examples/src/test/java/io/opentracing/examples/activate_deactivate/RunnableAction.java index fab14632..bda704d3 100644 --- a/opentracing-examples/src/test/java/io/opentracing/examples/activate_deactivate/RunnableAction.java +++ b/opentracing-examples/src/test/java/io/opentracing/examples/activate_deactivate/RunnableAction.java @@ -13,8 +13,8 @@ */ package io.opentracing.examples.activate_deactivate; -import io.opentracing.ActiveSpan; -import io.opentracing.ActiveSpan.Continuation; +import io.opentracing.examples.AutoFinishScope; +import io.opentracing.examples.AutoFinishScope.Continuation; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -30,8 +30,8 @@ public class RunnableAction implements Runnable { private final Continuation continuation; - RunnableAction(ActiveSpan activeSpan) { - continuation = activeSpan.capture(); + RunnableAction(AutoFinishScope scope) { + continuation = scope.capture(); logger.info("Action created"); } @@ -42,7 +42,7 @@ public class RunnableAction implements Runnable { @Override public void run() { logger.info("Action started"); - ActiveSpan activeSpan = continuation.activate(); + AutoFinishScope scope = continuation.activate(); try { TimeUnit.SECONDS.sleep(1); // without sleep first action can finish before second is started @@ -51,9 +51,9 @@ public void run() { } // set random tag starting with 'test_tag_' to test that finished span has all of them - activeSpan.setTag("test_tag_" + ThreadLocalRandom.current().nextInt(), "random"); + scope.span().setTag("test_tag_" + ThreadLocalRandom.current().nextInt(), "random"); - activeSpan.deactivate(); + scope.close(); logger.info("Action finished"); } } diff --git a/opentracing-examples/src/test/java/io/opentracing/examples/activate_deactivate/ScheduledActionsTest.java b/opentracing-examples/src/test/java/io/opentracing/examples/activate_deactivate/ScheduledActionsTest.java index c42ad772..cc5307c2 100644 --- a/opentracing-examples/src/test/java/io/opentracing/examples/activate_deactivate/ScheduledActionsTest.java +++ b/opentracing-examples/src/test/java/io/opentracing/examples/activate_deactivate/ScheduledActionsTest.java @@ -13,11 +13,12 @@ */ package io.opentracing.examples.activate_deactivate; -import io.opentracing.ActiveSpan; +import io.opentracing.Scope; +import io.opentracing.examples.AutoFinishScope; +import io.opentracing.examples.AutoFinishScopeManager; import io.opentracing.mock.MockSpan; import io.opentracing.mock.MockTracer; import io.opentracing.mock.MockTracer.Propagator; -import io.opentracing.util.ThreadLocalActiveSpanSource; import org.junit.Test; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -37,7 +38,7 @@ public class ScheduledActionsTest { private static final Logger logger = LoggerFactory.getLogger(ScheduledActionsTest.class); - private final MockTracer tracer = new MockTracer(new ThreadLocalActiveSpanSource(), + private final MockTracer tracer = new MockTracer(new AutoFinishScopeManager(), Propagator.TEXT_MAP); private final ScheduledExecutorService service = Executors.newScheduledThreadPool(10); @@ -88,8 +89,8 @@ private Thread entryThread() { @Override public void run() { logger.info("Entry thread started"); - try (ActiveSpan activeSpan = tracer.buildSpan("parent").startActive()) { - Runnable action = new RunnableAction(activeSpan); + try (Scope scope = tracer.buildSpan("parent").startActive()) { + Runnable action = new RunnableAction((AutoFinishScope)scope); // Action is executed at some time and we are not able to check status service.schedule(action, 500, TimeUnit.MILLISECONDS); @@ -107,9 +108,9 @@ private Thread entryThreadWithTwoActions() { @Override public void run() { logger.info("Entry thread 2x started"); - try (ActiveSpan activeSpan = tracer.buildSpan("parent").startActive()) { - Runnable action = new RunnableAction(activeSpan); - Runnable action2 = new RunnableAction(activeSpan); + try (Scope scope = tracer.buildSpan("parent").startActive()) { + Runnable action = new RunnableAction((AutoFinishScope)scope); + Runnable action2 = new RunnableAction((AutoFinishScope)scope); Random random = new Random(); diff --git a/opentracing-examples/src/test/java/io/opentracing/examples/active_span_replacement/ActiveSpanReplacementTest.java b/opentracing-examples/src/test/java/io/opentracing/examples/active_span_replacement/ActiveSpanReplacementTest.java index 7c907014..72cb979b 100644 --- a/opentracing-examples/src/test/java/io/opentracing/examples/active_span_replacement/ActiveSpanReplacementTest.java +++ b/opentracing-examples/src/test/java/io/opentracing/examples/active_span_replacement/ActiveSpanReplacementTest.java @@ -13,11 +13,12 @@ */ package io.opentracing.examples.active_span_replacement; -import io.opentracing.ActiveSpan; +import io.opentracing.Scope; +import io.opentracing.Span; import io.opentracing.mock.MockSpan; import io.opentracing.mock.MockTracer; import io.opentracing.mock.MockTracer.Propagator; -import io.opentracing.util.ThreadLocalActiveSpanSource; +import io.opentracing.util.ThreadLocalScopeManager; import org.junit.Test; import java.util.List; @@ -35,7 +36,7 @@ public class ActiveSpanReplacementTest { - private final MockTracer tracer = new MockTracer(new ThreadLocalActiveSpanSource(), + private final MockTracer tracer = new MockTracer(new ThreadLocalScopeManager(), Propagator.TEXT_MAP); private final ExecutorService executor = Executors.newCachedThreadPool(); @@ -43,8 +44,9 @@ public class ActiveSpanReplacementTest { @Test public void test() throws Exception { // Start an isolated task and query for its result in another task/thread - try (ActiveSpan span = tracer.buildSpan("initial").startActive()) { - submitAnotherTask(span); + try (Scope scope = tracer.buildSpan("initial").startActive(false)) { + // Explicitly pass a Span to be finished once a late calculation is done. + submitAnotherTask(scope.span()); } await().atMost(15, TimeUnit.SECONDS).until(finishedSpansSize(tracer), equalTo(3)); @@ -63,25 +65,25 @@ public void test() throws Exception { assertNotEquals(spans.get(0).context().traceId(), spans.get(1).context().traceId()); assertEquals(0, spans.get(0).parentId()); - assertNull(tracer.activeSpan()); + assertNull(tracer.scopeManager().active()); } - private void submitAnotherTask(ActiveSpan span) { - final ActiveSpan.Continuation cont = span.capture(); + private void submitAnotherTask(final Span initialSpan) { executor.submit(new Runnable() { @Override public void run() { // Create a new Span for this task - try (ActiveSpan taskSpan = tracer.buildSpan("task").startActive()) { + try (Scope taskScope = tracer.buildSpan("task").startActive()) { // Simulate work strictly related to the initial Span - try (ActiveSpan initialSpan = cont.activate()) { + // and finish it. + try (Scope initialScope = tracer.scopeManager().activate(initialSpan)) { sleep(50); } // Restore the span for this task and create a subspan - try (ActiveSpan subTask = tracer.buildSpan("subtask").startActive()) { + try (Scope subTaskScope = tracer.buildSpan("subtask").startActive()) { } } } diff --git a/opentracing-examples/src/test/java/io/opentracing/examples/client_server/Client.java b/opentracing-examples/src/test/java/io/opentracing/examples/client_server/Client.java index 15554a08..2954ab33 100644 --- a/opentracing-examples/src/test/java/io/opentracing/examples/client_server/Client.java +++ b/opentracing-examples/src/test/java/io/opentracing/examples/client_server/Client.java @@ -13,7 +13,7 @@ */ package io.opentracing.examples.client_server; -import io.opentracing.ActiveSpan; +import io.opentracing.Scope; import io.opentracing.Tracer; import io.opentracing.propagation.Format.Builtin; import io.opentracing.propagation.TextMapInjectAdapter; @@ -34,11 +34,11 @@ public Client(ArrayBlockingQueue queue, Tracer tracer) { public void send() throws InterruptedException { Message message = new Message(); - try (ActiveSpan activeSpan = tracer.buildSpan("send") + try (Scope scope = tracer.buildSpan("send") .withTag(Tags.SPAN_KIND.getKey(), Tags.SPAN_KIND_CLIENT) .withTag(Tags.COMPONENT.getKey(), "example-client") .startActive()) { - tracer.inject(activeSpan.context(), Builtin.TEXT_MAP, new TextMapInjectAdapter(message)); + tracer.inject(scope.span().context(), Builtin.TEXT_MAP, new TextMapInjectAdapter(message)); queue.put(message); } } diff --git a/opentracing-examples/src/test/java/io/opentracing/examples/client_server/Server.java b/opentracing-examples/src/test/java/io/opentracing/examples/client_server/Server.java index 2067ee2d..240445ea 100644 --- a/opentracing-examples/src/test/java/io/opentracing/examples/client_server/Server.java +++ b/opentracing-examples/src/test/java/io/opentracing/examples/client_server/Server.java @@ -13,7 +13,7 @@ */ package io.opentracing.examples.client_server; -import io.opentracing.ActiveSpan; +import io.opentracing.Scope; import io.opentracing.SpanContext; import io.opentracing.Tracer; import io.opentracing.propagation.Format.Builtin; @@ -34,7 +34,7 @@ public Server(ArrayBlockingQueue queue, Tracer tracer) { private void process(Message message) { SpanContext context = tracer.extract(Builtin.TEXT_MAP, new TextMapExtractAdapter(message)); - try (ActiveSpan activeSpan = tracer.buildSpan("receive") + try (Scope scope = tracer.buildSpan("receive") .withTag(Tags.SPAN_KIND.getKey(), Tags.SPAN_KIND_SERVER) .withTag(Tags.COMPONENT.getKey(), "example-server") .asChildOf(context).startActive()) { diff --git a/opentracing-examples/src/test/java/io/opentracing/examples/client_server/TestClientServerTest.java b/opentracing-examples/src/test/java/io/opentracing/examples/client_server/TestClientServerTest.java index 489b98b6..a289cc06 100644 --- a/opentracing-examples/src/test/java/io/opentracing/examples/client_server/TestClientServerTest.java +++ b/opentracing-examples/src/test/java/io/opentracing/examples/client_server/TestClientServerTest.java @@ -17,7 +17,7 @@ import io.opentracing.mock.MockTracer; import io.opentracing.mock.MockTracer.Propagator; import io.opentracing.tag.Tags; -import io.opentracing.util.ThreadLocalActiveSpanSource; +import io.opentracing.util.ThreadLocalScopeManager; import org.junit.After; import org.junit.Before; import org.junit.Test; @@ -36,7 +36,7 @@ public class TestClientServerTest { - private final MockTracer tracer = new MockTracer(new ThreadLocalActiveSpanSource(), + private final MockTracer tracer = new MockTracer(new ThreadLocalScopeManager(), Propagator.TEXT_MAP); private final ArrayBlockingQueue queue = new ArrayBlockingQueue<>(10); private Server server; @@ -65,6 +65,6 @@ public void test() throws Exception { assertEquals(finished.get(0).context().traceId(), finished.get(1).context().traceId()); assertNotNull(getOneByTag(finished, Tags.SPAN_KIND, Tags.SPAN_KIND_CLIENT)); assertNotNull(getOneByTag(finished, Tags.SPAN_KIND, Tags.SPAN_KIND_SERVER)); - assertNull(tracer.activeSpan()); + assertNull(tracer.scopeManager().active()); } } diff --git a/opentracing-examples/src/test/java/io/opentracing/examples/common_request_handler/HandlerTest.java b/opentracing-examples/src/test/java/io/opentracing/examples/common_request_handler/HandlerTest.java index 189ae1de..3e487d4c 100644 --- a/opentracing-examples/src/test/java/io/opentracing/examples/common_request_handler/HandlerTest.java +++ b/opentracing-examples/src/test/java/io/opentracing/examples/common_request_handler/HandlerTest.java @@ -13,12 +13,12 @@ */ package io.opentracing.examples.common_request_handler; -import io.opentracing.ActiveSpan; +import io.opentracing.Scope; import io.opentracing.mock.MockSpan; import io.opentracing.mock.MockTracer; import io.opentracing.mock.MockTracer.Propagator; import io.opentracing.tag.Tags; -import io.opentracing.util.ThreadLocalActiveSpanSource; +import io.opentracing.util.ThreadLocalScopeManager; import org.junit.Before; import org.junit.Test; @@ -39,7 +39,7 @@ */ public class HandlerTest { - private final MockTracer tracer = new MockTracer(new ThreadLocalActiveSpanSource(), + private final MockTracer tracer = new MockTracer(new ThreadLocalScopeManager(), Propagator.TEXT_MAP); private final Client client = new Client(new RequestHandler(tracer)); @@ -67,7 +67,7 @@ public void two_requests() throws Exception { assertEquals(0, finished.get(0).parentId()); assertEquals(0, finished.get(1).parentId()); - assertNull(tracer.activeSpan()); + assertNull(tracer.scopeManager().active()); } /** @@ -75,7 +75,7 @@ public void two_requests() throws Exception { */ @Test public void parent_not_picked_up() throws Exception { - try (ActiveSpan parent = tracer.buildSpan("parent").startActive()) { + try (Scope parent = tracer.buildSpan("parent").startActive()) { String response = client.send("no_parent").get(15, TimeUnit.SECONDS); assertEquals("no_parent:response", response); } @@ -102,8 +102,8 @@ public void parent_not_picked_up() throws Exception { @Test public void bad_solution_to_set_parent() throws Exception { Client client; - try (ActiveSpan parent = tracer.buildSpan("parent").startActive()) { - client = new Client(new RequestHandler(tracer, parent.context())); + try (Scope parent = tracer.buildSpan("parent").startActive()) { + client = new Client(new RequestHandler(tracer, parent.span().context())); String response = client.send("correct_parent").get(15, TimeUnit.SECONDS); assertEquals("correct_parent:response", response); } diff --git a/opentracing-examples/src/test/java/io/opentracing/examples/late_span_finish/LateSpanFinishTest.java b/opentracing-examples/src/test/java/io/opentracing/examples/late_span_finish/LateSpanFinishTest.java index 9fc043a0..60260771 100644 --- a/opentracing-examples/src/test/java/io/opentracing/examples/late_span_finish/LateSpanFinishTest.java +++ b/opentracing-examples/src/test/java/io/opentracing/examples/late_span_finish/LateSpanFinishTest.java @@ -13,12 +13,12 @@ */ package io.opentracing.examples.late_span_finish; -import io.opentracing.ActiveSpan; +import io.opentracing.Scope; import io.opentracing.Span; import io.opentracing.mock.MockSpan; import io.opentracing.mock.MockTracer; import io.opentracing.mock.MockTracer.Propagator; -import io.opentracing.util.ThreadLocalActiveSpanSource; +import io.opentracing.util.ThreadLocalScopeManager; import org.junit.Test; import java.util.List; @@ -33,7 +33,7 @@ public class LateSpanFinishTest { - private final MockTracer tracer = new MockTracer(new ThreadLocalActiveSpanSource(), + private final MockTracer tracer = new MockTracer(new ThreadLocalScopeManager(), Propagator.TEXT_MAP); private final ExecutorService executor = Executors.newCachedThreadPool(); @@ -58,7 +58,7 @@ public void test() throws Exception { assertSameTrace(spans); - assertNull(tracer.activeSpan()); + assertNull(tracer.scopeManager().active()); } @@ -72,11 +72,10 @@ private void submitTasks(final Span parentSpan) { @Override public void run() { // Alternative to calling makeActive() is to pass it manually to asChildOf() for each created Span. - try (ActiveSpan span = tracer.makeActive(parentSpan)) { - try (ActiveSpan childSpan1 = tracer.buildSpan("task1").startActive()) { + try (Scope scope = tracer.scopeManager().activate(parentSpan, false)) { + try (Scope childScope1 = tracer.buildSpan("task1").startActive()) { sleep(55); } - span.capture(); // Workaround, prevent parentSpan from being finished here. } } }); @@ -84,11 +83,10 @@ public void run() { executor.submit(new Runnable() { @Override public void run() { - try (ActiveSpan span = tracer.makeActive(parentSpan)) { - try (ActiveSpan childSpan1 = tracer.buildSpan("task2").startActive()) { + try (Scope span = tracer.scopeManager().activate(parentSpan, false)) { + try (Scope childScope2 = tracer.buildSpan("task2").startActive()) { sleep(85); } - span.capture(); // Workaround, prevent parentSpan from being finished here. } } }); diff --git a/opentracing-examples/src/test/java/io/opentracing/examples/listener_per_request/ListenerTest.java b/opentracing-examples/src/test/java/io/opentracing/examples/listener_per_request/ListenerTest.java index 0d8646cb..4afd3b0e 100644 --- a/opentracing-examples/src/test/java/io/opentracing/examples/listener_per_request/ListenerTest.java +++ b/opentracing-examples/src/test/java/io/opentracing/examples/listener_per_request/ListenerTest.java @@ -17,7 +17,7 @@ import io.opentracing.mock.MockTracer; import io.opentracing.mock.MockTracer.Propagator; import io.opentracing.tag.Tags; -import io.opentracing.util.ThreadLocalActiveSpanSource; +import io.opentracing.util.ThreadLocalScopeManager; import org.junit.Test; import java.util.List; @@ -32,7 +32,7 @@ */ public class ListenerTest { - private final MockTracer tracer = new MockTracer(new ThreadLocalActiveSpanSource(), + private final MockTracer tracer = new MockTracer(new ThreadLocalScopeManager(), Propagator.TEXT_MAP); @Test @@ -44,6 +44,6 @@ public void test() throws Exception { List finished = tracer.finishedSpans(); assertEquals(1, finished.size()); assertNotNull(getOneByTag(finished, Tags.SPAN_KIND, Tags.SPAN_KIND_CLIENT)); - assertNull(tracer.activeSpan()); + assertNull(tracer.scopeManager().active()); } } diff --git a/opentracing-examples/src/test/java/io/opentracing/examples/multiple_callbacks/Client.java b/opentracing-examples/src/test/java/io/opentracing/examples/multiple_callbacks/Client.java index 0a7c9858..6be803f5 100644 --- a/opentracing-examples/src/test/java/io/opentracing/examples/multiple_callbacks/Client.java +++ b/opentracing-examples/src/test/java/io/opentracing/examples/multiple_callbacks/Client.java @@ -13,8 +13,10 @@ */ package io.opentracing.examples.multiple_callbacks; -import io.opentracing.ActiveSpan; +import io.opentracing.Scope; import io.opentracing.Tracer; +import io.opentracing.examples.AutoFinishScope; +import io.opentracing.examples.AutoFinishScope.Continuation; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -36,15 +38,17 @@ public Client(Tracer tracer) { this.tracer = tracer; } - public Future send(final Object message, ActiveSpan parentSpan, final long milliseconds) { - final ActiveSpan.Continuation cont = parentSpan.capture(); + public Future send(final Object message, final long milliseconds) { + Scope scope = tracer.scopeManager().active(); + final Continuation cont = ((AutoFinishScope)scope).capture(); + return executor.submit(new Callable() { @Override public Object call() throws Exception { logger.info("Child thread with message '{}' started", message); - try (ActiveSpan parentSpan = cont.activate()) { - try (ActiveSpan span = tracer.buildSpan("subtask").startActive()) { + try (Scope parentScope = cont.activate()) { + try (Scope subtaskScope = tracer.buildSpan("subtask").startActive()) { // Simulate work. sleep(milliseconds); } diff --git a/opentracing-examples/src/test/java/io/opentracing/examples/multiple_callbacks/MultipleCallbacksTest.java b/opentracing-examples/src/test/java/io/opentracing/examples/multiple_callbacks/MultipleCallbacksTest.java index 92100687..517e77fd 100644 --- a/opentracing-examples/src/test/java/io/opentracing/examples/multiple_callbacks/MultipleCallbacksTest.java +++ b/opentracing-examples/src/test/java/io/opentracing/examples/multiple_callbacks/MultipleCallbacksTest.java @@ -13,11 +13,11 @@ */ package io.opentracing.examples.multiple_callbacks; -import io.opentracing.ActiveSpan; +import io.opentracing.Scope; +import io.opentracing.examples.AutoFinishScopeManager; import io.opentracing.mock.MockSpan; import io.opentracing.mock.MockTracer; import io.opentracing.mock.MockTracer.Propagator; -import io.opentracing.util.ThreadLocalActiveSpanSource; import org.junit.Test; import java.util.List; @@ -31,16 +31,16 @@ public class MultipleCallbacksTest { - private final MockTracer tracer = new MockTracer(new ThreadLocalActiveSpanSource(), + private final MockTracer tracer = new MockTracer(new AutoFinishScopeManager(), Propagator.TEXT_MAP); @Test public void test() throws Exception { Client client = new Client(tracer); - try (ActiveSpan span = tracer.buildSpan("parent").startActive()) { - client.send("task1", span, 300); - client.send("task2", span, 200); - client.send("task3", span, 100); + try (Scope scope = tracer.buildSpan("parent").startActive()) { + client.send("task1", 300); + client.send("task2", 200); + client.send("task3", 100); } await().atMost(15, TimeUnit.SECONDS).until(finishedSpansSize(tracer), equalTo(4)); @@ -56,6 +56,6 @@ public void test() throws Exception { assertEquals(parentSpan.context().spanId(), spans.get(i).parentId()); } - assertNull(tracer.activeSpan()); + assertNull(tracer.scopeManager().active()); } } diff --git a/opentracing-examples/src/test/java/io/opentracing/examples/nested_callbacks/NestedCallbacksTest.java b/opentracing-examples/src/test/java/io/opentracing/examples/nested_callbacks/NestedCallbacksTest.java index d25830ba..9f74fc83 100644 --- a/opentracing-examples/src/test/java/io/opentracing/examples/nested_callbacks/NestedCallbacksTest.java +++ b/opentracing-examples/src/test/java/io/opentracing/examples/nested_callbacks/NestedCallbacksTest.java @@ -13,11 +13,12 @@ */ package io.opentracing.examples.nested_callbacks; -import io.opentracing.ActiveSpan; +import io.opentracing.Scope; +import io.opentracing.Span; import io.opentracing.mock.MockSpan; import io.opentracing.mock.MockTracer; import io.opentracing.mock.MockTracer.Propagator; -import io.opentracing.util.ThreadLocalActiveSpanSource; +import io.opentracing.util.ThreadLocalScopeManager; import org.junit.Test; import java.util.List; @@ -34,15 +35,15 @@ public class NestedCallbacksTest { - private final MockTracer tracer = new MockTracer(new ThreadLocalActiveSpanSource(), + private final MockTracer tracer = new MockTracer(new ThreadLocalScopeManager(), Propagator.TEXT_MAP); private final ExecutorService executor = Executors.newCachedThreadPool(); @Test public void test() throws Exception { - try (ActiveSpan span = tracer.buildSpan("one").startActive()) { - submitCallbacks(span); + try (Scope scope = tracer.buildSpan("one").startActive(false)) { + submitCallbacks(scope.span()); } await().atMost(15, TimeUnit.SECONDS).until(finishedSpansSize(tracer), equalTo(1)); @@ -57,30 +58,27 @@ public void test() throws Exception { assertEquals(Integer.toString(i), tags.get("key" + i)); } - assertNull(tracer.activeSpan()); + assertNull(tracer.scopeManager().active()); } - private void submitCallbacks(ActiveSpan span) { - final ActiveSpan.Continuation cont = span.capture(); + private void submitCallbacks(final Span span) { executor.submit(new Runnable() { @Override public void run() { - try (ActiveSpan span = cont.activate()) { + try (Scope scope = tracer.scopeManager().activate(span, false)) { span.setTag("key1", "1"); - final ActiveSpan.Continuation cont = span.capture(); executor.submit(new Runnable() { @Override public void run() { - try (ActiveSpan span = cont.activate()) { + try (Scope scope = tracer.scopeManager().activate(span, false)) { span.setTag("key2", "2"); - final ActiveSpan.Continuation cont = span.capture(); executor.submit(new Runnable() { @Override public void run() { - try (ActiveSpan span = cont.activate()) { + try (Scope scope = tracer.scopeManager().activate(span)) { span.setTag("key3", "3"); } } diff --git a/opentracing-mock/src/main/java/io/opentracing/mock/MockTracer.java b/opentracing-mock/src/main/java/io/opentracing/mock/MockTracer.java index 50024ab9..36ea0232 100644 --- a/opentracing-mock/src/main/java/io/opentracing/mock/MockTracer.java +++ b/opentracing-mock/src/main/java/io/opentracing/mock/MockTracer.java @@ -18,17 +18,16 @@ import java.util.List; import java.util.Map; -import io.opentracing.ActiveSpan; -import io.opentracing.ActiveSpanSource; -import io.opentracing.BaseSpan; -import io.opentracing.References; +import io.opentracing.Scope; +import io.opentracing.ScopeManager; import io.opentracing.Span; +import io.opentracing.noop.NoopScopeManager; +import io.opentracing.References; import io.opentracing.SpanContext; import io.opentracing.Tracer; -import io.opentracing.noop.NoopActiveSpanSource; import io.opentracing.propagation.Format; import io.opentracing.propagation.TextMap; -import io.opentracing.util.ThreadLocalActiveSpanSource; +import io.opentracing.util.ThreadLocalScopeManager; /** * MockTracer makes it easy to test the semantics of OpenTracing instrumentation. @@ -41,26 +40,26 @@ public class MockTracer implements Tracer { private final List finishedSpans = new ArrayList<>(); private final Propagator propagator; - private final ActiveSpanSource spanSource; + private final ScopeManager scopeManager; public MockTracer() { - this(new ThreadLocalActiveSpanSource(), Propagator.TEXT_MAP); + this(new ThreadLocalScopeManager(), Propagator.TEXT_MAP); } - public MockTracer(ActiveSpanSource spanSource) { - this(spanSource, Propagator.TEXT_MAP); + public MockTracer(ScopeManager scopeManager) { + this(scopeManager, Propagator.TEXT_MAP); } - public MockTracer(ActiveSpanSource spanSource, Propagator propagator) { + public MockTracer(ScopeManager scopeManager, Propagator propagator) { + this.scopeManager = scopeManager; this.propagator = propagator; - this.spanSource = spanSource; } /** * Create a new MockTracer that passes through any calls to inject() and/or extract(). */ public MockTracer(Propagator propagator) { - this(NoopActiveSpanSource.INSTANCE, propagator); + this(NoopScopeManager.INSTANCE, propagator); } /** @@ -89,16 +88,6 @@ public synchronized List finishedSpans() { protected void onSpanFinished(MockSpan mockSpan) { } - @Override - public ActiveSpan activeSpan() { - return spanSource.activeSpan(); - } - - @Override - public ActiveSpan makeActive(Span span) { - return spanSource.makeActive(span); - } - /** * Propagator allows the developer to intercept and verify any calls to inject() and/or extract(). * @@ -173,18 +162,23 @@ public MockSpan.MockContext extract(Format format, C carrier) { }; } + @Override + public ScopeManager scopeManager() { + return this.scopeManager; + } + @Override public SpanBuilder buildSpan(String operationName) { return new SpanBuilder(operationName); } private SpanContext activeSpanContext() { - ActiveSpan handle = this.spanSource.activeSpan(); + Scope handle = this.scopeManager.active(); if (handle == null) { return null; } - return handle.context(); + return handle.span().context(); } @Override @@ -219,7 +213,7 @@ public SpanBuilder asChildOf(SpanContext parent) { } @Override - public SpanBuilder asChildOf(BaseSpan parent) { + public SpanBuilder asChildOf(Span parent) { if (parent == null) { return this; } @@ -265,15 +259,18 @@ public SpanBuilder withStartTimestamp(long microseconds) { } @Override - @Deprecated - public MockSpan start() { - return startManual(); + public Scope startActive() { + return MockTracer.this.scopeManager().activate(this.startManual()); } @Override - public ActiveSpan startActive() { - MockSpan span = this.startManual(); - return spanSource.makeActive(span); + public Scope startActive(boolean finishOnClose) { + return MockTracer.this.scopeManager().activate(this.startManual(), finishOnClose); + } + + @Override + public MockSpan start() { + return startManual(); } @Override 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 e4d8749f..129ec9ab 100644 --- a/opentracing-mock/src/test/java/io/opentracing/mock/MockTracerTest.java +++ b/opentracing-mock/src/test/java/io/opentracing/mock/MockTracerTest.java @@ -25,7 +25,7 @@ import org.junit.Assert; import org.junit.Test; -import io.opentracing.ActiveSpan; +import io.opentracing.Scope; import io.opentracing.Span; import io.opentracing.SpanContext; import io.opentracing.Tracer; @@ -288,11 +288,11 @@ public void testNonStandardReference() { @Test public void testDefaultConstructor() { MockTracer mockTracer = new MockTracer(); - ActiveSpan activeSpan = mockTracer.buildSpan("foo").startActive(); - assertEquals(activeSpan, mockTracer.activeSpan()); + Scope activeSpan = mockTracer.buildSpan("foo").startActive(); + assertEquals(activeSpan, mockTracer.scopeManager().active()); Map propag = new HashMap<>(); - mockTracer.inject(activeSpan.context(), Format.Builtin.TEXT_MAP, new TextMapInjectAdapter(propag)); + mockTracer.inject(activeSpan.span().context(), Format.Builtin.TEXT_MAP, new TextMapInjectAdapter(propag)); assertFalse(propag.isEmpty()); } diff --git a/opentracing-noop/src/main/java/io/opentracing/noop/NoopActiveSpanSource.java b/opentracing-noop/src/main/java/io/opentracing/noop/NoopActiveSpanSource.java deleted file mode 100644 index ddd150ce..00000000 --- a/opentracing-noop/src/main/java/io/opentracing/noop/NoopActiveSpanSource.java +++ /dev/null @@ -1,120 +0,0 @@ -/* - * Copyright 2016-2017 The OpenTracing Authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except - * in compliance with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software distributed under the License - * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express - * or implied. See the License for the specific language governing permissions and limitations under - * the License. - */ -package io.opentracing.noop; - -import io.opentracing.ActiveSpan; -import io.opentracing.ActiveSpanSource; -import io.opentracing.Span; -import io.opentracing.SpanContext; - -import java.util.Map; - -public interface NoopActiveSpanSource extends ActiveSpanSource { - NoopActiveSpanSource INSTANCE = new NoopActiveSpanSourceImpl(); - - interface NoopActiveSpan extends ActiveSpan { - NoopActiveSpanSource.NoopActiveSpan INSTANCE = new NoopActiveSpanSourceImpl.NoopActiveSpanImpl(); - } - interface NoopContinuation extends ActiveSpan.Continuation { - NoopActiveSpanSource.NoopContinuation INSTANCE = new NoopActiveSpanSourceImpl.NoopContinuationImpl(); - } -} - -/** - * A noop (i.e., cheap-as-possible) implementation of an ActiveSpanSource. - */ -class NoopActiveSpanSourceImpl implements NoopActiveSpanSource { - @Override - public ActiveSpan makeActive(Span span) { - return NoopActiveSpanSource.NoopActiveSpan.INSTANCE; - } - - @Override - public ActiveSpan activeSpan() { return null; } - - static class NoopActiveSpanImpl implements NoopActiveSpanSource.NoopActiveSpan { - @Override - public void deactivate() {} - - @Override - public Continuation capture() { - return NoopActiveSpanSource.NoopContinuation.INSTANCE; - } - - @Override - public SpanContext context() { - return NoopSpanContextImpl.INSTANCE; - } - - @Override - public void close() {} - - @Override - public NoopActiveSpan setTag(String key, String value) { - return NoopActiveSpanSource.NoopActiveSpan.INSTANCE; - } - - @Override - public NoopActiveSpan setTag(String key, boolean value) { - return NoopActiveSpanSource.NoopActiveSpan.INSTANCE; - } - - @Override - public NoopActiveSpan setTag(String key, Number value) { - return NoopActiveSpanSource.NoopActiveSpan.INSTANCE; - } - - @Override - public NoopActiveSpan log(Map fields) { - return NoopActiveSpanSource.NoopActiveSpan.INSTANCE; - } - - @Override - public NoopActiveSpan log(long timestampMicroseconds, Map fields) { - return NoopActiveSpanSource.NoopActiveSpan.INSTANCE; - } - - @Override - public NoopActiveSpan log(String event) { - return NoopActiveSpanSource.NoopActiveSpan.INSTANCE; - } - - @Override - public NoopActiveSpan log(long timestampMicroseconds, String event) { - return NoopActiveSpanSource.NoopActiveSpan.INSTANCE; - } - - @Override - public NoopActiveSpan setBaggageItem(String key, String value) { - return NoopActiveSpanSource.NoopActiveSpan.INSTANCE; - } - - @Override - public String getBaggageItem(String key) { - return null; - } - - @Override - public NoopActiveSpan setOperationName(String operationName) { - return NoopActiveSpanSource.NoopActiveSpan.INSTANCE; - } - } - - static class NoopContinuationImpl implements NoopActiveSpanSource.NoopContinuation { - @Override - public ActiveSpan activate() { - return NoopActiveSpanSource.NoopActiveSpan.INSTANCE; - } - } -} diff --git a/opentracing-noop/src/main/java/io/opentracing/noop/NoopScopeManager.java b/opentracing-noop/src/main/java/io/opentracing/noop/NoopScopeManager.java new file mode 100644 index 00000000..2b9ab300 --- /dev/null +++ b/opentracing-noop/src/main/java/io/opentracing/noop/NoopScopeManager.java @@ -0,0 +1,56 @@ +/* + * Copyright 2016-2017 The OpenTracing Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License + * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the License for the specific language governing permissions and limitations under + * the License. + */ +package io.opentracing.noop; + +import io.opentracing.Scope; +import io.opentracing.ScopeManager; +import io.opentracing.Span; + +public interface NoopScopeManager extends ScopeManager { + NoopScopeManager INSTANCE = new NoopScopeManagerImpl(); + + interface NoopScope extends Scope { + NoopScope INSTANCE = new NoopScopeManagerImpl.NoopScopeImpl(); + } +} + +/** + * A noop (i.e., cheap-as-possible) implementation of an ScopeManager. + */ +class NoopScopeManagerImpl implements NoopScopeManager { + @Override + public Scope activate(Span span) { + return NoopScope.INSTANCE; + } + + @Override + public Scope activate(Span span, boolean finishOnClose) { + return NoopScope.INSTANCE; + } + + @Override + public Scope active() { + return null; + } + + static class NoopScopeImpl implements NoopScopeManager.NoopScope { + @Override + public void close() {} + + @Override + public Span span() { + return NoopSpan.INSTANCE; + } + } +} diff --git a/opentracing-noop/src/main/java/io/opentracing/noop/NoopSpanBuilder.java b/opentracing-noop/src/main/java/io/opentracing/noop/NoopSpanBuilder.java index 3b033833..dfda5559 100644 --- a/opentracing-noop/src/main/java/io/opentracing/noop/NoopSpanBuilder.java +++ b/opentracing-noop/src/main/java/io/opentracing/noop/NoopSpanBuilder.java @@ -13,8 +13,7 @@ */ package io.opentracing.noop; -import io.opentracing.ActiveSpan; -import io.opentracing.BaseSpan; +import io.opentracing.Scope; import io.opentracing.Span; import io.opentracing.SpanContext; import io.opentracing.Tracer; @@ -42,7 +41,7 @@ public Tracer.SpanBuilder asChildOf(SpanContext parent) { public Tracer.SpanBuilder ignoreActiveSpan() { return this; } @Override - public Tracer.SpanBuilder asChildOf(BaseSpan parent) { + public Tracer.SpanBuilder asChildOf(Span parent) { return this; } @@ -67,14 +66,18 @@ public Tracer.SpanBuilder withStartTimestamp(long microseconds) { } @Override - @Deprecated - public Span start() { - return startManual(); + public Scope startActive() { + return NoopScopeManager.NoopScope.INSTANCE; + } + + @Override + public Scope startActive(boolean finishOnClose) { + return NoopScopeManager.NoopScope.INSTANCE; } @Override - public ActiveSpan startActive() { - return NoopActiveSpanSource.NoopActiveSpan.INSTANCE; + public Span start() { + return startManual(); } @Override @@ -89,4 +92,4 @@ public Iterable> baggageItems() { @Override public String toString() { return NoopSpanBuilder.class.getSimpleName(); } -} \ No newline at end of file +} diff --git a/opentracing-noop/src/main/java/io/opentracing/noop/NoopTracer.java b/opentracing-noop/src/main/java/io/opentracing/noop/NoopTracer.java index 678a302a..3fb63804 100644 --- a/opentracing-noop/src/main/java/io/opentracing/noop/NoopTracer.java +++ b/opentracing-noop/src/main/java/io/opentracing/noop/NoopTracer.java @@ -13,8 +13,7 @@ */ package io.opentracing.noop; -import io.opentracing.ActiveSpan; -import io.opentracing.Span; +import io.opentracing.ScopeManager; import io.opentracing.SpanContext; import io.opentracing.Tracer; import io.opentracing.propagation.Format; @@ -25,6 +24,11 @@ public interface NoopTracer extends Tracer { final class NoopTracerImpl implements NoopTracer { final static NoopTracer INSTANCE = new NoopTracerImpl(); + @Override + public ScopeManager scopeManager() { + return NoopScopeManager.INSTANCE; + } + @Override public SpanBuilder buildSpan(String operationName) { return NoopSpanBuilderImpl.INSTANCE; } @@ -36,15 +40,5 @@ public void inject(SpanContext spanContext, Format format, C carrier) {} @Override public String toString() { return NoopTracer.class.getSimpleName(); } - - @Override - public ActiveSpan activeSpan() { - return null; - } - - @Override - public ActiveSpan makeActive(Span span) { - return NoopActiveSpanSource.NoopActiveSpan.INSTANCE; - } } diff --git a/opentracing-util/src/main/java/io/opentracing/util/GlobalTracer.java b/opentracing-util/src/main/java/io/opentracing/util/GlobalTracer.java index 89b6f073..24ef261b 100644 --- a/opentracing-util/src/main/java/io/opentracing/util/GlobalTracer.java +++ b/opentracing-util/src/main/java/io/opentracing/util/GlobalTracer.java @@ -13,10 +13,9 @@ */ package io.opentracing.util; -import io.opentracing.ActiveSpan; +import io.opentracing.ScopeManager; import io.opentracing.noop.NoopTracer; import io.opentracing.noop.NoopTracerFactory; -import io.opentracing.Span; import io.opentracing.SpanContext; import io.opentracing.Tracer; import io.opentracing.propagation.Format; @@ -123,6 +122,11 @@ public static synchronized boolean isRegistered() { return !(GlobalTracer.tracer instanceof NoopTracer); } + @Override + public ScopeManager scopeManager() { + return tracer.scopeManager(); + } + @Override public SpanBuilder buildSpan(String operationName) { return tracer.buildSpan(operationName); @@ -142,14 +146,4 @@ public SpanContext extract(Format format, C carrier) { public String toString() { return GlobalTracer.class.getSimpleName() + '{' + tracer + '}'; } - - @Override - public ActiveSpan activeSpan() { - return tracer.activeSpan(); - } - - @Override - public ActiveSpan makeActive(Span span) { - return tracer.makeActive(span); - } } diff --git a/opentracing-util/src/main/java/io/opentracing/util/ThreadLocalActiveSpan.java b/opentracing-util/src/main/java/io/opentracing/util/ThreadLocalActiveSpan.java deleted file mode 100644 index ba90ca43..00000000 --- a/opentracing-util/src/main/java/io/opentracing/util/ThreadLocalActiveSpan.java +++ /dev/null @@ -1,149 +0,0 @@ -/* - * Copyright 2016-2017 The OpenTracing Authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except - * in compliance with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software distributed under the License - * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express - * or implied. See the License for the specific language governing permissions and limitations under - * the License. - */ -package io.opentracing.util; - -import java.util.Map; -import java.util.concurrent.atomic.AtomicInteger; - -import io.opentracing.ActiveSpan; -import io.opentracing.ActiveSpanSource; -import io.opentracing.Span; -import io.opentracing.SpanContext; -import io.opentracing.Tracer; - -/** - * {@link ThreadLocalActiveSpan} is a simple {@link ActiveSpan} implementation that relies on Java's - * thread-local storage primitive. - * - * @see ActiveSpanSource - * @see Tracer#activeSpan() - */ -public class ThreadLocalActiveSpan implements ActiveSpan { - private final ThreadLocalActiveSpanSource source; - private final Span wrapped; - private final ThreadLocalActiveSpan toRestore; - private final AtomicInteger refCount; - - ThreadLocalActiveSpan(ThreadLocalActiveSpanSource source, Span wrapped, AtomicInteger refCount) { - this.source = source; - this.refCount = refCount; - this.wrapped = wrapped; - this.toRestore = source.tlsSnapshot.get(); - source.tlsSnapshot.set(this); - } - - @Override - public void deactivate() { - if (source.tlsSnapshot.get() != this) { - // This shouldn't happen if users call methods in the expected order. Bail out. - return; - } - source.tlsSnapshot.set(toRestore); - - if (0 == refCount.decrementAndGet()) { - wrapped.finish(); - } - } - - @Override - public Continuation capture() { - return new ThreadLocalActiveSpan.Continuation(); - } - - @Override - public SpanContext context() { - return wrapped.context(); - } - - @Override - public ThreadLocalActiveSpan setTag(String key, String value) { - wrapped.setTag(key, value); - return this; - } - - @Override - public ThreadLocalActiveSpan setTag(String key, boolean value) { - wrapped.setTag(key, value); - return this; - } - - @Override - public ThreadLocalActiveSpan setTag(String key, Number value) { - wrapped.setTag(key, value); - return this; - } - - @Override - public ThreadLocalActiveSpan log(Map fields) { - wrapped.log(fields); - return this; - } - - @Override - public ThreadLocalActiveSpan log(long timestampMicroseconds, Map fields) { - wrapped.log(timestampMicroseconds, fields); - return this; - } - - @Override - public ThreadLocalActiveSpan log(String event) { - wrapped.log(event); - return this; - } - - @Override - public ThreadLocalActiveSpan log(long timestampMicroseconds, String event) { - wrapped.log(timestampMicroseconds, event); - return this; - } - - @Override - public ThreadLocalActiveSpan setBaggageItem(String key, String value) { - wrapped.setBaggageItem(key, value); - return this; - } - - @Override - public String getBaggageItem(String key) { - return wrapped.getBaggageItem(key); - } - - @Override - public ThreadLocalActiveSpan setOperationName(String operationName) { - wrapped.setOperationName(operationName); - return this; - } - - @Override - public void close() { - deactivate(); - } - - @Override - public String toString() { - return wrapped.toString(); - } - - private final class Continuation implements ActiveSpan.Continuation { - Continuation() { - refCount.incrementAndGet(); - } - - @Override - public ThreadLocalActiveSpan activate() { - return new ThreadLocalActiveSpan(source, wrapped, refCount); - } - } - -} diff --git a/opentracing-util/src/main/java/io/opentracing/util/ThreadLocalScope.java b/opentracing-util/src/main/java/io/opentracing/util/ThreadLocalScope.java new file mode 100644 index 00000000..45ab6d5f --- /dev/null +++ b/opentracing-util/src/main/java/io/opentracing/util/ThreadLocalScope.java @@ -0,0 +1,58 @@ +/* + * Copyright 2016-2017 The OpenTracing Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License + * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the License for the specific language governing permissions and limitations under + * the License. + */ +package io.opentracing.util; + +import io.opentracing.Scope; +import io.opentracing.ScopeManager; +import io.opentracing.Span; + +/** + * {@link ThreadLocalScope} is a simple {@link Scope} implementation that relies on Java's + * thread-local storage primitive. + * + * @see ScopeManager + */ +public class ThreadLocalScope implements Scope { + private final ThreadLocalScopeManager scopeManager; + private final Span wrapped; + private final boolean finishOnClose; + private final ThreadLocalScope toRestore; + + ThreadLocalScope(ThreadLocalScopeManager scopeManager, Span wrapped, boolean finishOnClose) { + this.scopeManager = scopeManager; + this.wrapped = wrapped; + this.finishOnClose = finishOnClose; + this.toRestore = scopeManager.tlsScope.get(); + scopeManager.tlsScope.set(this); + } + + @Override + public void close() { + if (scopeManager.tlsScope.get() != this) { + // This shouldn't happen if users call methods in the expected order. Bail out. + return; + } + + if (finishOnClose) { + wrapped.finish(); + } + + scopeManager.tlsScope.set(toRestore); + } + + @Override + public Span span() { + return wrapped; + } +} diff --git a/opentracing-util/src/main/java/io/opentracing/util/ThreadLocalScopeManager.java b/opentracing-util/src/main/java/io/opentracing/util/ThreadLocalScopeManager.java new file mode 100644 index 00000000..095c4c8f --- /dev/null +++ b/opentracing-util/src/main/java/io/opentracing/util/ThreadLocalScopeManager.java @@ -0,0 +1,42 @@ +/* + * Copyright 2016-2017 The OpenTracing Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License + * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the License for the specific language governing permissions and limitations under + * the License. + */ +package io.opentracing.util; + +import io.opentracing.Scope; +import io.opentracing.ScopeManager; +import io.opentracing.Span; + +/** + * A simple {@link ScopeManager} implementation built on top of Java's thread-local storage primitive. + * + * @see ThreadLocalScope + */ +public class ThreadLocalScopeManager implements ScopeManager { + final ThreadLocal tlsScope = new ThreadLocal(); + + @Override + public Scope activate(Span span) { + return new ThreadLocalScope(this, span, true); + } + + @Override + public Scope activate(Span span, boolean finishOnClose) { + return new ThreadLocalScope(this, span, finishOnClose); + } + + @Override + public Scope active() { + return tlsScope.get(); + } +} diff --git a/opentracing-util/src/test/java/io/opentracing/util/ThreadLocalActiveSpanSourceTest.java b/opentracing-util/src/test/java/io/opentracing/util/ThreadLocalActiveSpanSourceTest.java deleted file mode 100644 index 180662ee..00000000 --- a/opentracing-util/src/test/java/io/opentracing/util/ThreadLocalActiveSpanSourceTest.java +++ /dev/null @@ -1,60 +0,0 @@ -/* - * Copyright 2016-2017 The OpenTracing Authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except - * in compliance with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software distributed under the License - * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express - * or implied. See the License for the specific language governing permissions and limitations under - * the License. - */ -package io.opentracing.util; - -import io.opentracing.ActiveSpan; -import io.opentracing.Span; -import org.junit.Before; -import org.junit.Test; - -import static org.junit.Assert.*; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.verify; - -public class ThreadLocalActiveSpanSourceTest { - private ThreadLocalActiveSpanSource source; - @Before - public void before() throws Exception { - source = new ThreadLocalActiveSpanSource(); - } - - @Test - public void missingActiveSpan() throws Exception { - ActiveSpan missingSpan = source.activeSpan(); - assertNull(missingSpan); - } - - @Test - public void makeActiveSpan() throws Exception { - Span span = mock(Span.class); - - // We can't use 1.7 features like try-with-resources in this repo without meddling with pom details for tests. - ActiveSpan activeSpan = source.makeActive(span); - try { - assertNotNull(activeSpan); - ActiveSpan otherActiveSpan = source.activeSpan(); - assertEquals(otherActiveSpan, activeSpan); - } finally { - activeSpan.close(); - } - - // Make sure the Span got finish()ed. - verify(span).finish(); - - // And now it's gone: - ActiveSpan missingSpan = source.activeSpan(); - assertNull(missingSpan); - } - -} \ No newline at end of file diff --git a/opentracing-util/src/test/java/io/opentracing/util/ThreadLocalScopeManagerTest.java b/opentracing-util/src/test/java/io/opentracing/util/ThreadLocalScopeManagerTest.java new file mode 100644 index 00000000..c5e2fc30 --- /dev/null +++ b/opentracing-util/src/test/java/io/opentracing/util/ThreadLocalScopeManagerTest.java @@ -0,0 +1,102 @@ +/* + * Copyright 2016-2017 The OpenTracing Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License + * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the License for the specific language governing permissions and limitations under + * the License. + */ +package io.opentracing.util; + +import io.opentracing.Scope; +import io.opentracing.Span; +import org.junit.Before; +import org.junit.Test; + +import static org.junit.Assert.*; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.never; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; + +public class ThreadLocalScopeManagerTest { + private ThreadLocalScopeManager source; + + @Before + public void before() throws Exception { + source = new ThreadLocalScopeManager(); + } + + @Test + public void missingActiveScope() throws Exception { + Scope missingScope = source.active(); + assertNull(missingScope); + } + + @Test + public void activateSpan() throws Exception { + Span span = mock(Span.class); + + // We can't use 1.7 features like try-with-resources in this repo without meddling with pom details for tests. + Scope scope = source.activate(span); + try { + assertNotNull(scope); + Scope otherScope = source.active(); + assertEquals(otherScope, scope); + } finally { + scope.close(); + } + + // Make sure the Span got finish()ed. + verify(span, times(1)).finish(); + + // And now it's gone: + Scope missingScope = source.active(); + assertNull(missingScope); + } + + @Test + public void activateSpanClose() throws Exception { + Span span = mock(Span.class); + + // We can't use 1.7 features like try-with-resources in this repo without meddling with pom details for tests. + Scope scope = source.activate(span, true); + try { + assertNotNull(scope); + assertNotNull(source.active()); + } finally { + scope.close(); + } + + // Make sure the Span got finish()ed. + verify(span, times(1)).finish(); + + // Verify it's gone. + assertNull(source.active()); + } + + @Test + public void activateSpanNoClose() throws Exception { + Span span = mock(Span.class); + + // We can't use 1.7 features like try-with-resources in this repo without meddling with pom details for tests. + Scope scope = source.activate(span, false); + try { + assertNotNull(scope); + assertNotNull(source.active()); + } finally { + scope.close(); + } + + // Make sure the Span did *not* get finish()ed. + verify(span, never()).finish(); + + // Verify it's gone. + assertNull(source.active()); + } +} diff --git a/opentracing-util/src/test/java/io/opentracing/util/ThreadLocalActiveSpanTest.java b/opentracing-util/src/test/java/io/opentracing/util/ThreadLocalScopeTest.java similarity index 56% rename from opentracing-util/src/test/java/io/opentracing/util/ThreadLocalActiveSpanTest.java rename to opentracing-util/src/test/java/io/opentracing/util/ThreadLocalScopeTest.java index 06d49093..e97c4cbd 100644 --- a/opentracing-util/src/test/java/io/opentracing/util/ThreadLocalActiveSpanTest.java +++ b/opentracing-util/src/test/java/io/opentracing/util/ThreadLocalScopeTest.java @@ -21,49 +21,17 @@ import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; -import io.opentracing.ActiveSpan; +import io.opentracing.Scope; import io.opentracing.Span; import org.junit.Before; import org.junit.Test; -public class ThreadLocalActiveSpanTest { - private ThreadLocalActiveSpanSource source; +public class ThreadLocalScopeTest { + private ThreadLocalScopeManager scopeManager; @Before public void before() throws Exception { - source = new ThreadLocalActiveSpanSource(); - } - - @Test - public void continuation() throws Exception { - Span span = mock(Span.class); - - // Quasi try-with-resources (this is 1.6). - ActiveSpan activeSpan = source.makeActive(span); - ActiveSpan.Continuation continued = null; - try { - assertNotNull(activeSpan); - continued = activeSpan.capture(); - } finally { - activeSpan.close(); - } - - // Make sure the Span was not finished since there was a capture(). - verify(span, never()).finish(); - - // Activate the continuation. - try { - activeSpan = continued.activate(); - } finally { - activeSpan.close(); - } - - // Now the Span should be finished. - verify(span, times(1)).finish(); - - // And now it's no longer active. - ActiveSpan missingSpan = source.activeSpan(); - assertNull(missingSpan); + scopeManager = new ThreadLocalScopeManager(); } @Test @@ -72,21 +40,21 @@ public void implicitSpanStack() throws Exception { Span foregroundSpan = mock(Span.class); // Quasi try-with-resources (this is 1.6). - ActiveSpan backgroundActive = source.makeActive(backgroundSpan); + Scope backgroundActive = scopeManager.activate(backgroundSpan); try { assertNotNull(backgroundActive); - // Activate a new ActiveSpan on top of the background one. - ActiveSpan foregroundActive = source.makeActive(foregroundSpan); + // Activate a new Scope on top of the background one. + Scope foregroundActive = scopeManager.activate(foregroundSpan); try { - ActiveSpan shouldBeForeground = source.activeSpan(); + Scope shouldBeForeground = scopeManager.active(); assertEquals(foregroundActive, shouldBeForeground); } finally { foregroundActive.close(); } // And now the backgroundActive should be reinstated. - ActiveSpan shouldBeBackground = source.activeSpan(); + Scope shouldBeBackground = scopeManager.active(); assertEquals(backgroundActive, shouldBeBackground); } finally { backgroundActive.close(); @@ -97,7 +65,7 @@ public void implicitSpanStack() throws Exception { verify(foregroundSpan, times(1)).finish(); // And now nothing is active. - ActiveSpan missingSpan = source.activeSpan(); + Scope missingSpan = scopeManager.active(); assertNull(missingSpan); } @@ -105,9 +73,9 @@ public void implicitSpanStack() throws Exception { public void testDeactivateWhenDifferentSpanIsActive() { Span span = mock(Span.class); - ActiveSpan activeSpan = source.makeActive(span); - source.makeActive(mock(Span.class)); - activeSpan.deactivate(); + Scope active = scopeManager.activate(span); + scopeManager.activate(mock(Span.class)); + active.close(); verify(span, times(0)).finish(); } From fe24aa1c16eca3232e36d468104a8de54a720344 Mon Sep 17 00:00:00 2001 From: Pavol Loffay Date: Tue, 26 Sep 2017 09:13:37 +0200 Subject: [PATCH 08/19] travis publish.sh allow releases from branches (#191) --- travis/publish.sh | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/travis/publish.sh b/travis/publish.sh index 10701263..584fb8b0 100755 --- a/travis/publish.sh +++ b/travis/publish.sh @@ -35,12 +35,12 @@ is_pull_request() { fi } -is_travis_branch_master() { - if [ "${TRAVIS_BRANCH}" = master ]; then - echo "[Publishing] Travis branch is master" +is_travis_branch_master_or_release() { + if [[ "${TRAVIS_BRANCH}" == "master" || "${TRAVIS_BRANCH}" =~ ^[0-9]+\.[0-9]+\.[0-9]+$ ]]; then + echo "[Publishing] Travis branch is ${TRAVIS_BRANCH}" return 0 else - echo "[Not Publishing] Travis branch is not master" + echo "[Not Publishing] Travis branch is not master or 0.0.0" return 1 fi } @@ -60,12 +60,12 @@ check_travis_branch_equals_travis_tag() { check_release_tag() { tag="${TRAVIS_TAG}" - if [[ "$tag" =~ ^[[:digit:]]+\.[[:digit:]]+\.[[:digit:]]+(\.RC[[:digit:]]+)?$ ]]; then + if [[ "$tag" =~ ^[[:digit:]]+\.[[:digit:]]+\.[[:digit:]]+(\-RC[[:digit:]]+)?$ ]]; then echo "Build started by version tag $tag. During the release process tags like this" echo "are created by the 'release' Maven plugin. Nothing to do here." exit 0 - elif [[ ! "$tag" =~ ^release-[[:digit:]]+\.[[:digit:]]+\.[[:digit:]]+(\.RC[[:digit:]]+)?$ ]]; then - echo "You must specify a tag of the format 'release-0.0.0' or 'release-0.0.0.RC0' to release this project." + elif [[ ! "$tag" =~ ^release-[[:digit:]]+\.[[:digit:]]+\.[[:digit:]]+(\-RC[[:digit:]]+)?$ ]]; then + echo "You must specify a tag of the format 'release-0.0.0' or 'release-0.0.0-RC0' to release this project." echo "The provided tag ${tag} doesn't match that. Aborting." exit 1 fi @@ -73,7 +73,7 @@ check_release_tag() { is_release_commit() { project_version=$(./mvnw help:evaluate -N -Dexpression=project.version|sed -n '/^[0-9]/p') - if [[ "$project_version" =~ ^[[:digit:]]+\.[[:digit:]]+\.[[:digit:]]+(\.RC[[:digit:]]+)?$ ]]; then + if [[ "$project_version" =~ ^[[:digit:]]+\.[[:digit:]]+\.[[:digit:]]+(\-RC[[:digit:]]+)?$ ]]; then echo "Build started by release commit $project_version. Will synchronize to maven central." return 0 else @@ -115,7 +115,7 @@ if is_pull_request; then true # If we are on master, we will deploy the latest snapshot or release version # - If a release commit fails to deploy for a transient reason, delete the broken version from bintray and click rebuild -elif is_travis_branch_master; then +elif is_travis_branch_master_or_release; then ./mvnw --batch-mode -s ./.settings.xml -Prelease -nsu -DskipTests deploy # If the deployment succeeded, sync it to Maven Central. Note: this needs to be done once per project, not module, hence -N From 7d6fe210bd8a332320834a80d87dff5b032b5a61 Mon Sep 17 00:00:00 2001 From: Pavol Loffay Date: Tue, 26 Sep 2017 11:32:07 +0200 Subject: [PATCH 09/19] Travis allow release from non master branches (#192) * Travis allow release from non master branches Publis script compares remote branch with current checkout. This passes travis_branch into git checkout command so it will compare the same branches. * Fix comments --- travis/publish.sh | 23 ++++++++++++----------- 1 file changed, 12 insertions(+), 11 deletions(-) diff --git a/travis/publish.sh b/travis/publish.sh index 584fb8b0..d7968447 100755 --- a/travis/publish.sh +++ b/travis/publish.sh @@ -85,16 +85,17 @@ release_version() { echo "${TRAVIS_TAG}" | sed 's/^release-//' } -safe_checkout_master() { - # We need to be on a branch for release:perform to be able to create commits, and we want that branch to be master. - # But we also want to make sure that we build and release exactly the tagged version, so we verify that the remote - # master is where our tag is. - git checkout -B master - git fetch origin master:origin/master - commit_local_master="$(git show --pretty='format:%H' master)" - commit_remote_master="$(git show --pretty='format:%H' origin/master)" - if [ "$commit_local_master" != "$commit_remote_master" ]; then - echo "Master on remote 'origin' has commits since the version under release, aborting" +safe_checkout_remote_branch() { + # We need to be on a branch for release:perform to be able to create commits, + # and we want that branch to be master or 0.0.0. which has been checked before. + # But we also want to make sure that we build and release exactly the tagged version, + # so we verify that the remote branch is where our tag is. + git checkout -B "${TRAVIS_BRANCH}" + git fetch origin "${TRAVIS_BRANCH}":origin/"${TRAVIS_BRANCH}" + commit_local="$(git show --pretty='format:%H' ${TRAVIS_BRANCH})" + commit_remote="$(git show --pretty='format:%H' origin/${TRAVIS_BRANCH})" + if [ "$commit_local" != "$commit_remote" ]; then + echo "${TRAVIS_BRANCH} on remote 'origin' has commits since the version under release, aborting" exit 1 fi } @@ -125,7 +126,7 @@ elif is_travis_branch_master_or_release; then # If we are on a release tag, the following will update any version references and push a version tag for deployment. elif build_started_by_tag; then - safe_checkout_master + safe_checkout_remote_branch ./mvnw --batch-mode -s ./.settings.xml -Prelease -nsu -DreleaseVersion="$(release_version)" -Darguments="-DskipTests" release:prepare fi From be1a7200c8eb00d9ed33228644a4e4b1b0f95f05 Mon Sep 17 00:00:00 2001 From: Pavol Loffay Date: Tue, 26 Sep 2017 14:47:22 +0200 Subject: [PATCH 10/19] Travis publish script, remove -RC on git checkout (#193) --- travis/publish.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/travis/publish.sh b/travis/publish.sh index d7968447..23366a01 100755 --- a/travis/publish.sh +++ b/travis/publish.sh @@ -90,7 +90,7 @@ safe_checkout_remote_branch() { # and we want that branch to be master or 0.0.0. which has been checked before. # But we also want to make sure that we build and release exactly the tagged version, # so we verify that the remote branch is where our tag is. - git checkout -B "${TRAVIS_BRANCH}" + git checkout -B `release_version | sed 's/-RC[[:digit:]]\+//'` git fetch origin "${TRAVIS_BRANCH}":origin/"${TRAVIS_BRANCH}" commit_local="$(git show --pretty='format:%H' ${TRAVIS_BRANCH})" commit_remote="$(git show --pretty='format:%H' origin/${TRAVIS_BRANCH})" From c02a43abbcd81f95ef5aec78d3844877661547dc Mon Sep 17 00:00:00 2001 From: Carlos Alberto Cortez Date: Thu, 28 Sep 2017 22:48:48 +0900 Subject: [PATCH 11/19] Update the Travis script to allow publishing from v.0.0.0 branches. (#195) Thing is, we cannot publish from 0.0.0-style branches as they are excluded, based on the current global Travis configuration, thus we try to publish from branches following a v.0.0.0 style, if any. --- travis/publish.sh | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/travis/publish.sh b/travis/publish.sh index 23366a01..6837e433 100755 --- a/travis/publish.sh +++ b/travis/publish.sh @@ -36,11 +36,11 @@ is_pull_request() { } is_travis_branch_master_or_release() { - if [[ "${TRAVIS_BRANCH}" == "master" || "${TRAVIS_BRANCH}" =~ ^[0-9]+\.[0-9]+\.[0-9]+$ ]]; then + if [[ "${TRAVIS_BRANCH}" == "master" || "${TRAVIS_BRANCH}" =~ ^v[0-9]+\.[0-9]+\.[0-9]+$ ]]; then echo "[Publishing] Travis branch is ${TRAVIS_BRANCH}" return 0 else - echo "[Not Publishing] Travis branch is not master or 0.0.0" + echo "[Not Publishing] Travis branch is not master or v0.0.0" return 1 fi } @@ -87,10 +87,10 @@ release_version() { safe_checkout_remote_branch() { # We need to be on a branch for release:perform to be able to create commits, - # and we want that branch to be master or 0.0.0. which has been checked before. + # and we want that branch to be master or v0.0.0. which has been checked before. # But we also want to make sure that we build and release exactly the tagged version, # so we verify that the remote branch is where our tag is. - git checkout -B `release_version | sed 's/-RC[[:digit:]]\+//'` + git checkout -B v`release_version | sed 's/-RC[[:digit:]]\+//'` git fetch origin "${TRAVIS_BRANCH}":origin/"${TRAVIS_BRANCH}" commit_local="$(git show --pretty='format:%H' ${TRAVIS_BRANCH})" commit_remote="$(git show --pretty='format:%H' origin/${TRAVIS_BRANCH})" From 89323e529133d3e033bad99dee5d19d75ae8b00d Mon Sep 17 00:00:00 2001 From: Pavol Loffay Date: Mon, 9 Oct 2017 13:48:32 +0200 Subject: [PATCH 12/19] Readme document release process for release candidates (#198) * Readme document release process for release candidates * Adjust publish.sh to work with release from master branch --- RELEASE.md | 9 ++++++++- travis/publish.sh | 16 ++++++++++------ 2 files changed, 18 insertions(+), 7 deletions(-) diff --git a/RELEASE.md b/RELEASE.md index 73cdb221..48edb2af 100644 --- a/RELEASE.md +++ b/RELEASE.md @@ -16,7 +16,14 @@ This repo uses semantic versions. Please keep this in mind when choosing version This part is controlled by [`travis/publish.sh`](travis/publish.sh). It creates a bunch of new commits, bumps the version, publishes artifacts, and syncs to Maven Central. - + +## Release candidates + +Repository supports releasing release candidates from branches `v.N.M.L`. The version schema +for release candidates is `N.M.L-RCH`, where `H` denotes a release candidate version. + +To release the first release candidate switch to a branch `v.3.7.1`/`HEAD` and push a tag `release-3.7.1-RC1`. + ## Credentials Credentials of various kind are needed for the release process to work. If you notice something diff --git a/travis/publish.sh b/travis/publish.sh index 6837e433..48c24f61 100755 --- a/travis/publish.sh +++ b/travis/publish.sh @@ -87,15 +87,19 @@ release_version() { safe_checkout_remote_branch() { # We need to be on a branch for release:perform to be able to create commits, - # and we want that branch to be master or v0.0.0. which has been checked before. + # and we want that branch to be master or v0.0.0 (for RCs). which has been checked before. # But we also want to make sure that we build and release exactly the tagged version, # so we verify that the remote branch is where our tag is. - git checkout -B v`release_version | sed 's/-RC[[:digit:]]\+//'` - git fetch origin "${TRAVIS_BRANCH}":origin/"${TRAVIS_BRANCH}" - commit_local="$(git show --pretty='format:%H' ${TRAVIS_BRANCH})" - commit_remote="$(git show --pretty='format:%H' origin/${TRAVIS_BRANCH})" + checkoutBranch=master + if [[ "${TRAVIS_BRANCH}" =~ ^release-[[:digit:]]+\.[[:digit:]]+\.[[:digit:]]+\-RC[[:digit:]]+$ ]]; then + checkoutBranch=v`release_version | sed 's/-RC[[:digit:]]\+//'` + fi + git checkout -B "${checkoutBranch}" + git fetch origin "${checkoutBranch}":origin/"${checkoutBranch}" + commit_local="$(git show --pretty='format:%H' ${checkoutBranch})" + commit_remote="$(git show --pretty='format:%H' origin/${checkoutBranch})" if [ "$commit_local" != "$commit_remote" ]; then - echo "${TRAVIS_BRANCH} on remote 'origin' has commits since the version under release, aborting" + echo "${checkoutBranch} on remote 'origin' has commits since the version under release, aborting" exit 1 fi } From 0ab157cd1291119610335cbe57f88aa0e1d198e4 Mon Sep 17 00:00:00 2001 From: Tyler Benson Date: Thu, 9 Nov 2017 13:56:23 -0500 Subject: [PATCH 13/19] Add Examples for async use cases (#197) * Add examples for async as test cases This includes execution flow similar to: * Actor ask/tell * Promises with callbacks * Work interleaved on a thread using suspend/resume. The implementations of these execution models are obviously very simplistic, but intended to emphasize the tracing aspect. --- opentracing-examples/README.md | 4 +- .../io/opentracing/examples/TestUtils.java | 24 +++- .../examples/actor_propagation/Actor.java | 94 +++++++++++++ .../ActorPropagationTest.java | 127 ++++++++++++++++++ .../examples/promise_propagation/Promise.java | 97 +++++++++++++ .../promise_propagation/PromiseContext.java | 44 ++++++ .../PromisePropagationTest.java | 120 +++++++++++++++++ .../SuspendResume.java | 52 +++++++ .../SuspendResumePropagationTest.java | 73 ++++++++++ 9 files changed, 627 insertions(+), 8 deletions(-) create mode 100644 opentracing-examples/src/test/java/io/opentracing/examples/actor_propagation/Actor.java create mode 100644 opentracing-examples/src/test/java/io/opentracing/examples/actor_propagation/ActorPropagationTest.java create mode 100644 opentracing-examples/src/test/java/io/opentracing/examples/promise_propagation/Promise.java create mode 100644 opentracing-examples/src/test/java/io/opentracing/examples/promise_propagation/PromiseContext.java create mode 100644 opentracing-examples/src/test/java/io/opentracing/examples/promise_propagation/PromisePropagationTest.java create mode 100644 opentracing-examples/src/test/java/io/opentracing/examples/suspend_resume_propagation/SuspendResume.java create mode 100644 opentracing-examples/src/test/java/io/opentracing/examples/suspend_resume_propagation/SuspendResumePropagationTest.java diff --git a/opentracing-examples/README.md b/opentracing-examples/README.md index 8cf60602..2807c9e4 100644 --- a/opentracing-examples/README.md +++ b/opentracing-examples/README.md @@ -10,10 +10,12 @@ List of patterns: - **activate_deactivate** - actions are executed by scheduler. It shows continuation as a solution to finish span when last action is completed. - **active_span_replacement** - start an isolated task and query for its result in another task/thread +- **actor_propagation** - tracing for blocking and non-blocking actor based tracing - **client_server** - typical client-server example - **common_request_handler** - one request handler for all requests - **late_span_finish** - late parent span finish - **listener_per_request** - one listener per request - **multiple_callbacks** - many callbacks spawned at the same time - **nested_callbacks** - one callback at the time, defined in a pipeline fashion - +- **promise_propagation** - tracing patterns for promises with callbacks +- **suspend_resume_propagation** - tracing pattern for interleaving of spans diff --git a/opentracing-examples/src/test/java/io/opentracing/examples/TestUtils.java b/opentracing-examples/src/test/java/io/opentracing/examples/TestUtils.java index 3070709f..0bc544b3 100644 --- a/opentracing-examples/src/test/java/io/opentracing/examples/TestUtils.java +++ b/opentracing-examples/src/test/java/io/opentracing/examples/TestUtils.java @@ -17,6 +17,7 @@ import io.opentracing.mock.MockTracer; import io.opentracing.tag.AbstractTag; +import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; import java.util.List; @@ -37,20 +38,29 @@ public Integer call() throws Exception { }; } - public static MockSpan getOneByTag(List spans, AbstractTag key, Object value) { - MockSpan found = null; + public static List getByTag(List spans, AbstractTag key, Object value) { + List found = new ArrayList<>(spans.size()); for (MockSpan span : spans) { if (span.tags().get(key.getKey()).equals(value)) { - if (found != null) { - throw new IllegalArgumentException("there is more than one span with tag '" - + key.getKey() + "' and value '" + value + "'"); - } - found = span; + found.add(span); } } return found; } + public static MockSpan getOneByTag(List spans, AbstractTag key, Object value) { + List found = getByTag(spans, key, value); + if (found.size() > 1) { + throw new IllegalArgumentException("there is more than one span with tag '" + + key.getKey() + "' and value '" + value + "'"); + } + if (found.isEmpty()) { + return null; + } else { + return found.get(0); + } + } + public static void sleep() { try { TimeUnit.MILLISECONDS.sleep(new Random().nextInt(2000)); diff --git a/opentracing-examples/src/test/java/io/opentracing/examples/actor_propagation/Actor.java b/opentracing-examples/src/test/java/io/opentracing/examples/actor_propagation/Actor.java new file mode 100644 index 00000000..10f812b1 --- /dev/null +++ b/opentracing-examples/src/test/java/io/opentracing/examples/actor_propagation/Actor.java @@ -0,0 +1,94 @@ +/* + * Copyright 2016-2017 The OpenTracing Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License + * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the License for the specific language governing permissions and limitations under + * the License. + */ +package io.opentracing.examples.actor_propagation; + +import io.opentracing.References; +import io.opentracing.Scope; +import io.opentracing.Span; +import io.opentracing.mock.MockTracer; +import io.opentracing.tag.Tags; +import java.util.concurrent.Callable; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.Future; +import java.util.concurrent.Phaser; + +/** @author tylerbenson */ +public class Actor implements AutoCloseable { + private final ExecutorService executor; + private final MockTracer tracer; + private final Phaser phaser; + + public Actor(MockTracer tracer, Phaser phaser) { + // Passed along here for testing. Normally should be referenced via GlobalTracer.get(). + this.tracer = tracer; + + this.phaser = phaser; + executor = Executors.newFixedThreadPool(2); + } + + @Override + public void close() { + executor.shutdown(); + } + + public void tell(final String message) { + final Span parent = tracer.scopeManager().active().span(); + phaser.register(); + executor.submit( + new Runnable() { + @Override + public void run() { + try (Scope child = + tracer + .buildSpan("received") + .addReference(References.FOLLOWS_FROM, parent.context()) + .withTag(Tags.SPAN_KIND.getKey(), Tags.SPAN_KIND_CONSUMER) + .startActive()) { + phaser.arriveAndAwaitAdvance(); // child tracer started + child.span().log("received " + message); + phaser.arriveAndAwaitAdvance(); // assert size + } + phaser.arriveAndAwaitAdvance(); // child tracer finished + phaser.arriveAndAwaitAdvance(); // assert size + } + }); + } + + public Future ask(final String message) { + final Span parent = tracer.scopeManager().active().span(); + phaser.register(); + Future future = + executor.submit( + new Callable() { + @Override + public String call() throws Exception { + try (Scope child = + tracer + .buildSpan("received") + .addReference(References.FOLLOWS_FROM, parent.context()) + .withTag(Tags.SPAN_KIND.getKey(), Tags.SPAN_KIND_CONSUMER) + .startActive()) { + phaser.arriveAndAwaitAdvance(); // child tracer started + phaser.arriveAndAwaitAdvance(); // assert size + return "received " + message; + } finally { + phaser.arriveAndAwaitAdvance(); // child tracer finished + phaser.arriveAndAwaitAdvance(); // assert size + } + } + }); + return future; + } +} diff --git a/opentracing-examples/src/test/java/io/opentracing/examples/actor_propagation/ActorPropagationTest.java b/opentracing-examples/src/test/java/io/opentracing/examples/actor_propagation/ActorPropagationTest.java new file mode 100644 index 00000000..a4e72b9f --- /dev/null +++ b/opentracing-examples/src/test/java/io/opentracing/examples/actor_propagation/ActorPropagationTest.java @@ -0,0 +1,127 @@ +/* + * Copyright 2016-2017 The OpenTracing Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License + * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the License for the specific language governing permissions and limitations under + * the License. + */ +package io.opentracing.examples.actor_propagation; + +import io.opentracing.Scope; +import io.opentracing.mock.MockSpan; +import io.opentracing.mock.MockTracer; +import io.opentracing.mock.MockTracer.Propagator; +import io.opentracing.tag.Tags; +import io.opentracing.util.ThreadLocalScopeManager; +import org.junit.Before; +import org.junit.Test; + +import java.util.List; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.Future; +import java.util.concurrent.Phaser; + +import static io.opentracing.examples.TestUtils.getByTag; +import static io.opentracing.examples.TestUtils.getOneByTag; +import static org.assertj.core.api.Assertions.assertThat; + +/** + * These tests are intended to simulate the kind of async models that are common in java async + * frameworks. + * + * For improved readability, ignore the phaser lines as those are there to ensure deterministic + * execution for the tests without sleeps. + * + * @author tylerbenson + */ +public class ActorPropagationTest { + + private final MockTracer tracer = + new MockTracer(new ThreadLocalScopeManager(), Propagator.TEXT_MAP); + private Phaser phaser; + + @Before + public void before() { + phaser = new Phaser(); + } + + @Test + public void testActorTell() { + try (Actor actor = new Actor(tracer, phaser)) { + phaser.register(); + try (Scope parent = + tracer + .buildSpan("actorTell") + .withTag(Tags.SPAN_KIND.getKey(), Tags.SPAN_KIND_PRODUCER) + .withTag(Tags.COMPONENT.getKey(), "example-actor") + .startActive()) { + actor.tell("my message 1"); + actor.tell("my message 2"); + } + phaser.arriveAndAwaitAdvance(); // child tracer started + assertThat(tracer.finishedSpans().size()).isEqualTo(1); // Parent should be reported + phaser.arriveAndAwaitAdvance(); // continue... + + phaser.arriveAndAwaitAdvance(); // child tracer finished + assertThat(tracer.finishedSpans().size()).isEqualTo(3); + assertThat(getByTag(tracer.finishedSpans(), Tags.SPAN_KIND, Tags.SPAN_KIND_CONSUMER)) + .hasSize(2); + phaser.arriveAndDeregister(); // continue... + + List finished = tracer.finishedSpans(); + + assertThat(finished.size()).isEqualTo(3); + assertThat(finished.get(0).context().traceId()) + .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(); + } + } + + @Test + public void testActorAsk() throws ExecutionException, InterruptedException { + try (Actor actor = new Actor(tracer, phaser)) { + phaser.register(); + Future future1; + Future future2; + try (Scope parent = + tracer + .buildSpan("actorAsk") + .withTag(Tags.SPAN_KIND.getKey(), Tags.SPAN_KIND_PRODUCER) + .withTag(Tags.COMPONENT.getKey(), "example-actor") + .startActive()) { + future1 = actor.ask("my message 1"); + future2 = actor.ask("my message 2"); + } + phaser.arriveAndAwaitAdvance(); // child tracer started + assertThat(tracer.finishedSpans().size()).isEqualTo(1); + phaser.arriveAndAwaitAdvance(); // continue... + + phaser.arriveAndAwaitAdvance(); // child tracer finished + assertThat(tracer.finishedSpans().size()).isEqualTo(3); + assertThat(getByTag(tracer.finishedSpans(), Tags.SPAN_KIND, Tags.SPAN_KIND_CONSUMER)) + .hasSize(2); + phaser.arriveAndDeregister(); // continue... + + List finished = tracer.finishedSpans(); + + String message1 = future1.get(); // This really should be a non-blocking callback... + String message2 = future2.get(); // This really should be a non-blocking callback... + assertThat(message1).isEqualTo("received my message 1"); + assertThat(message2).isEqualTo("received my message 2"); + assertThat(finished.size()).isEqualTo(3); + assertThat(finished.get(0).context().traceId()) + .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(); + } + } +} diff --git a/opentracing-examples/src/test/java/io/opentracing/examples/promise_propagation/Promise.java b/opentracing-examples/src/test/java/io/opentracing/examples/promise_propagation/Promise.java new file mode 100644 index 00000000..8bcf38a7 --- /dev/null +++ b/opentracing-examples/src/test/java/io/opentracing/examples/promise_propagation/Promise.java @@ -0,0 +1,97 @@ +/* + * Copyright 2016-2017 The OpenTracing Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License + * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the License for the specific language governing permissions and limitations under + * the License. + */ +package io.opentracing.examples.promise_propagation; + +import io.opentracing.References; +import io.opentracing.Scope; +import io.opentracing.mock.MockTracer; +import io.opentracing.tag.Tags; +import java.util.Collection; +import java.util.LinkedList; + +/** @author tylerbenson */ +public class Promise { + private final PromiseContext context; + private final MockTracer tracer; + private final Scope parentScope; + + private final Collection> successCallbacks = new LinkedList<>(); + private final Collection errorCallbacks = new LinkedList<>(); + + public Promise(PromiseContext context, MockTracer tracer) { + this.context = context; + + // Passed along here for testing. Normally should be referenced via GlobalTracer.get(). + this.tracer = tracer; + parentScope = tracer.scopeManager().active(); + } + + public void onSuccess(SuccessCallback successCallback) { + successCallbacks.add(successCallback); + } + + public void onError(ErrorCallback errorCallback) { + errorCallbacks.add(errorCallback); + } + + public void success(final T result) { + for (final SuccessCallback callback : successCallbacks) { + context.submit( + new Runnable() { + @Override + public void run() { + try (Scope child = + tracer + .buildSpan("success") + .addReference(References.FOLLOWS_FROM, parentScope.span().context()) + .withTag(Tags.COMPONENT.getKey(), "success") + .startActive()) { + callback.accept(result); + } + context.getPhaser().arriveAndAwaitAdvance(); // trace reported + } + }); + } + } + + public void error(final Throwable error) { + for (final ErrorCallback callback : errorCallbacks) { + context.submit( + new Runnable() { + @Override + public void run() { + try (Scope child = + tracer + .buildSpan("error") + .addReference(References.FOLLOWS_FROM, parentScope.span().context()) + .withTag(Tags.COMPONENT.getKey(), "error") + .startActive()) { + callback.accept(error); + } + context.getPhaser().arriveAndAwaitAdvance(); // trace reported + } + }); + } + } + + public interface SuccessCallback { + /** @param t the result of the promise */ + void accept(T t); + } + + public interface ErrorCallback { + /** @param t the error result of the promise */ + void accept(Throwable t); + } +} diff --git a/opentracing-examples/src/test/java/io/opentracing/examples/promise_propagation/PromiseContext.java b/opentracing-examples/src/test/java/io/opentracing/examples/promise_propagation/PromiseContext.java new file mode 100644 index 00000000..017c23ee --- /dev/null +++ b/opentracing-examples/src/test/java/io/opentracing/examples/promise_propagation/PromiseContext.java @@ -0,0 +1,44 @@ +/* + * Copyright 2016-2017 The OpenTracing Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License + * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the License for the specific language governing permissions and limitations under + * the License. + */ +package io.opentracing.examples.promise_propagation; + +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.Phaser; + +/** @author tylerbenson */ +public class PromiseContext implements AutoCloseable { + + private final Phaser phaser; + private final ExecutorService executor; + + public PromiseContext(Phaser phaser, int concurrency) { + this.phaser = phaser; + executor = Executors.newFixedThreadPool(concurrency); + } + + @Override + public void close() { + executor.shutdown(); + } + + public void submit(Runnable runnable) { + phaser.register(); // register the work to be done on the executor + executor.submit(runnable); + } + + public Phaser getPhaser() { + return phaser; + } +} diff --git a/opentracing-examples/src/test/java/io/opentracing/examples/promise_propagation/PromisePropagationTest.java b/opentracing-examples/src/test/java/io/opentracing/examples/promise_propagation/PromisePropagationTest.java new file mode 100644 index 00000000..48679e8a --- /dev/null +++ b/opentracing-examples/src/test/java/io/opentracing/examples/promise_propagation/PromisePropagationTest.java @@ -0,0 +1,120 @@ +/* + * Copyright 2016-2017 The OpenTracing Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License + * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the License for the specific language governing permissions and limitations under + * the License. + */ +package io.opentracing.examples.promise_propagation; + +import io.opentracing.Scope; +import io.opentracing.mock.MockSpan; +import io.opentracing.mock.MockTracer; +import io.opentracing.mock.MockTracer.Propagator; +import io.opentracing.tag.Tags; +import io.opentracing.util.ThreadLocalScopeManager; +import java.util.List; +import java.util.concurrent.Phaser; +import java.util.concurrent.atomic.AtomicReference; +import org.junit.Before; +import org.junit.Test; + +import static io.opentracing.examples.TestUtils.getByTag; +import static io.opentracing.examples.TestUtils.getOneByTag; +import static org.assertj.core.api.Assertions.assertThat; + +/** + * These tests are intended to simulate the kind of async models that are common in java async + * frameworks. + * + * For improved readability, ignore the phaser lines as those are there to ensure deterministic + * execution for the tests without sleeps. + * + * @author tylerbenson + */ +public class PromisePropagationTest { + + private final MockTracer tracer = + new MockTracer(new ThreadLocalScopeManager(), Propagator.TEXT_MAP); + private Phaser phaser; + + @Before + public void before() { + phaser = new Phaser(); + } + + @Test + public void testPromiseCallback() { + phaser.register(); // register test thread + final AtomicReference successResult1 = new AtomicReference<>(); + final AtomicReference successResult2 = new AtomicReference<>(); + final AtomicReference errorResult = new AtomicReference<>(); + try (PromiseContext context = new PromiseContext(phaser, 3)) { + try (Scope parent = + tracer + .buildSpan("promises") + .withTag(Tags.COMPONENT.getKey(), "example-promises") + .startActive()) { + + Promise successPromise = new Promise<>(context, tracer); + + successPromise.onSuccess( + new Promise.SuccessCallback() { + @Override + public void accept(String s) { + tracer.scopeManager().active().span().log("Promised 1 " + s); + successResult1.set(s); + phaser.arriveAndAwaitAdvance(); // result set + } + }); + successPromise.onSuccess( + new Promise.SuccessCallback() { + @Override + public void accept(String s) { + tracer.scopeManager().active().span().log("Promised 2 " + s); + successResult2.set(s); + phaser.arriveAndAwaitAdvance(); // result set + } + }); + + Promise errorPromise = new Promise(context, tracer); + + errorPromise.onError( + new Promise.ErrorCallback() { + @Override + public void accept(Throwable t) { + errorResult.set(t); + phaser.arriveAndAwaitAdvance(); // result set + } + }); + assertThat(tracer.finishedSpans().size()).isEqualTo(0); + successPromise.success("success!"); + errorPromise.error(new Exception("some error.")); + } + + phaser.arriveAndAwaitAdvance(); // wait for results to be set + assertThat(successResult1.get()).isEqualTo("success!"); + assertThat(successResult2.get()).isEqualTo("success!"); + assertThat(errorResult.get()).hasMessage("some error."); + + phaser.arriveAndAwaitAdvance(); // wait for traces to be reported + List finished = tracer.finishedSpans(); + assertThat(finished.size()).isEqualTo(4); + assertThat(getOneByTag(finished, Tags.COMPONENT, "example-promises")).isNotNull(); + assertThat(getOneByTag(finished, Tags.COMPONENT, "example-promises").parentId()).isEqualTo(0); + long parentId = getOneByTag(finished, Tags.COMPONENT, "example-promises").context().spanId(); + assertThat(getByTag(finished, Tags.COMPONENT, "success")).hasSize(2); + for (MockSpan span : getByTag(finished, Tags.COMPONENT, "success")) { + assertThat(span.parentId()).isEqualTo(parentId); + } + assertThat(getOneByTag(finished, Tags.COMPONENT, "error")).isNotNull(); + assertThat(getOneByTag(finished, Tags.COMPONENT, "error").parentId()).isEqualTo(parentId); + } + } +} diff --git a/opentracing-examples/src/test/java/io/opentracing/examples/suspend_resume_propagation/SuspendResume.java b/opentracing-examples/src/test/java/io/opentracing/examples/suspend_resume_propagation/SuspendResume.java new file mode 100644 index 00000000..e799d5d6 --- /dev/null +++ b/opentracing-examples/src/test/java/io/opentracing/examples/suspend_resume_propagation/SuspendResume.java @@ -0,0 +1,52 @@ +/* + * Copyright 2016-2017 The OpenTracing Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License + * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the License for the specific language governing permissions and limitations under + * the License. + */ +package io.opentracing.examples.suspend_resume_propagation; + +import io.opentracing.Scope; +import io.opentracing.Span; +import io.opentracing.mock.MockTracer; +import io.opentracing.tag.Tags; + +/** @author tylerbenson */ +public class SuspendResume { + + private final int id; + private final MockTracer tracer; + private Span span; + + public SuspendResume(int id, MockTracer tracer) { + this.id = id; + + // Passed along here for testing. Normally should be referenced via GlobalTracer.get(). + this.tracer = tracer; + + try (Scope scope = + tracer + .buildSpan("job " + id) + .withTag(Tags.COMPONENT.getKey(), "suspend-resume") + .startActive(false)) { + span = scope.span(); + } + } + + public void doPart(String name) { + try (Scope scope = tracer.scopeManager().activate(span, false)) { + scope.span().log("part: " + name); + } + } + + public void done() { + span.finish(); + } +} diff --git a/opentracing-examples/src/test/java/io/opentracing/examples/suspend_resume_propagation/SuspendResumePropagationTest.java b/opentracing-examples/src/test/java/io/opentracing/examples/suspend_resume_propagation/SuspendResumePropagationTest.java new file mode 100644 index 00000000..727f0c3c --- /dev/null +++ b/opentracing-examples/src/test/java/io/opentracing/examples/suspend_resume_propagation/SuspendResumePropagationTest.java @@ -0,0 +1,73 @@ +/* + * Copyright 2016-2017 The OpenTracing Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License + * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the License for the specific language governing permissions and limitations under + * the License. + */ +package io.opentracing.examples.suspend_resume_propagation; + +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.Phaser; + +import static org.assertj.core.api.Assertions.assertThat; + +/** + * These tests are intended to simulate the kind of async models that are common in java async + * frameworks. + * + * For improved readability, ignore the phaser lines as those are there to ensure deterministic + * execution for the tests without sleeps. + * + * @author tylerbenson + */ +public class SuspendResumePropagationTest { + + private final MockTracer tracer = + new MockTracer(new ThreadLocalScopeManager(), Propagator.TEXT_MAP); + private Phaser phaser; + + @Before + public void before() { + phaser = new Phaser(); + } + + @Test + public void testContinuationInterleaving() { + SuspendResume job1 = new SuspendResume(1, tracer); + SuspendResume job2 = new SuspendResume(2, tracer); + + // Pretend that the framework is controlling actual execution here. + job1.doPart("some work for 1"); + job2.doPart("some work for 2"); + job1.doPart("other work for 1"); + job2.doPart("other work for 2"); + job2.doPart("more work for 2"); + job1.doPart("more work for 1"); + + job1.done(); + job2.done(); + + List finished = tracer.finishedSpans(); + assertThat(finished.size()).isEqualTo(2); + + assertThat(finished.get(0).operationName()).isEqualTo("job 1"); + assertThat(finished.get(1).operationName()).isEqualTo("job 2"); + + assertThat(finished.get(0).parentId()).isEqualTo(0); + assertThat(finished.get(1).parentId()).isEqualTo(0); + } +} From 153d1ba29af69d2ab8f4faac763f7685cbd6a8ed Mon Sep 17 00:00:00 2001 From: Carlos Alberto Cortez Date: Tue, 14 Nov 2017 01:13:00 +0100 Subject: [PATCH 14/19] Update README files to reflect the Scope concept. (#217) --- README.md | 78 ++++++++++++++++++++------------------ opentracing-mock/README.md | 4 +- opentracing-util/README.md | 2 +- 3 files changed, 44 insertions(+), 40 deletions(-) diff --git a/README.md b/README.md index 983cfac3..6bcd5132 100644 --- a/README.md +++ b/README.md @@ -30,36 +30,36 @@ Where possible, use some form of dependency injection (of which there are many) That said, instrumentation for packages that are themselves statically configured (e.g., JDBC drivers) may be unable to make use of said DI mechanisms for `Tracer` access, and as such they should fall back on [GlobalTracer](https://github.com/opentracing/opentracing-java/blob/master/opentracing-util/src/main/java/io/opentracing/util/GlobalTracer.java). By and large, OpenTracing instrumentation should always allow the programmer to specify a `Tracer` instance to use for instrumentation, though the [GlobalTracer](https://github.com/opentracing/opentracing-java/blob/master/opentracing-util/src/main/java/io/opentracing/util/GlobalTracer.java) is a reasonable fallback or default value. -### `ActiveSpan`s, `Continuation`s, and within-process propagation +### `Scope`s and within-process propagation For any thread, at most one `Span` may be "active". Of course there may be many other `Spans` involved with the thread which are (a) started, (b) not finished, and yet (c) not "active": perhaps they are waiting for I/O, blocked on a child Span, or otherwise off of the critical path. -It's inconvenient to pass an active `Span` from function to function manually, so OpenTracing requires that every `Tracer` implement an `ActiveSpanSource` interface that grants access to an `ActiveSpan`. Any `ActiveSpan` may be transferred to another callback or thread via `ActiveSpan#defer()` and `Continuation#activate()`; more on this below. +It's inconvenient to pass an active `Span` from function to function manually, so OpenTracing requires that every `Tracer` contains a `ScopeManager` that grants access to the active `Span` through a `Scope`. Any `Span` may be transferred to another callback or thread, but not `Scope`; more on this below. -#### Accessing the `ActiveSpan` +#### Accessing the active Span through `Scope` Access to the active span is straightforward: ```java io.opentracing.Tracer tracer = ...; ... -ActiveSpan span = tracer.activeSpan(); -if (span != null) { - span.log("..."); +Scope scope = tracer.scopeManager().active(); +if (scope != null) { + scope.span().log("..."); } ``` ### Starting a new Span -The common case starts an `ActiveSpan` that's automatically registered for intra-process propagation via `ActiveSpanSource`. The best practice is to use a try-with-resources pattern which handles Exceptions and early returns: +The common case starts an `Scope` that's automatically registered for intra-process propagation via `ScopeManager`. The best practice is to use a try-with-resources pattern which handles Exceptions and early returns: ```java io.opentracing.Tracer tracer = ...; ... -try (ActiveSpan activeSpan = tracer.buildSpan("someWork").startActive()) { +try (Scope scope = tracer.buildSpan("someWork").startActive()) { // Do things. // - // If we create async work, `activeSpan.capture()` allows us to pass the `ActiveSpan` along as well. + // If we create async work, `scope.span()` allows us to pass the `Span` along as well. } ``` @@ -68,15 +68,15 @@ The above is semantically equivalent to the more explicit try-finally version: ```java io.opentracing.Tracer tracer = ...; ... -ActiveSpan activeSpan = tracer.buildSpan("someWork").startActive(); +Scope scope = tracer.buildSpan("someWork").startActive(); try { // Do things. } finally { - activeSpan.deactivate(); + scope.deactivate(); } ``` -To manually step around the `ActiveSpanSource` registration, use `startManual()`, like this: +To manually step around the `ScopeManager` registration, use `startManual()`, like this: ```java io.opentracing.Tracer tracer = ...; @@ -89,14 +89,29 @@ try { } ``` -**If there is an `ActiveSpan`, it will act as the parent to any newly started `Span`** unless the programmer invokes `ignoreActiveSpan()` at `buildSpan()` time, like so: +**If there is an `Scope`, it will act as the parent to any newly started `Span`** unless the programmer invokes `ignoreActiveSpan()` at `buildSpan()` time, like so: ```java io.opentracing.Tracer tracer = ...; ... -ActiveSpan span = tracer.buildSpan("someWork").ignoreActiveSpan().startActive(); +Scope scope = tracer.buildSpan("someWork").ignoreActiveSpan().startActive(); ``` +#### Explicit `finish()`ing via `Scope.activate(boolean)` + +When an `Scope` is created (either via `Tracer.SpanBuilder#startActive` or `ScopeManager#activate`), it's possible to specify whether the `Span` will be finished upon `Scope.deactivate()`, through a method overload taking a `finishSpanOnClose` parameter, which defaults to true. + +```java +io.opentracing.Tracer tracer = ...; +... +try (Scope scope = tracer.buildSpan("someWork").startActive(false)) { + // false was passed to `startActive()`, so the `Span` will not be finished + // upon Scope deactivation +} +``` + +This is specially useful when a `Span` needs to be passed to a another thread or callback, reactivated, and then passed to the next thread or callback, and only be finished when the task end is reached. + ### Deferring asynchronous work Consider the case where a `Span`'s lifetime logically starts in one thread and ends in another. For instance, the Span's own internal timing breakdown might look like this: @@ -110,29 +125,28 @@ Consider the case where a `Span`'s lifetime logically starts in one thread and e The `"ServiceHandlerSpan"` is _active_ while it's running FunctionA and FunctionB, and inactive while it's waiting on an RPC (presumably modelled as its own Span, though that's not the concern here). -**The `ActiveSpanSource` API makes it easy to `capture()` the Span and execution context in `FunctionA` and re-activate it in `FunctionB`.** Note that every `Tracer` implements `ActiveSpanSource`. These are the steps: +**The `ScopeManager` API makes it possible to fetch the `span()` in `FunctionA` and re-activate it in `FunctionB`.** Note that every `Tracer` contains a `ScopeManager`. These are the steps: -1. Start an `ActiveSpan` via `Tracer.startActive()` (or, if the `Span` was already started manually via `startManual()`, call `ActiveSpanSource#makeActive(span)`) -2. In the method that *allocates* the closure/`Runnable`/`Future`/etc, call `ActiveSpan#capture()` to obtain an `ActiveSpan.Continuation` -3. In the closure/`Runnable`/`Future`/etc itself, invoke `ActiveSpan.Continuation#activate` to re-activate the `ActiveSpan`, then `deactivate()` it when the Span is no longer active (or use try-with-resources for less typing). +1. Start a `Span` via either `startManual` or `startActive(false)` to prevent the `Span` from being finished upon `Scope` deactivation. +2. In the closure/`Runnable`/`Future`/etc itself, invoke `tracer.scopeManager().activate(span, false)` to re-activate the `Span` and get a new `Scope`, then `deactivate()` it when the `Span` is no longer active (or use try-with-resources for less typing). +3. In the closure/`Runnable`/`Future`/etc where the end of the task is reached, invoke `tracer.scopeManager().activate(span, true)` to re-activate the `Span` and have the new `Scope` close the `Span` automatically. For example: ```java io.opentracing.Tracer tracer = ...; ... -// STEP 1 ABOVE: start the ActiveSpan -try (ActiveSpan serviceSpan = tracer.buildSpan("ServiceHandlerSpan").startActive()) { +// STEP 1 ABOVE: start the Scope/Span +try (Scope scope = tracer.buildSpan("ServiceHandlerSpan").startActive(false)) { ... - - // STEP 2 ABOVE: capture the ActiveSpan - final ActiveSpan.Continuation cont = serviceSpan.capture(); + final Span span = scope.span(); doAsyncWork(new Runnable() { @Override public void run() { - // STEP 3 ABOVE: use the Continuation to reactivate the Span in the callback. - try (ActiveSpan activeSpan = cont.activate()) { + // STEP 2 ABOVE: reactivate the Span in the callback, passing true to + // startActive() if/when the Span must be finished. + try (Scope scope = tracer.scopeManager().activate(span, false)) { ... } } @@ -140,19 +154,9 @@ try (ActiveSpan serviceSpan = tracer.buildSpan("ServiceHandlerSpan").startActive } ``` -In practice, all of this is most fluently accomplished through the use of an OpenTracing-aware `ExecutorService` and/or `Runnable`/`Callable` adapter; they factor out most of the typing. - -#### Automatic `finish()`ing via `ActiveSpan` reference counts +Observe that passing `Scope` to another thread or callback is not supported. Only `Span` can be used under this scenario. -When an `ActiveSpan` is created (either via `Tracer.SpanBuilder#startActive` or `ActiveSpanSource#makeActive(Span)`), the reference count associated with the `ActiveSpan` is `1`. - -- When an `ActiveSpan.Continuation` is created via `ActiveSpan#capture`, the reference count **increments** -- When an `ActiveSpan.Continuation` is `ActiveSpan.Continuation#activate()`d and thus transformed back into an `ActiveSpan`, the reference count **is unchanged** -- When an `ActiveSpan` is `ActiveSpan#deactivate()`d, the reference count **decrements** - -When the reference count decrements to zero, **the `Span`'s `finish()` method is invoked automatically.** - -When used as designed, the programmer lets `ActiveSpan` and `ActiveSpan.Continuation` finish the `Span` as soon as the last active or deferred `ActiveSpan` is deactivated. +In practice, all of this is most fluently accomplished through the use of an OpenTracing-aware `ExecutorService` and/or `Runnable`/`Callable` adapter; they factor out most of the typing. # Development diff --git a/opentracing-mock/README.md b/opentracing-mock/README.md index cbdc45d7..24582692 100644 --- a/opentracing-mock/README.md +++ b/opentracing-mock/README.md @@ -8,8 +8,8 @@ Imagine the following (admittedly unrealistic) OpenTracing-instrumented applicat ```java public void handlePurchase(User user, Item item, Tracer tracer) { - try (ActiveSpan span = tracer.buildSpan("handlePurchase").startActive()) { - span.setTag("username", user.getUsername()); + try (Scope scope = tracer.buildSpan("handlePurchase").startActive()) { + scope.span().setTag("username", user.getUsername()); } } ``` diff --git a/opentracing-util/README.md b/opentracing-util/README.md index 168349c7..793245b9 100644 --- a/opentracing-util/README.md +++ b/opentracing-util/README.md @@ -37,7 +37,7 @@ GlobalTracer.register(configuredTracer); Once initialized, all application code can instrument tracing by starting new spans like: ```java -try (Span span = GlobalTracer.get().buildSpan("someOperation").startActive()) { +try (Scope scope = GlobalTracer.get().buildSpan("someOperation").startActive()) { // ... Traced block of code ... } ``` From 3e54a2790e7989bf57f223fcd65155d63e148b59 Mon Sep 17 00:00:00 2001 From: Carlos Alberto Cortez Date: Wed, 6 Dec 2017 11:54:13 -0600 Subject: [PATCH 15/19] Let Tracer.activeSpan() be a shorthand for ScopeManager's active Span. (#228) * Let Tracer.activeSpan() be a shorthand for ScopeManager's active Span. * Document the null case for Tracer.activeSpan(). * Have Tracer.activeSpan() return null. * Remove @link for Tracer.activeSpan(). 'Nested' links do not happen to exist under javadoc, so Tracer.scopeManager().active().span() is now not a link. --- .../src/main/java/io/opentracing/Tracer.java | 6 ++++++ .../java/io/opentracing/mock/MockTracer.java | 6 ++++++ .../io/opentracing/mock/MockTracerTest.java | 18 +++++++++++++++++- .../java/io/opentracing/noop/NoopTracer.java | 6 ++++++ .../java/io/opentracing/util/GlobalTracer.java | 6 ++++++ 5 files changed, 41 insertions(+), 1 deletion(-) diff --git a/opentracing-api/src/main/java/io/opentracing/Tracer.java b/opentracing-api/src/main/java/io/opentracing/Tracer.java index bb3c0d16..a75aef91 100644 --- a/opentracing-api/src/main/java/io/opentracing/Tracer.java +++ b/opentracing-api/src/main/java/io/opentracing/Tracer.java @@ -25,6 +25,12 @@ public interface Tracer { */ ScopeManager scopeManager(); + /** + * @return the active {@link Span}. This is a shorthand for Tracer.scopeManager().active().span(), + * and null will be returned if {@link Scope#active()} is null. + */ + Span activeSpan(); + /** * Return a new SpanBuilder for a Span with the given `operationName`. * 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 36ea0232..b15cd86e 100644 --- a/opentracing-mock/src/main/java/io/opentracing/mock/MockTracer.java +++ b/opentracing-mock/src/main/java/io/opentracing/mock/MockTracer.java @@ -191,6 +191,12 @@ public SpanContext extract(Format format, C carrier) { return this.propagator.extract(format, carrier); } + @Override + public Span activeSpan() { + Scope scope = this.scopeManager.active(); + return scope == null ? null : scope.span(); + } + synchronized void appendFinishedSpan(MockSpan mockSpan) { this.finishedSpans.add(mockSpan); this.onSpanFinished(mockSpan); 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 129ec9ab..2390f99c 100644 --- a/opentracing-mock/src/test/java/io/opentracing/mock/MockTracerTest.java +++ b/opentracing-mock/src/test/java/io/opentracing/mock/MockTracerTest.java @@ -17,7 +17,6 @@ import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotEquals; -import io.opentracing.References; import java.util.HashMap; import java.util.List; import java.util.Map; @@ -25,6 +24,7 @@ import org.junit.Assert; import org.junit.Test; +import io.opentracing.References; import io.opentracing.Scope; import io.opentracing.Span; import io.opentracing.SpanContext; @@ -202,6 +202,22 @@ public void testTextMapPropagatorHttpHeaders() { Assert.assertEquals(finishedSpans.get(0).context().spanId(), finishedSpans.get(1).parentId()); } + @Test + public void testActiveSpan() { + MockTracer mockTracer = new MockTracer(); + Assert.assertNull(mockTracer.activeSpan()); + + Scope scope = null; + try { + scope = mockTracer.buildSpan("foo").startActive(true); + Assert.assertEquals(mockTracer.scopeManager().active().span(), mockTracer.activeSpan()); + } finally { + scope.close(); + } + + Assert.assertNull(mockTracer.activeSpan()); + } + @Test public void testReset() { MockTracer mockTracer = new MockTracer(); diff --git a/opentracing-noop/src/main/java/io/opentracing/noop/NoopTracer.java b/opentracing-noop/src/main/java/io/opentracing/noop/NoopTracer.java index 3fb63804..bb0b6db2 100644 --- a/opentracing-noop/src/main/java/io/opentracing/noop/NoopTracer.java +++ b/opentracing-noop/src/main/java/io/opentracing/noop/NoopTracer.java @@ -14,6 +14,7 @@ package io.opentracing.noop; import io.opentracing.ScopeManager; +import io.opentracing.Span; import io.opentracing.SpanContext; import io.opentracing.Tracer; import io.opentracing.propagation.Format; @@ -29,6 +30,11 @@ public ScopeManager scopeManager() { return NoopScopeManager.INSTANCE; } + @Override + public Span activeSpan() { + return null; + } + @Override public SpanBuilder buildSpan(String operationName) { return NoopSpanBuilderImpl.INSTANCE; } diff --git a/opentracing-util/src/main/java/io/opentracing/util/GlobalTracer.java b/opentracing-util/src/main/java/io/opentracing/util/GlobalTracer.java index 24ef261b..d1d06905 100644 --- a/opentracing-util/src/main/java/io/opentracing/util/GlobalTracer.java +++ b/opentracing-util/src/main/java/io/opentracing/util/GlobalTracer.java @@ -14,6 +14,7 @@ package io.opentracing.util; import io.opentracing.ScopeManager; +import io.opentracing.Span; import io.opentracing.noop.NoopTracer; import io.opentracing.noop.NoopTracerFactory; import io.opentracing.SpanContext; @@ -142,6 +143,11 @@ public SpanContext extract(Format format, C carrier) { return tracer.extract(format, carrier); } + @Override + public Span activeSpan() { + return tracer.activeSpan(); + } + @Override public String toString() { return GlobalTracer.class.getSimpleName() + '{' + tracer + '}'; From 1b5a2258acf3c669be68b82e6f0deb58a03a63af Mon Sep 17 00:00:00 2001 From: Carlos Alberto Cortez Date: Wed, 6 Dec 2017 12:40:04 -0600 Subject: [PATCH 16/19] Change BINARY to be resizable and stream-oriented. (#223) * Change BINARY to be resizable and stream-oriented. * Abstract the Binary adapter and have an Adapters class to return it. * Remove the isInbound/isOutbound methods from BinaryAdapter. * Make Binary use the Channel paradigm for injection/extraction * Have binary methods in Adapters named after inject/extract. * Add a BINARY propagator for MockTracer. * Throw RuntimeException in case of errors during BINARY's injection. * Put braces around if-blocks for Adapters/BinaryAdapter. * Use verbose messages for null parameters in Adapters. --- .../io/opentracing/propagation/Adapters.java | 89 +++++++++++++++++++ .../io/opentracing/propagation/Binary.java | 57 ++++++++++++ .../propagation/BinaryAdapter.java | 69 ++++++++++++++ .../io/opentracing/propagation/Format.java | 2 +- .../opentracing/propagation/AdaptersTest.java | 78 ++++++++++++++++ .../propagation/BinaryAdapterTest.java | 61 +++++++++++++ .../java/io/opentracing/mock/MockTracer.java | 82 +++++++++++++++++ .../io/opentracing/mock/MockTracerTest.java | 36 ++++++++ 8 files changed, 473 insertions(+), 1 deletion(-) create mode 100644 opentracing-api/src/main/java/io/opentracing/propagation/Adapters.java create mode 100644 opentracing-api/src/main/java/io/opentracing/propagation/Binary.java create mode 100644 opentracing-api/src/main/java/io/opentracing/propagation/BinaryAdapter.java create mode 100644 opentracing-api/src/test/java/io/opentracing/propagation/AdaptersTest.java create mode 100644 opentracing-api/src/test/java/io/opentracing/propagation/BinaryAdapterTest.java diff --git a/opentracing-api/src/main/java/io/opentracing/propagation/Adapters.java b/opentracing-api/src/main/java/io/opentracing/propagation/Adapters.java new file mode 100644 index 00000000..7986d959 --- /dev/null +++ b/opentracing-api/src/main/java/io/opentracing/propagation/Adapters.java @@ -0,0 +1,89 @@ +/* + * 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 java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.nio.channels.Channels; +import java.nio.channels.ReadableByteChannel; +import java.nio.channels.WritableByteChannel; + +public final class Adapters { + private Adapters() {} + + /** + * Creates an outbound Binary instance used for injection, backed up + * by the specified OutputStream as output. + * + * @param stream The OutputStream used as the output. + * + * @return The new Binary carrier used for injection. + */ + public static Binary injectBinary(OutputStream stream) { + if (stream == null) { + throw new IllegalArgumentException("stream cannot be null"); + } + + return new BinaryAdapter(Channels.newChannel(stream)); + } + + /** + * Creates an outbound Binary instance used for injection, backed up + * by the specified WritableByteChannel as the output. + * + * @param channel The WritableByteChannel used as output. + * + * @return The new Binary carrier used for injection. + */ + public static Binary injectBinary(WritableByteChannel channel) { + if (channel == null) { + throw new IllegalArgumentException("channel cannot be null"); + } + + return new BinaryAdapter(channel); + } + + /** + * Creates an inbound Binary instance used for extraction with the + * specified InputStream as the input. + * + * @param stream The InputStream used as input. + * + * @return The new Binary carrier used for extraction. + */ + public static Binary extractBinary(InputStream stream) { + if (stream == null) { + throw new IllegalArgumentException("stream cannot be null"); + } + + return new BinaryAdapter(Channels.newChannel(stream)); + } + + /** + * Creates an inbound Binary instance used for extraction with the + * specified ReadableByteChannel as the input. + * + * @param channel The ReadableByteChannel used as input. + * + * @return The new Binary carrier used for extraction. + */ + public static Binary extractBinary(ReadableByteChannel channel) { + if (channel == null) { + throw new IllegalArgumentException("channel cannot be null"); + } + + return new BinaryAdapter(channel); + } +} diff --git a/opentracing-api/src/main/java/io/opentracing/propagation/Binary.java b/opentracing-api/src/main/java/io/opentracing/propagation/Binary.java new file mode 100644 index 00000000..ada9725c --- /dev/null +++ b/opentracing-api/src/main/java/io/opentracing/propagation/Binary.java @@ -0,0 +1,57 @@ +/* + * Copyright 2016-2017 The OpenTracing Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License + * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the License for the specific language governing permissions and limitations under + * the License. + */ +package io.opentracing.propagation; + +import java.io.IOException; +import java.nio.ByteBuffer; + +/** + * Binary is an interface defining the required operations for a binary carrier for + * Tracer.inject() and Tracer.extract(). Binary can be defined either as inbound (extraction) + * or outbound (injection). + * + * When Binary is defined as inbound, read() must be used to read data, + * and it is an error to call read(). + * + * When Binary is defined as outbound, write() must be used to write data, + * and it is an error to call write(). + * + * @see Format.Builtin#BINARY + * @see io.opentracing.Tracer#inject(SpanContext, Format, Object) + * @see io.opentracing.Tracer#extract(Format, Object) + */ +public interface Binary { + /** + * Writes a sequence of bytes to this channel from the given buffer. + * The internal buffer is expected to grow as more data is written. + * + * The behavior of this method is expected to be the same as WritableByteChannel.write(). + * + * @param buffer The buffer from which bytes are to be retrieved. + * + * @return The number of bytes written, possibly zero. + */ + int write(ByteBuffer buffer) throws IOException; + + /** + * Reads a sequence of bytes into the given buffer. + * + * The behavior of this method is expected to be the same as ReadableByteChannel.read(). + * + * @param buffer The buffer into which bytes are to be transferred. + * + * @return The number of bytes read, possibly zero, or -1 if the channel has reached end-of-stream. + */ + int read(ByteBuffer buffer) throws IOException; +} diff --git a/opentracing-api/src/main/java/io/opentracing/propagation/BinaryAdapter.java b/opentracing-api/src/main/java/io/opentracing/propagation/BinaryAdapter.java new file mode 100644 index 00000000..0412e691 --- /dev/null +++ b/opentracing-api/src/main/java/io/opentracing/propagation/BinaryAdapter.java @@ -0,0 +1,69 @@ +/* + * 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 java.io.IOException; +import java.nio.ByteBuffer; +import java.nio.channels.ReadableByteChannel; +import java.nio.channels.WritableByteChannel; + +/** + * BinaryAdapter is a built-in carrier for Tracer.inject() and Tracer.extract(). BinaryAdapter + * is backed up by either a ReadableByteChannel or a WritableByteChannel, depending + * on whether it's defined as injection or extraction, respectively. + */ +final class BinaryAdapter implements Binary { + private final ReadableByteChannel readChannel; + private final WritableByteChannel writeChannel; + + /** + * Create an outbound BinaryAdapter backed by the specified write channel. + */ + BinaryAdapter(WritableByteChannel writeChannel) { + this.writeChannel = writeChannel; + this.readChannel = null; + } + + /** + * Create an inbound BinaryAdapter backed by the specified read channel. + */ + BinaryAdapter(ReadableByteChannel readChannel) { + this.readChannel = readChannel; + this.writeChannel = null; + } + + ReadableByteChannel readChannel() { + return readChannel; + } + + WritableByteChannel writeChannel() { + return writeChannel; + } + + public int write(ByteBuffer buffer) throws IOException { + if (writeChannel == null) { + throw new UnsupportedOperationException(); + } + + return writeChannel.write(buffer); + } + + public int read(ByteBuffer buffer) throws IOException { + if (readChannel == null) { + throw new UnsupportedOperationException(); + } + + return readChannel.read(buffer); + } +} 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 d1b55483..dd63aba5 100644 --- a/opentracing-api/src/main/java/io/opentracing/propagation/Format.java +++ b/opentracing-api/src/main/java/io/opentracing/propagation/Format.java @@ -76,7 +76,7 @@ private Builtin(String name) { * @see io.opentracing.Tracer#extract(Format, Object) * @see Format */ - public final static Format BINARY = new Builtin("BINARY"); + public final static Format BINARY = new Builtin("BINARY"); /** * @return Short name for built-in formats as they tend to show up in exception messages. diff --git a/opentracing-api/src/test/java/io/opentracing/propagation/AdaptersTest.java b/opentracing-api/src/test/java/io/opentracing/propagation/AdaptersTest.java new file mode 100644 index 00000000..2c9e6564 --- /dev/null +++ b/opentracing-api/src/test/java/io/opentracing/propagation/AdaptersTest.java @@ -0,0 +1,78 @@ +/* + * 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 java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.InputStream; +import java.io.OutputStream; +import java.nio.channels.Channels; +import java.nio.channels.ReadableByteChannel; +import java.nio.channels.WritableByteChannel; +import org.junit.Test; + +import static org.junit.Assert.assertArrayEquals; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; + +public class AdaptersTest { + + @Test + public void testExtractBinaryStream() { + byte[] ctx = new byte[0]; + BinaryAdapter binary = (BinaryAdapter) Adapters.extractBinary(new ByteArrayInputStream(ctx)); + assertNotNull(binary.readChannel()); + } + + @Test + public void testExtractBinaryChannel() { + byte[] ctx = new byte[0]; + ReadableByteChannel channel = Channels.newChannel(new ByteArrayInputStream(new byte[0])); + BinaryAdapter binary = (BinaryAdapter) Adapters.extractBinary(channel); + assertEquals(channel, binary.readChannel()); + } + + @Test(expected = IllegalArgumentException.class) + public void testExtractNullStream() { + Adapters.extractBinary((InputStream)null); + } + + @Test(expected = IllegalArgumentException.class) + public void testExtractNullChannel() { + Adapters.extractBinary((ReadableByteChannel)null); + } + + @Test + public void testInjectBinaryStream() { + BinaryAdapter binary = (BinaryAdapter) Adapters.injectBinary(new ByteArrayOutputStream()); + assertNotNull(binary.writeChannel()); + } + + @Test + public void testInjectBinaryChannel() { + WritableByteChannel channel = Channels.newChannel(new ByteArrayOutputStream()); + BinaryAdapter binary = (BinaryAdapter) Adapters.injectBinary(channel); + assertEquals(channel, binary.writeChannel()); + } + + @Test(expected = IllegalArgumentException.class) + public void testInjectNullStream() { + Adapters.injectBinary((OutputStream)null); + } + + @Test(expected = IllegalArgumentException.class) + public void testInjectNullChannel() { + Adapters.injectBinary((WritableByteChannel)null); + } +} diff --git a/opentracing-api/src/test/java/io/opentracing/propagation/BinaryAdapterTest.java b/opentracing-api/src/test/java/io/opentracing/propagation/BinaryAdapterTest.java new file mode 100644 index 00000000..ef489ca7 --- /dev/null +++ b/opentracing-api/src/test/java/io/opentracing/propagation/BinaryAdapterTest.java @@ -0,0 +1,61 @@ +/* + * 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 java.io.ByteArrayOutputStream; +import java.io.ByteArrayInputStream; +import java.io.IOException; +import java.nio.ByteBuffer; +import java.nio.channels.Channels; +import org.junit.Test; + +import static org.junit.Assert.assertArrayEquals; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNull; + +public class BinaryAdapterTest { + + @Test + public void testRead() throws IOException { + ByteArrayInputStream stream = new ByteArrayInputStream(new byte[] { 1, 2, 3, 4, 4, 3, 2, 1 }); + BinaryAdapter binary = new BinaryAdapter(Channels.newChannel(stream)); + assertNotNull(binary.readChannel()); + assertNull(binary.writeChannel()); + + ByteBuffer buffer = ByteBuffer.allocate(4); + assertEquals(4, binary.read(buffer)); + assertArrayEquals(new byte[] { 1, 2, 3, 4 }, buffer.array()); + + buffer.rewind(); + assertEquals(4, binary.read(buffer)); + assertArrayEquals(new byte[] { 4, 3, 2, 1 }, buffer.array()); + + buffer.rewind(); + assertEquals(-1, binary.read(buffer)); + } + + @Test + public void testWrite() throws IOException { + ByteArrayOutputStream stream = new ByteArrayOutputStream(); + BinaryAdapter binary = new BinaryAdapter(Channels.newChannel(stream)); + assertNotNull(binary.writeChannel()); + assertNull(binary.readChannel()); + + assertEquals(4, binary.write(ByteBuffer.wrap(new byte [] { 1, 2, 3, 4 }))); + assertEquals(4, binary.write(ByteBuffer.wrap(new byte [] { 4, 3, 2, 1 }))); + + assertArrayEquals(new byte[] { 1, 2, 3, 4, 4, 3, 2, 1 }, stream.toByteArray()); + } +} 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 b15cd86e..b8327fef 100644 --- a/opentracing-mock/src/main/java/io/opentracing/mock/MockTracer.java +++ b/opentracing-mock/src/main/java/io/opentracing/mock/MockTracer.java @@ -13,6 +13,12 @@ */ package io.opentracing.mock; +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; +import java.io.IOException; +import java.nio.ByteBuffer; import java.util.ArrayList; import java.util.HashMap; import java.util.List; @@ -25,6 +31,7 @@ import io.opentracing.References; import io.opentracing.SpanContext; import io.opentracing.Tracer; +import io.opentracing.propagation.Binary; import io.opentracing.propagation.Format; import io.opentracing.propagation.TextMap; import io.opentracing.util.ThreadLocalScopeManager; @@ -112,6 +119,81 @@ public MockSpan.MockContext extract(Format format, C carrier) { } }; + Propagator BINARY = new Propagator() { + static final int BUFFER_SIZE = 128; + + @Override + public void inject(MockSpan.MockContext ctx, Format format, C carrier) { + if (carrier instanceof Binary) { + Binary binary = (Binary) carrier; + ByteArrayOutputStream stream = new ByteArrayOutputStream(); + ObjectOutputStream objStream = null; + try { + objStream = new ObjectOutputStream(stream); + objStream.writeLong(ctx.spanId()); + objStream.writeLong(ctx.traceId()); + + for (Map.Entry entry : ctx.baggageItems()) { + objStream.writeUTF(entry.getKey()); + objStream.writeUTF(entry.getValue()); + } + + objStream.flush(); // *need* to flush ObjectOutputStream. + binary.write(ByteBuffer.wrap(stream.toByteArray())); + + } catch (IOException e) { + throw new RuntimeException("Corrupted state"); + } finally { + if (objStream != null) { + try { objStream.close(); } catch (Exception e2) {} + } + } + } else { + throw new IllegalArgumentException("Unknown carrier"); + } + } + + @Override + public MockSpan.MockContext extract(Format format, C carrier) { + Long traceId = null; + Long spanId = null; + Map baggage = new HashMap<>(); + + if (carrier instanceof Binary) { + Binary binary = (Binary) carrier; + ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); + ObjectInputStream objStream = null; + try { + ByteBuffer buffer = ByteBuffer.allocate(BUFFER_SIZE); + for (int readBytes = 0; (readBytes = binary.read(buffer)) > 0; buffer.rewind()) { + outputStream.write(buffer.array(), 0, readBytes); + } + + objStream = new ObjectInputStream(new ByteArrayInputStream(outputStream.toByteArray())); + spanId = objStream.readLong(); + traceId = objStream.readLong(); + + while (objStream.available() > 0) { + baggage.put(objStream.readUTF(), objStream.readUTF()); + } + } catch (IOException e) { + } finally { + if (objStream != null) { + try { objStream.close(); } catch (Exception e2) {} + } + } + } else { + throw new IllegalArgumentException("Unknown carrier"); + } + + if (traceId != null && spanId != null) { + return new MockSpan.MockContext(traceId, spanId, baggage); + } + + return null; + } + }; + Propagator TEXT_MAP = new Propagator() { public static final String SPAN_ID_KEY = "spanid"; public static final String TRACE_ID_KEY = "traceid"; 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 2390f99c..eb380d74 100644 --- a/opentracing-mock/src/test/java/io/opentracing/mock/MockTracerTest.java +++ b/opentracing-mock/src/test/java/io/opentracing/mock/MockTracerTest.java @@ -17,6 +17,8 @@ import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotEquals; +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; import java.util.HashMap; import java.util.List; import java.util.Map; @@ -29,6 +31,7 @@ import io.opentracing.Span; import io.opentracing.SpanContext; import io.opentracing.Tracer; +import io.opentracing.propagation.Adapters; import io.opentracing.propagation.Format; import io.opentracing.propagation.TextMapExtractAdapter; import io.opentracing.propagation.TextMapInjectAdapter; @@ -202,6 +205,39 @@ public void testTextMapPropagatorHttpHeaders() { Assert.assertEquals(finishedSpans.get(0).context().spanId(), finishedSpans.get(1).parentId()); } + @Test + public void testBinaryPropagator() { + MockTracer tracer = new MockTracer(MockTracer.Propagator.BINARY); + { + Span parentSpan = tracer.buildSpan("foo") + .start(); + parentSpan.setBaggageItem("foobag", "fooitem"); + parentSpan.finish(); + + ByteArrayOutputStream injectStream = new ByteArrayOutputStream(); + tracer.inject(parentSpan.context(), Format.Builtin.BINARY, + Adapters.injectBinary(injectStream)); + + ByteArrayInputStream extractStream = new ByteArrayInputStream(injectStream.toByteArray()); + SpanContext extract = tracer.extract(Format.Builtin.BINARY, Adapters.extractBinary(extractStream)); + + Span childSpan = tracer.buildSpan("bar") + .asChildOf(extract) + .start(); + childSpan.setBaggageItem("barbag", "baritem"); + childSpan.finish(); + } + List finishedSpans = tracer.finishedSpans(); + + Assert.assertEquals(2, finishedSpans.size()); + Assert.assertEquals(finishedSpans.get(0).context().traceId(), finishedSpans.get(1).context().traceId()); + Assert.assertEquals(finishedSpans.get(0).context().spanId(), finishedSpans.get(1).parentId()); + Assert.assertEquals("fooitem", finishedSpans.get(0).getBaggageItem("foobag")); + Assert.assertNull(finishedSpans.get(0).getBaggageItem("barbag")); + Assert.assertEquals("fooitem", finishedSpans.get(1).getBaggageItem("foobag")); + Assert.assertEquals("baritem", finishedSpans.get(1).getBaggageItem("barbag")); + } + @Test public void testActiveSpan() { MockTracer mockTracer = new MockTracer(); From 7f6cf453f6a64f93f6b5d66dd7a092d696b52222 Mon Sep 17 00:00:00 2001 From: Pavol Loffay Date: Thu, 7 Dec 2017 11:46:28 -0600 Subject: [PATCH 17/19] SpanBuilder deprecate startManual (#225) * SpanBuilder deprecate startManual * Fix review comments --- .../src/main/java/io/opentracing/Tracer.java | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/opentracing-api/src/main/java/io/opentracing/Tracer.java b/opentracing-api/src/main/java/io/opentracing/Tracer.java index a75aef91..5b73ea04 100644 --- a/opentracing-api/src/main/java/io/opentracing/Tracer.java +++ b/opentracing-api/src/main/java/io/opentracing/Tracer.java @@ -231,6 +231,12 @@ interface SpanBuilder { */ Scope startActive(boolean finishSpanOnClose); + /** + * @deprecated use {@link #start} or {@link #startActive} instead. + */ + @Deprecated + Span startManual(); + /** * Like {@link #startActive()}, but the returned {@link Span} has not been registered via the * {@link ScopeManager}. @@ -239,12 +245,6 @@ interface SpanBuilder { * @return the newly-started Span instance, which has *not* been automatically registered * via the {@link ScopeManager} */ - Span startManual(); - - /** - * @deprecated use {@link #startManual} or {@link #startActive} instead. - */ - @Deprecated Span start(); } } From 74c18892a438cbcefdf88251346bc18162dbf4e7 Mon Sep 17 00:00:00 2001 From: Pavol Loffay Date: Thu, 14 Dec 2017 19:20:46 -0600 Subject: [PATCH 18/19] Remove default finish behaviour for `activate()` (#219) * Do not auto finish on scope.close * Fix review comments * Fix review comments * Add explanatory statement about not auto-finishing * Define only activate(s, bool) --- README.md | 79 +++++++------------ .../java/io/opentracing/ScopeManager.java | 13 +-- .../src/main/java/io/opentracing/Tracer.java | 38 +-------- .../examples/AutoFinishScopeManager.java | 5 -- .../ScheduledActionsTest.java | 4 +- .../ActiveSpanReplacementTest.java | 6 +- .../examples/actor_propagation/Actor.java | 4 +- .../ActorPropagationTest.java | 4 +- .../examples/client_server/Client.java | 2 +- .../examples/client_server/Server.java | 7 +- .../common_request_handler/HandlerTest.java | 4 +- .../late_span_finish/LateSpanFinishTest.java | 4 +- .../examples/multiple_callbacks/Client.java | 2 +- .../MultipleCallbacksTest.java | 2 +- .../nested_callbacks/NestedCallbacksTest.java | 2 +- .../examples/promise_propagation/Promise.java | 4 +- .../PromisePropagationTest.java | 2 +- .../java/io/opentracing/mock/MockTracer.java | 5 -- .../io/opentracing/noop/NoopScopeManager.java | 5 -- .../io/opentracing/noop/NoopSpanBuilder.java | 5 -- .../util/ThreadLocalScopeManager.java | 5 -- .../util/ThreadLocalScopeManagerTest.java | 12 +-- .../util/ThreadLocalScopeTest.java | 9 +-- 23 files changed, 68 insertions(+), 155 deletions(-) diff --git a/README.md b/README.md index 6bcd5132..04db8fa7 100644 --- a/README.md +++ b/README.md @@ -10,14 +10,6 @@ In order to understand the Java platform API, one must first be familiar with the [OpenTracing project](http://opentracing.io) and [terminology](http://opentracing.io/documentation/pages/spec.html) more specifically. -## Status - -This project has a working design of interfaces for the OpenTracing API. There -is a [MockTracer](https://github.com/opentracing/opentracing-java/tree/master/opentracing-mock) -to facilitate unit-testing of OpenTracing Java instrumentation. - -Packages are deployed to Maven Central under the `io.opentracing` group. - ## Usage ### Initialization @@ -51,45 +43,41 @@ if (scope != null) { ### Starting a new Span -The common case starts an `Scope` that's automatically registered for intra-process propagation via `ScopeManager`. The best practice is to use a try-with-resources pattern which handles Exceptions and early returns: +The common case starts a `Scope` that's automatically registered for intra-process propagation via `ScopeManager`. -```java -io.opentracing.Tracer tracer = ...; -... -try (Scope scope = tracer.buildSpan("someWork").startActive()) { - // Do things. - // - // If we create async work, `scope.span()` allows us to pass the `Span` along as well. -} -``` - -The above is semantically equivalent to the more explicit try-finally version: +Note that `startActive(true)` finishes the span on `Scope.close()`. +Use it carefully because the `try-with-resources` construct finishes the span before +the `catch` or `finally` blocks are executed, which makes logging exceptions and +setting tags impossible. It is recommended to start the span and activate it later in `try-with-resources`. +This makes the span available in catch and finally blocks. ```java io.opentracing.Tracer tracer = ...; ... -Scope scope = tracer.buildSpan("someWork").startActive(); -try { +Span span = tracer.buildSpan("someWork").start(); +try (Scope scope = tracer.scopeManager().activate(span, false)) // Do things. +} catch { + Tags.ERROR.set(scope.span(), true); } finally { - scope.deactivate(); + span.finish(); } ``` -To manually step around the `ScopeManager` registration, use `startManual()`, like this: +The following code uses `try-with-resources` to finish the span. ```java io.opentracing.Tracer tracer = ...; ... -Span span = tracer.buildSpan("someWork").startManual(); -try { - // (do things / record data to `span`) -} finally { - span.finish(); +try (Scope scope = tracer.buildSpan("someWork").startActive(true)) { + // Do things. + // + // `scope.span()` allows us to pass the `Span` to newly created threads. } ``` -**If there is an `Scope`, it will act as the parent to any newly started `Span`** unless the programmer invokes `ignoreActiveSpan()` at `buildSpan()` time, like so: +**If there is a `Scope`, it will act as the parent to any newly started `Span`** unless +the programmer invokes `ignoreActiveSpan()` at `buildSpan()` time or specified parent context explicitly: ```java io.opentracing.Tracer tracer = ...; @@ -97,21 +85,6 @@ io.opentracing.Tracer tracer = ...; Scope scope = tracer.buildSpan("someWork").ignoreActiveSpan().startActive(); ``` -#### Explicit `finish()`ing via `Scope.activate(boolean)` - -When an `Scope` is created (either via `Tracer.SpanBuilder#startActive` or `ScopeManager#activate`), it's possible to specify whether the `Span` will be finished upon `Scope.deactivate()`, through a method overload taking a `finishSpanOnClose` parameter, which defaults to true. - -```java -io.opentracing.Tracer tracer = ...; -... -try (Scope scope = tracer.buildSpan("someWork").startActive(false)) { - // false was passed to `startActive()`, so the `Span` will not be finished - // upon Scope deactivation -} -``` - -This is specially useful when a `Span` needs to be passed to a another thread or callback, reactivated, and then passed to the next thread or callback, and only be finished when the task end is reached. - ### Deferring asynchronous work Consider the case where a `Span`'s lifetime logically starts in one thread and ends in another. For instance, the Span's own internal timing breakdown might look like this: @@ -158,16 +131,20 @@ Observe that passing `Scope` to another thread or callback is not supported. Onl In practice, all of this is most fluently accomplished through the use of an OpenTracing-aware `ExecutorService` and/or `Runnable`/`Callable` adapter; they factor out most of the typing. -# Development +## Instrumentation Tests -This is a maven project, and provides a wrapper, `./mvnw` to pin a consistent -version. For example, `./mvnw clean install`. +This project has a working design of interfaces for the OpenTracing API. There +is a [MockTracer](https://github.com/opentracing/opentracing-java/tree/master/opentracing-mock) +to facilitate unit-testing of OpenTracing Java instrumentation. -This wrapper was generated by `mvn -N io.takari:maven:wrapper -Dmaven=3.5.0` +Packages are deployed to Maven Central under the `io.opentracing` group. + +## Development -## Building +This is a maven project, and provides a wrapper, `./mvnw` to pin a consistent +version. Run `./mvnw clean install` to build, run tests, and create jars. -Execute `./mvnw clean install` to build, run tests, and create jars. +This wrapper was generated by `mvn -N io.takari:maven:wrapper -Dmaven=3.5.0` ## Contributing diff --git a/opentracing-api/src/main/java/io/opentracing/ScopeManager.java b/opentracing-api/src/main/java/io/opentracing/ScopeManager.java index bcd6e922..d1c98945 100644 --- a/opentracing-api/src/main/java/io/opentracing/ScopeManager.java +++ b/opentracing-api/src/main/java/io/opentracing/ScopeManager.java @@ -15,22 +15,13 @@ /** * The {@link ScopeManager} interface abstracts both the activation of {@link Span} instances (via - * {@link ScopeManager#activate(Span)}) and access to an active {@link Span}/{@link Scope} + * {@link ScopeManager#activate(Span, boolean)}) and access to an active {@link Span}/{@link Scope} * (via {@link ScopeManager#active()}). * * @see Scope * @see Tracer#scopeManager() */ public interface ScopeManager { - /** - * Make a {@link Span} instance active. - * - * @param span the {@link Span} that should become the {@link #active()} - * @return a {@link Scope} instance to control the end of the active period for the {@link Span}. - * Span will automatically be finished when {@link Scope#close()} is called. It is a - * programming error to neglect to call {@link Scope#close()} on the returned instance. - */ - Scope activate(Span span); /** * Make a {@link Span} instance active. @@ -48,7 +39,7 @@ public interface ScopeManager { * *

* If there is an {@link Scope non-null scope}, its wrapped {@link Span} becomes an implicit parent of any - * newly-created {@link Span} at {@link Tracer.SpanBuilder#startActive()} time (rather than at + * newly-created {@link Span} at {@link Tracer.SpanBuilder#startActive(boolean)} time (rather than at * {@link Tracer#buildSpan(String)} time). * * @return the {@link Scope active scope}, or null if none could be found. diff --git a/opentracing-api/src/main/java/io/opentracing/Tracer.java b/opentracing-api/src/main/java/io/opentracing/Tracer.java index 5b73ea04..ab7cd975 100644 --- a/opentracing-api/src/main/java/io/opentracing/Tracer.java +++ b/opentracing-api/src/main/java/io/opentracing/Tracer.java @@ -136,7 +136,7 @@ interface SpanBuilder { *

  • {@link SpanBuilder#ignoreActiveSpan()} is not invoked, * * ... then an inferred {@link References#CHILD_OF} reference is created to the - * {@link ScopeManager#active()} {@link SpanContext} when either {@link SpanBuilder#startActive()} or + * {@link ScopeManager#active()} {@link SpanContext} when either {@link SpanBuilder#startActive(boolean)} or * {@link SpanBuilder#startManual} is invoked. * * @param referenceType the reference type, typically one of the constants defined in References @@ -171,41 +171,11 @@ interface SpanBuilder { *

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

    
    -         *     try (Scope scope = tracer.buildSpan("...").startActive()) {
    +         *     try (Scope scope = tracer.buildSpan("...").startActive(true)) {
              *         // (Do work)
              *         scope.span().setTag( ... );  // etc, etc
              *     }
    -         *     // Span finishes automatically when the Scope is closed,
    -         *     // following the default behavior of ScopeManager.activate(Span)
    -         * 
    - * - *

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

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

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

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

    @@ -241,7 +211,7 @@ interface SpanBuilder { * Like {@link #startActive()}, but the returned {@link Span} has not been registered via the * {@link ScopeManager}. * - * @see SpanBuilder#startActive() + * @see SpanBuilder#startActive(boolean) * @return the newly-started Span instance, which has *not* been automatically registered * via the {@link ScopeManager} */ diff --git a/opentracing-examples/src/test/java/io/opentracing/examples/AutoFinishScopeManager.java b/opentracing-examples/src/test/java/io/opentracing/examples/AutoFinishScopeManager.java index bfb578bd..7bc80c59 100644 --- a/opentracing-examples/src/test/java/io/opentracing/examples/AutoFinishScopeManager.java +++ b/opentracing-examples/src/test/java/io/opentracing/examples/AutoFinishScopeManager.java @@ -21,11 +21,6 @@ public class AutoFinishScopeManager implements ScopeManager { final ThreadLocal tlsScope = new ThreadLocal(); - @Override - public AutoFinishScope activate(Span span) { - return new AutoFinishScope(this, new AtomicInteger(1), span); - } - @Override public AutoFinishScope activate(Span span, boolean finishOnClose) { return new AutoFinishScope(this, new AtomicInteger(1), span); diff --git a/opentracing-examples/src/test/java/io/opentracing/examples/activate_deactivate/ScheduledActionsTest.java b/opentracing-examples/src/test/java/io/opentracing/examples/activate_deactivate/ScheduledActionsTest.java index cc5307c2..fc8651e5 100644 --- a/opentracing-examples/src/test/java/io/opentracing/examples/activate_deactivate/ScheduledActionsTest.java +++ b/opentracing-examples/src/test/java/io/opentracing/examples/activate_deactivate/ScheduledActionsTest.java @@ -89,7 +89,7 @@ private Thread entryThread() { @Override public void run() { logger.info("Entry thread started"); - try (Scope scope = tracer.buildSpan("parent").startActive()) { + try (Scope scope = tracer.buildSpan("parent").startActive(false)) { Runnable action = new RunnableAction((AutoFinishScope)scope); // Action is executed at some time and we are not able to check status @@ -108,7 +108,7 @@ private Thread entryThreadWithTwoActions() { @Override public void run() { logger.info("Entry thread 2x started"); - try (Scope scope = tracer.buildSpan("parent").startActive()) { + try (Scope scope = tracer.buildSpan("parent").startActive(false)) { Runnable action = new RunnableAction((AutoFinishScope)scope); Runnable action2 = new RunnableAction((AutoFinishScope)scope); diff --git a/opentracing-examples/src/test/java/io/opentracing/examples/active_span_replacement/ActiveSpanReplacementTest.java b/opentracing-examples/src/test/java/io/opentracing/examples/active_span_replacement/ActiveSpanReplacementTest.java index 72cb979b..39b470c8 100644 --- a/opentracing-examples/src/test/java/io/opentracing/examples/active_span_replacement/ActiveSpanReplacementTest.java +++ b/opentracing-examples/src/test/java/io/opentracing/examples/active_span_replacement/ActiveSpanReplacementTest.java @@ -74,16 +74,16 @@ private void submitAnotherTask(final Span initialSpan) { @Override public void run() { // Create a new Span for this task - try (Scope taskScope = tracer.buildSpan("task").startActive()) { + try (Scope taskScope = tracer.buildSpan("task").startActive(true)) { // Simulate work strictly related to the initial Span // and finish it. - try (Scope initialScope = tracer.scopeManager().activate(initialSpan)) { + try (Scope initialScope = tracer.scopeManager().activate(initialSpan, true)) { sleep(50); } // Restore the span for this task and create a subspan - try (Scope subTaskScope = tracer.buildSpan("subtask").startActive()) { + try (Scope subTaskScope = tracer.buildSpan("subtask").startActive(true)) { } } } diff --git a/opentracing-examples/src/test/java/io/opentracing/examples/actor_propagation/Actor.java b/opentracing-examples/src/test/java/io/opentracing/examples/actor_propagation/Actor.java index 10f812b1..7597362e 100644 --- a/opentracing-examples/src/test/java/io/opentracing/examples/actor_propagation/Actor.java +++ b/opentracing-examples/src/test/java/io/opentracing/examples/actor_propagation/Actor.java @@ -55,7 +55,7 @@ public void run() { .buildSpan("received") .addReference(References.FOLLOWS_FROM, parent.context()) .withTag(Tags.SPAN_KIND.getKey(), Tags.SPAN_KIND_CONSUMER) - .startActive()) { + .startActive(true)) { phaser.arriveAndAwaitAdvance(); // child tracer started child.span().log("received " + message); phaser.arriveAndAwaitAdvance(); // assert size @@ -79,7 +79,7 @@ public String call() throws Exception { .buildSpan("received") .addReference(References.FOLLOWS_FROM, parent.context()) .withTag(Tags.SPAN_KIND.getKey(), Tags.SPAN_KIND_CONSUMER) - .startActive()) { + .startActive(true)) { phaser.arriveAndAwaitAdvance(); // child tracer started phaser.arriveAndAwaitAdvance(); // assert size return "received " + message; diff --git a/opentracing-examples/src/test/java/io/opentracing/examples/actor_propagation/ActorPropagationTest.java b/opentracing-examples/src/test/java/io/opentracing/examples/actor_propagation/ActorPropagationTest.java index a4e72b9f..b5b8c048 100644 --- a/opentracing-examples/src/test/java/io/opentracing/examples/actor_propagation/ActorPropagationTest.java +++ b/opentracing-examples/src/test/java/io/opentracing/examples/actor_propagation/ActorPropagationTest.java @@ -60,7 +60,7 @@ public void testActorTell() { .buildSpan("actorTell") .withTag(Tags.SPAN_KIND.getKey(), Tags.SPAN_KIND_PRODUCER) .withTag(Tags.COMPONENT.getKey(), "example-actor") - .startActive()) { + .startActive(true)) { actor.tell("my message 1"); actor.tell("my message 2"); } @@ -96,7 +96,7 @@ public void testActorAsk() throws ExecutionException, InterruptedException { .buildSpan("actorAsk") .withTag(Tags.SPAN_KIND.getKey(), Tags.SPAN_KIND_PRODUCER) .withTag(Tags.COMPONENT.getKey(), "example-actor") - .startActive()) { + .startActive(true)) { future1 = actor.ask("my message 1"); future2 = actor.ask("my message 2"); } diff --git a/opentracing-examples/src/test/java/io/opentracing/examples/client_server/Client.java b/opentracing-examples/src/test/java/io/opentracing/examples/client_server/Client.java index 2954ab33..8ad6c4a8 100644 --- a/opentracing-examples/src/test/java/io/opentracing/examples/client_server/Client.java +++ b/opentracing-examples/src/test/java/io/opentracing/examples/client_server/Client.java @@ -37,7 +37,7 @@ public void send() throws InterruptedException { try (Scope scope = tracer.buildSpan("send") .withTag(Tags.SPAN_KIND.getKey(), Tags.SPAN_KIND_CLIENT) .withTag(Tags.COMPONENT.getKey(), "example-client") - .startActive()) { + .startActive(true)) { tracer.inject(scope.span().context(), Builtin.TEXT_MAP, new TextMapInjectAdapter(message)); queue.put(message); } diff --git a/opentracing-examples/src/test/java/io/opentracing/examples/client_server/Server.java b/opentracing-examples/src/test/java/io/opentracing/examples/client_server/Server.java index 240445ea..32d56b49 100644 --- a/opentracing-examples/src/test/java/io/opentracing/examples/client_server/Server.java +++ b/opentracing-examples/src/test/java/io/opentracing/examples/client_server/Server.java @@ -35,9 +35,10 @@ public Server(ArrayBlockingQueue queue, Tracer tracer) { private void process(Message message) { SpanContext context = tracer.extract(Builtin.TEXT_MAP, new TextMapExtractAdapter(message)); try (Scope scope = tracer.buildSpan("receive") - .withTag(Tags.SPAN_KIND.getKey(), Tags.SPAN_KIND_SERVER) - .withTag(Tags.COMPONENT.getKey(), "example-server") - .asChildOf(context).startActive()) { + .withTag(Tags.SPAN_KIND.getKey(), Tags.SPAN_KIND_SERVER) + .withTag(Tags.COMPONENT.getKey(), "example-server") + .asChildOf(context) + .startActive(true)) { } } diff --git a/opentracing-examples/src/test/java/io/opentracing/examples/common_request_handler/HandlerTest.java b/opentracing-examples/src/test/java/io/opentracing/examples/common_request_handler/HandlerTest.java index 3e487d4c..e691b11d 100644 --- a/opentracing-examples/src/test/java/io/opentracing/examples/common_request_handler/HandlerTest.java +++ b/opentracing-examples/src/test/java/io/opentracing/examples/common_request_handler/HandlerTest.java @@ -75,7 +75,7 @@ public void two_requests() throws Exception { */ @Test public void parent_not_picked_up() throws Exception { - try (Scope parent = tracer.buildSpan("parent").startActive()) { + try (Scope parent = tracer.buildSpan("parent").startActive(true)) { String response = client.send("no_parent").get(15, TimeUnit.SECONDS); assertEquals("no_parent:response", response); } @@ -102,7 +102,7 @@ public void parent_not_picked_up() throws Exception { @Test public void bad_solution_to_set_parent() throws Exception { Client client; - try (Scope parent = tracer.buildSpan("parent").startActive()) { + try (Scope parent = tracer.buildSpan("parent").startActive(true)) { client = new Client(new RequestHandler(tracer, parent.span().context())); String response = client.send("correct_parent").get(15, TimeUnit.SECONDS); assertEquals("correct_parent:response", response); diff --git a/opentracing-examples/src/test/java/io/opentracing/examples/late_span_finish/LateSpanFinishTest.java b/opentracing-examples/src/test/java/io/opentracing/examples/late_span_finish/LateSpanFinishTest.java index 60260771..2d6c2fba 100644 --- a/opentracing-examples/src/test/java/io/opentracing/examples/late_span_finish/LateSpanFinishTest.java +++ b/opentracing-examples/src/test/java/io/opentracing/examples/late_span_finish/LateSpanFinishTest.java @@ -73,7 +73,7 @@ private void submitTasks(final Span parentSpan) { public void run() { // Alternative to calling makeActive() is to pass it manually to asChildOf() for each created Span. try (Scope scope = tracer.scopeManager().activate(parentSpan, false)) { - try (Scope childScope1 = tracer.buildSpan("task1").startActive()) { + try (Scope childScope1 = tracer.buildSpan("task1").startActive(true)) { sleep(55); } } @@ -84,7 +84,7 @@ public void run() { @Override public void run() { try (Scope span = tracer.scopeManager().activate(parentSpan, false)) { - try (Scope childScope2 = tracer.buildSpan("task2").startActive()) { + try (Scope childScope2 = tracer.buildSpan("task2").startActive(true)) { sleep(85); } } diff --git a/opentracing-examples/src/test/java/io/opentracing/examples/multiple_callbacks/Client.java b/opentracing-examples/src/test/java/io/opentracing/examples/multiple_callbacks/Client.java index 6be803f5..e902c452 100644 --- a/opentracing-examples/src/test/java/io/opentracing/examples/multiple_callbacks/Client.java +++ b/opentracing-examples/src/test/java/io/opentracing/examples/multiple_callbacks/Client.java @@ -48,7 +48,7 @@ public Object call() throws Exception { logger.info("Child thread with message '{}' started", message); try (Scope parentScope = cont.activate()) { - try (Scope subtaskScope = tracer.buildSpan("subtask").startActive()) { + try (Scope subtaskScope = tracer.buildSpan("subtask").startActive(false)) { // Simulate work. sleep(milliseconds); } diff --git a/opentracing-examples/src/test/java/io/opentracing/examples/multiple_callbacks/MultipleCallbacksTest.java b/opentracing-examples/src/test/java/io/opentracing/examples/multiple_callbacks/MultipleCallbacksTest.java index 517e77fd..cc5d8325 100644 --- a/opentracing-examples/src/test/java/io/opentracing/examples/multiple_callbacks/MultipleCallbacksTest.java +++ b/opentracing-examples/src/test/java/io/opentracing/examples/multiple_callbacks/MultipleCallbacksTest.java @@ -37,7 +37,7 @@ public class MultipleCallbacksTest { @Test public void test() throws Exception { Client client = new Client(tracer); - try (Scope scope = tracer.buildSpan("parent").startActive()) { + try (Scope scope = tracer.buildSpan("parent").startActive(false)) { client.send("task1", 300); client.send("task2", 200); client.send("task3", 100); diff --git a/opentracing-examples/src/test/java/io/opentracing/examples/nested_callbacks/NestedCallbacksTest.java b/opentracing-examples/src/test/java/io/opentracing/examples/nested_callbacks/NestedCallbacksTest.java index 9f74fc83..a22ad6d0 100644 --- a/opentracing-examples/src/test/java/io/opentracing/examples/nested_callbacks/NestedCallbacksTest.java +++ b/opentracing-examples/src/test/java/io/opentracing/examples/nested_callbacks/NestedCallbacksTest.java @@ -78,7 +78,7 @@ public void run() { executor.submit(new Runnable() { @Override public void run() { - try (Scope scope = tracer.scopeManager().activate(span)) { + try (Scope scope = tracer.scopeManager().activate(span, true)) { span.setTag("key3", "3"); } } diff --git a/opentracing-examples/src/test/java/io/opentracing/examples/promise_propagation/Promise.java b/opentracing-examples/src/test/java/io/opentracing/examples/promise_propagation/Promise.java index 8bcf38a7..3d71020b 100644 --- a/opentracing-examples/src/test/java/io/opentracing/examples/promise_propagation/Promise.java +++ b/opentracing-examples/src/test/java/io/opentracing/examples/promise_propagation/Promise.java @@ -56,7 +56,7 @@ public void run() { .buildSpan("success") .addReference(References.FOLLOWS_FROM, parentScope.span().context()) .withTag(Tags.COMPONENT.getKey(), "success") - .startActive()) { + .startActive(true)) { callback.accept(result); } context.getPhaser().arriveAndAwaitAdvance(); // trace reported @@ -76,7 +76,7 @@ public void run() { .buildSpan("error") .addReference(References.FOLLOWS_FROM, parentScope.span().context()) .withTag(Tags.COMPONENT.getKey(), "error") - .startActive()) { + .startActive(true)) { callback.accept(error); } context.getPhaser().arriveAndAwaitAdvance(); // trace reported diff --git a/opentracing-examples/src/test/java/io/opentracing/examples/promise_propagation/PromisePropagationTest.java b/opentracing-examples/src/test/java/io/opentracing/examples/promise_propagation/PromisePropagationTest.java index 48679e8a..420cde06 100644 --- a/opentracing-examples/src/test/java/io/opentracing/examples/promise_propagation/PromisePropagationTest.java +++ b/opentracing-examples/src/test/java/io/opentracing/examples/promise_propagation/PromisePropagationTest.java @@ -60,7 +60,7 @@ public void testPromiseCallback() { tracer .buildSpan("promises") .withTag(Tags.COMPONENT.getKey(), "example-promises") - .startActive()) { + .startActive(true)) { Promise successPromise = new Promise<>(context, tracer); 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 b8327fef..111f8a62 100644 --- a/opentracing-mock/src/main/java/io/opentracing/mock/MockTracer.java +++ b/opentracing-mock/src/main/java/io/opentracing/mock/MockTracer.java @@ -346,11 +346,6 @@ public SpanBuilder withStartTimestamp(long microseconds) { return this; } - @Override - public Scope startActive() { - return MockTracer.this.scopeManager().activate(this.startManual()); - } - @Override public Scope startActive(boolean finishOnClose) { return MockTracer.this.scopeManager().activate(this.startManual(), finishOnClose); diff --git a/opentracing-noop/src/main/java/io/opentracing/noop/NoopScopeManager.java b/opentracing-noop/src/main/java/io/opentracing/noop/NoopScopeManager.java index 2b9ab300..f0588ad8 100644 --- a/opentracing-noop/src/main/java/io/opentracing/noop/NoopScopeManager.java +++ b/opentracing-noop/src/main/java/io/opentracing/noop/NoopScopeManager.java @@ -29,11 +29,6 @@ interface NoopScope extends Scope { * A noop (i.e., cheap-as-possible) implementation of an ScopeManager. */ class NoopScopeManagerImpl implements NoopScopeManager { - @Override - public Scope activate(Span span) { - return NoopScope.INSTANCE; - } - @Override public Scope activate(Span span, boolean finishOnClose) { return NoopScope.INSTANCE; diff --git a/opentracing-noop/src/main/java/io/opentracing/noop/NoopSpanBuilder.java b/opentracing-noop/src/main/java/io/opentracing/noop/NoopSpanBuilder.java index dfda5559..78cebf63 100644 --- a/opentracing-noop/src/main/java/io/opentracing/noop/NoopSpanBuilder.java +++ b/opentracing-noop/src/main/java/io/opentracing/noop/NoopSpanBuilder.java @@ -65,11 +65,6 @@ public Tracer.SpanBuilder withStartTimestamp(long microseconds) { return this; } - @Override - public Scope startActive() { - return NoopScopeManager.NoopScope.INSTANCE; - } - @Override public Scope startActive(boolean finishOnClose) { return NoopScopeManager.NoopScope.INSTANCE; 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 095c4c8f..95390463 100644 --- a/opentracing-util/src/main/java/io/opentracing/util/ThreadLocalScopeManager.java +++ b/opentracing-util/src/main/java/io/opentracing/util/ThreadLocalScopeManager.java @@ -25,11 +25,6 @@ public class ThreadLocalScopeManager implements ScopeManager { final ThreadLocal tlsScope = new ThreadLocal(); - @Override - public Scope activate(Span span) { - return new ThreadLocalScope(this, span, true); - } - @Override public Scope activate(Span span, boolean finishOnClose) { return new ThreadLocalScope(this, span, finishOnClose); diff --git a/opentracing-util/src/test/java/io/opentracing/util/ThreadLocalScopeManagerTest.java b/opentracing-util/src/test/java/io/opentracing/util/ThreadLocalScopeManagerTest.java index c5e2fc30..5390a304 100644 --- a/opentracing-util/src/test/java/io/opentracing/util/ThreadLocalScopeManagerTest.java +++ b/opentracing-util/src/test/java/io/opentracing/util/ThreadLocalScopeManagerTest.java @@ -39,11 +39,11 @@ public void missingActiveScope() throws Exception { } @Test - public void activateSpan() throws Exception { + public void defaultActivate() throws Exception { Span span = mock(Span.class); // We can't use 1.7 features like try-with-resources in this repo without meddling with pom details for tests. - Scope scope = source.activate(span); + Scope scope = source.activate(span, false); try { assertNotNull(scope); Scope otherScope = source.active(); @@ -52,8 +52,8 @@ public void activateSpan() throws Exception { scope.close(); } - // Make sure the Span got finish()ed. - verify(span, times(1)).finish(); + // Make sure the Span is not finished. + verify(span, times(0)).finish(); // And now it's gone: Scope missingScope = source.active(); @@ -61,7 +61,7 @@ public void activateSpan() throws Exception { } @Test - public void activateSpanClose() throws Exception { + public void finishSpanClose() 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. @@ -81,7 +81,7 @@ public void activateSpanClose() throws Exception { } @Test - public void activateSpanNoClose() throws Exception { + public void dontFinishSpanNoClose() 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. diff --git a/opentracing-util/src/test/java/io/opentracing/util/ThreadLocalScopeTest.java b/opentracing-util/src/test/java/io/opentracing/util/ThreadLocalScopeTest.java index e97c4cbd..cee091a0 100644 --- a/opentracing-util/src/test/java/io/opentracing/util/ThreadLocalScopeTest.java +++ b/opentracing-util/src/test/java/io/opentracing/util/ThreadLocalScopeTest.java @@ -17,7 +17,6 @@ import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNull; import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.never; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; @@ -40,12 +39,12 @@ public void implicitSpanStack() throws Exception { Span foregroundSpan = mock(Span.class); // Quasi try-with-resources (this is 1.6). - Scope backgroundActive = scopeManager.activate(backgroundSpan); + Scope backgroundActive = scopeManager.activate(backgroundSpan, true); try { assertNotNull(backgroundActive); // Activate a new Scope on top of the background one. - Scope foregroundActive = scopeManager.activate(foregroundSpan); + Scope foregroundActive = scopeManager.activate(foregroundSpan, true); try { Scope shouldBeForeground = scopeManager.active(); assertEquals(foregroundActive, shouldBeForeground); @@ -73,8 +72,8 @@ public void implicitSpanStack() throws Exception { public void testDeactivateWhenDifferentSpanIsActive() { Span span = mock(Span.class); - Scope active = scopeManager.activate(span); - scopeManager.activate(mock(Span.class)); + Scope active = scopeManager.activate(span, false); + scopeManager.activate(mock(Span.class), false); active.close(); verify(span, times(0)).finish(); From 32ae4e2ea9e48ff83222220d79b8d3ee7c7a44cb Mon Sep 17 00:00:00 2001 From: Carlos Alberto Cortez Date: Fri, 15 Dec 2017 00:15:07 -0600 Subject: [PATCH 19/19] Use the parameterless startActive() in a forgotten test in MockTracerTest. --- .../src/test/java/io/opentracing/mock/MockTracerTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 eb380d74..4709df90 100644 --- a/opentracing-mock/src/test/java/io/opentracing/mock/MockTracerTest.java +++ b/opentracing-mock/src/test/java/io/opentracing/mock/MockTracerTest.java @@ -340,7 +340,7 @@ public void testNonStandardReference() { @Test public void testDefaultConstructor() { MockTracer mockTracer = new MockTracer(); - Scope activeSpan = mockTracer.buildSpan("foo").startActive(); + Scope activeSpan = mockTracer.buildSpan("foo").startActive(true); assertEquals(activeSpan, mockTracer.scopeManager().active()); Map propag = new HashMap<>();