From aad6bca0f5c415a002408d833f7b11596848355e Mon Sep 17 00:00:00 2001 From: Ben Sigelman Date: Tue, 9 Aug 2016 11:59:58 -0400 Subject: [PATCH] Move to the immutable SpanContext model Per https://github.com/opentracing/opentracing.github.io/issues/106 --- .../src/main/java/io/opentracing/Span.java | 20 ++++++++++ .../main/java/io/opentracing/SpanContext.java | 32 ++++++---------- .../io/opentracing/AbstractSpanBuilder.java | 6 +-- .../io/opentracing/AbstractTracerTest.java | 19 +--------- .../io/opentracing/TestSpanContextImpl.java | 31 ++++++++++----- .../java/io/opentracing/TestSpanImpl.java | 38 +++++++++++++++++++ .../main/java/io/opentracing/NoopSpan.java | 6 +++ .../java/io/opentracing/NoopSpanContext.java | 12 +++--- 8 files changed, 107 insertions(+), 57 deletions(-) create mode 100644 opentracing-impl-java8/src/test/java/io/opentracing/TestSpanImpl.java diff --git a/opentracing-api/src/main/java/io/opentracing/Span.java b/opentracing-api/src/main/java/io/opentracing/Span.java index 0419da54..9428f39a 100644 --- a/opentracing-api/src/main/java/io/opentracing/Span.java +++ b/opentracing-api/src/main/java/io/opentracing/Span.java @@ -84,4 +84,24 @@ public interface Span extends AutoCloseable { * The timestamp in microseconds in UTC time. **/ Span log(long timestampMicroseconds, String eventName, /* @Nullable */ Object payload); + + /** + * 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); } diff --git a/opentracing-api/src/main/java/io/opentracing/SpanContext.java b/opentracing-api/src/main/java/io/opentracing/SpanContext.java index 553403fd..96fda174 100644 --- a/opentracing-api/src/main/java/io/opentracing/SpanContext.java +++ b/opentracing-api/src/main/java/io/opentracing/SpanContext.java @@ -13,32 +13,24 @@ */ package io.opentracing; +import java.util.Map; + /** * SpanContext represents Span state that must propagate to descendant Spans and across process boundaries. * - * SpanContext is logically divided into two pieces: (1) the user-level "Baggage" (see set_baggage_item and - * get_baggage_item) that propagates across Span boundaries and (2) any Tracer-implementation-specific fields that are - * needed to identify or otherwise contextualize the associated Span instance (e.g., a - * tuple). + * SpanContext is logically divided into two pieces: (1) the user-level "Baggage" that propagates across Span + * boundaries and (2) any Tracer-implementation-specific fields that are needed to identify or otherwise contextualize + * the associated Span instance (e.g., a tuple). + * + * @see Span#setBaggageItem(String, String) + * @see Span#getBaggageItem(String) */ public interface SpanContext { /** - * Sets a baggage item in the 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. + * @return all zero or more baggage items propagating along with the associated Span * - * Note 2: Baggage is sent in-band with every subsequent local and remote calls, so this feature must be used with - * care. - * - * @return this SpanContext instance, for chaining - */ - SpanContext 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 + * @see Span#setBaggageItem(String, String) + * @see Span#getBaggageItem(String) */ - String getBaggageItem(String key); + Iterable> baggageItems(); } diff --git a/opentracing-impl-java8/src/main/java/io/opentracing/AbstractSpanBuilder.java b/opentracing-impl-java8/src/main/java/io/opentracing/AbstractSpanBuilder.java index 17150aeb..882ab4e8 100644 --- a/opentracing-impl-java8/src/main/java/io/opentracing/AbstractSpanBuilder.java +++ b/opentracing-impl-java8/src/main/java/io/opentracing/AbstractSpanBuilder.java @@ -13,10 +13,6 @@ */ package io.opentracing; -import io.opentracing.References; -import io.opentracing.Span; -import io.opentracing.SpanContext; -import io.opentracing.Tracer; import java.time.Instant; import java.util.ArrayList; import java.util.HashMap; @@ -88,7 +84,7 @@ public final Span start() { stringTags.entrySet().stream().forEach((entry) -> { span.setTag(entry.getKey(), entry.getValue()); }); booleanTags.entrySet().stream().forEach((entry) -> { span.setTag(entry.getKey(), entry.getValue()); }); numberTags.entrySet().stream().forEach((entry) -> { span.setTag(entry.getKey(), entry.getValue()); }); - baggage.entrySet().stream().forEach((entry) -> { span.context().setBaggageItem(entry.getKey(), entry.getValue()); }); + baggage.entrySet().stream().forEach((entry) -> { span.setBaggageItem(entry.getKey(), entry.getValue()); }); return span; } diff --git a/opentracing-impl-java8/src/test/java/io/opentracing/AbstractTracerTest.java b/opentracing-impl-java8/src/test/java/io/opentracing/AbstractTracerTest.java index c942d386..11981363 100644 --- a/opentracing-impl-java8/src/test/java/io/opentracing/AbstractTracerTest.java +++ b/opentracing-impl-java8/src/test/java/io/opentracing/AbstractTracerTest.java @@ -48,15 +48,7 @@ public void testInject() { AbstractTracer instance = new TestTracerImpl(); instance.register(TextMap.class, new TestTextMapInjectorImpl()); - String operationName = "test-inject-span"; - Span span = new AbstractSpan(operationName) { - SpanContext spanContext = new TestSpanContextImpl("whatever"); - - @Override - public SpanContext context() { - return spanContext; - } - }; + Span span = new TestSpanImpl("test-inject-span"); Map map = new HashMap<>(); TextMap carrier = new TextMapInjectAdapter(map); instance.inject(span.context(), Format.Builtin.TEXT_MAP, carrier); @@ -106,14 +98,7 @@ public AbstractSpanBuilder createSpanBuilder(String operationName) { return new AbstractSpanBuilder(operationName) { @Override protected AbstractSpan createSpan() { - return new AbstractSpan(this.operationName) { - SpanContext spanContext = new TestSpanContextImpl("op=" + operationName); - - @Override - public SpanContext context() { - return spanContext; - } - }; + return new TestSpanImpl(this.operationName); } }; } diff --git a/opentracing-impl-java8/src/test/java/io/opentracing/TestSpanContextImpl.java b/opentracing-impl-java8/src/test/java/io/opentracing/TestSpanContextImpl.java index a682ade5..77ccfd6d 100644 --- a/opentracing-impl-java8/src/test/java/io/opentracing/TestSpanContextImpl.java +++ b/opentracing-impl-java8/src/test/java/io/opentracing/TestSpanContextImpl.java @@ -18,22 +18,35 @@ public class TestSpanContextImpl implements SpanContext { final String marker; - protected Map baggage = new HashMap(); + protected final Map baggage; public TestSpanContextImpl(String marker) { - this.marker = marker; + this(marker, new HashMap<>()); } - public String getMarker() { return marker; } + public TestSpanContextImpl(String marker, Map adoptedBaggage) { + this.marker = marker; + this.baggage = adoptedBaggage; + } @Override - public synchronized SpanContext setBaggageItem(String key, String value) { - this.baggage.put(key, value); - return this; + public Iterable> baggageItems() { + return baggage.entrySet(); } - @Override - public synchronized String getBaggageItem(String key) { - return this.baggage.get(key); + /////////////////////////////////////////////////////////////////////////////////// + // Implementation-specific extensions (mainly to support the immutable idiom here). + /////////////////////////////////////////////////////////////////////////////////// + + public TestSpanContextImpl withBaggageItem(String key, String val) { + Map baggageCopy = new HashMap<>(baggage); + baggageCopy.put(key, val); + return new TestSpanContextImpl(marker, baggageCopy); + } + + public String getBaggageItem(String key) { + return baggage.get(key); } + + public String getMarker() { return marker; } } diff --git a/opentracing-impl-java8/src/test/java/io/opentracing/TestSpanImpl.java b/opentracing-impl-java8/src/test/java/io/opentracing/TestSpanImpl.java new file mode 100644 index 00000000..eace44ee --- /dev/null +++ b/opentracing-impl-java8/src/test/java/io/opentracing/TestSpanImpl.java @@ -0,0 +1,38 @@ +/** + * Copyright 2016 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; + +public class TestSpanImpl extends AbstractSpan { + TestSpanContextImpl spanContext = new TestSpanContextImpl("whatever"); + + TestSpanImpl(String operationName) { + super(operationName); + } + + @Override + public SpanContext context() { + return spanContext; + } + + @Override + public synchronized Span setBaggageItem(String key, String value) { + spanContext = spanContext.withBaggageItem(key, value); + return this; + } + + @Override + public synchronized String getBaggageItem(String key) { + return spanContext.getBaggageItem(key); + } +} diff --git a/opentracing-impl/src/main/java/io/opentracing/NoopSpan.java b/opentracing-impl/src/main/java/io/opentracing/NoopSpan.java index d8152835..b6bf38b1 100644 --- a/opentracing-impl/src/main/java/io/opentracing/NoopSpan.java +++ b/opentracing-impl/src/main/java/io/opentracing/NoopSpan.java @@ -59,4 +59,10 @@ public Span log(long timestampMicroseconds, String eventName, Object payload) { return this; } + @Override + public Span setBaggageItem(String key, String value) { return this; } + + @Override + public String getBaggageItem(String key) { return null; } + } diff --git a/opentracing-impl/src/main/java/io/opentracing/NoopSpanContext.java b/opentracing-impl/src/main/java/io/opentracing/NoopSpanContext.java index bf3432b8..b238170a 100644 --- a/opentracing-impl/src/main/java/io/opentracing/NoopSpanContext.java +++ b/opentracing-impl/src/main/java/io/opentracing/NoopSpanContext.java @@ -13,14 +13,14 @@ */ package io.opentracing; +import java.util.HashMap; +import java.util.Map; + public class NoopSpanContext implements SpanContext { - @Override - public SpanContext setBaggageItem(String key, String value) { - return this; - } + private static Map EMPTY_MAP = new HashMap<>(); @Override - public String getBaggageItem(String key) { - return null; + public Iterable> baggageItems() { + return EMPTY_MAP.entrySet(); } }