Merge pull request #1607 from spring-cloud/deprecate-spring-messaging-headers

Stops propagating Sleuth 1.x spring-messaging headers
This commit is contained in:
Adrian Cole
2020-04-07 11:13:54 +08:00
committed by GitHub
22 changed files with 233 additions and 316 deletions

View File

@@ -132,13 +132,6 @@
<dependencyManagement>
<dependencies>
<!-- force latest reactor-netty -->
<dependency>
<groupId>io.projectreactor.netty</groupId>
<artifactId>reactor-netty</artifactId>
<version>0.9.6.RELEASE</version>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-sleuth-dependencies</artifactId>

View File

@@ -72,11 +72,16 @@ public class TraceBaggageAutoConfiguration {
* To override the underlying context format, override this bean and set the delegate
* to what you need. {@link BaggagePropagation.FactoryBuilder} will unwrap itself if
* no fields are configured.
*
* <p>
* This will use {@link B3Propagation.Format#SINGLE_NO_PARENT} for non-remote spans,
* such as for messaging. Note: it will still parse incoming multi-header spans.
*/
@Bean
@ConditionalOnMissingBean
BaggagePropagation.FactoryBuilder baggagePropagationFactoryBuilder() {
return BaggagePropagation.newFactoryBuilder(B3Propagation.FACTORY);
return BaggagePropagation.newFactoryBuilder(B3Propagation.newFactoryBuilder()
.injectFormat(B3Propagation.Format.SINGLE_NO_PARENT).build());
}
@Bean

View File

@@ -19,8 +19,11 @@ package org.springframework.cloud.sleuth.instrument.messaging;
import java.nio.charset.StandardCharsets;
import java.util.Collections;
import java.util.HashMap;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.atomic.AtomicBoolean;
import brave.propagation.Propagation;
import org.apache.commons.logging.Log;
@@ -45,25 +48,19 @@ enum MessageHeaderPropagation
private static final Log log = LogFactory.getLog(MessageHeaderPropagation.class);
private static final Set<String> DEPRECATED_HEADERS = new LinkedHashSet<>();
private static final Map<String, String> LEGACY_HEADER_MAPPING = new HashMap<>();
private static final String TRACE_ID_NAME = "X-B3-TraceId";
private static final String SPAN_ID_NAME = "X-B3-SpanId";
private static final String PARENT_SPAN_ID_NAME = "X-B3-ParentSpanId";
private static final String SAMPLED_NAME = "X-B3-Sampled";
private static final String FLAGS_NAME = "X-B3-Flags";
static {
LEGACY_HEADER_MAPPING.put(TRACE_ID_NAME, TraceMessageHeaders.TRACE_ID_NAME);
LEGACY_HEADER_MAPPING.put(SPAN_ID_NAME, TraceMessageHeaders.SPAN_ID_NAME);
LEGACY_HEADER_MAPPING.put(PARENT_SPAN_ID_NAME,
LEGACY_HEADER_MAPPING.put("X-B3-TraceId", TraceMessageHeaders.TRACE_ID_NAME);
LEGACY_HEADER_MAPPING.put("X-B3-SpanId", TraceMessageHeaders.SPAN_ID_NAME);
LEGACY_HEADER_MAPPING.put("X-B3-ParentSpanId",
TraceMessageHeaders.PARENT_ID_NAME);
LEGACY_HEADER_MAPPING.put(SAMPLED_NAME, TraceMessageHeaders.SAMPLED_NAME);
LEGACY_HEADER_MAPPING.put(FLAGS_NAME, TraceMessageHeaders.SPAN_FLAGS_NAME);
LEGACY_HEADER_MAPPING.put("X-B3-Sampled", TraceMessageHeaders.SAMPLED_NAME);
LEGACY_HEADER_MAPPING.put("X-B3-Flags", TraceMessageHeaders.SPAN_FLAGS_NAME);
DEPRECATED_HEADERS.addAll(LEGACY_HEADER_MAPPING.keySet());
DEPRECATED_HEADERS.addAll(LEGACY_HEADER_MAPPING.values());
}
static Map<String, ?> propagationHeaders(Map<String, ?> headers,
@@ -119,8 +116,15 @@ enum MessageHeaderPropagation
return nativeAccessor;
}
static final AtomicBoolean LOGGED_PUT_DEPRECATED_HEADER = new AtomicBoolean();
@Override
public void put(MessageHeaderAccessor accessor, String key, String value) {
if (DEPRECATED_HEADERS.contains(key)
&& LOGGED_PUT_DEPRECATED_HEADER.compareAndSet(false, true)) {
log.warn("Please update your code so that it uses the 'b3' header "
+ "instead of " + key);
}
try {
doPut(accessor, key, value);
}
@@ -130,10 +134,6 @@ enum MessageHeaderPropagation
+ "] from message", ex);
}
}
String legacyKey = LEGACY_HEADER_MAPPING.get(key);
if (legacyKey != null) {
doPut(accessor, legacyKey, value);
}
}
private void doPut(MessageHeaderAccessor accessor, String key, String value) {
@@ -188,7 +188,14 @@ enum MessageHeaderPropagation
return null;
}
static final AtomicBoolean LOGGED_GET_DEPRECATED_HEADER = new AtomicBoolean();
private String doGet(MessageHeaderAccessor accessor, String key) {
if (DEPRECATED_HEADERS.contains(key)
&& LOGGED_GET_DEPRECATED_HEADER.compareAndSet(false, true)) {
log.warn("Please update your code so that it uses the 'b3' header "
+ "instead of " + key);
}
if (accessor instanceof NativeMessageHeaderAccessor) {
NativeMessageHeaderAccessor nativeAccessor = (NativeMessageHeaderAccessor) accessor;
String result = nativeAccessor.getFirstNativeHeader(key);

View File

@@ -23,7 +23,9 @@ package org.springframework.cloud.sleuth.instrument.messaging;
*
* @author Marcin Grzejszczak
* @since 1.0.4
* @deprecated Since 3.0 these headers should not be used anymore as "b3" is sent instead
*/
@Deprecated
public final class TraceMessageHeaders {
/**

View File

@@ -16,6 +16,7 @@
package org.springframework.cloud.sleuth.autoconfig;
import brave.Tracing;
import brave.baggage.BaggagePropagation;
import brave.propagation.B3Propagation;
import brave.propagation.B3SinglePropagation;
@@ -41,8 +42,8 @@ public class TraceAutoConfigurationPropagationCustomizationTests {
@Test
public void stillCreatesDefault() {
this.contextRunner.run((context) -> {
BDDAssertions.then(context.getBean(Propagation.Factory.class))
.isEqualTo(B3Propagation.FACTORY);
BDDAssertions.then(context.getBean(Tracing.class).propagation())
.isInstanceOf(B3Propagation.class);
});
}
@@ -52,8 +53,7 @@ public class TraceAutoConfigurationPropagationCustomizationTests {
.withPropertyValues("spring.sleuth.baggage.remote-fields=country-code")
.run((context) -> {
BDDAssertions.then(context.getBean(Propagation.Factory.class))
.hasFieldOrPropertyWithValue("delegate",
B3Propagation.FACTORY);
.extracting("delegate").isNotNull();
});
}
@@ -61,8 +61,8 @@ public class TraceAutoConfigurationPropagationCustomizationTests {
public void defaultValueUsedWhenApplicationNameNotSet() {
this.contextRunner.withPropertyValues("spring.application.name=")
.run((context) -> {
BDDAssertions.then(context.getBean(Propagation.Factory.class))
.isEqualTo(B3Propagation.FACTORY);
BDDAssertions.then(context.getBean(Tracing.class).propagation())
.isInstanceOf(B3Propagation.class);
});
}

View File

@@ -56,26 +56,26 @@ public class MessageHeaderPropagationTest
@Test
public void testGetByteArrayValue() {
MessageHeaderAccessor carrier = carrier();
carrier.setHeader("X-B3-TraceId", "48485a3953bb6124".getBytes());
carrier.setHeader("X-B3-TraceId", "48485a3953bb6124000000".getBytes());
String value = MessageHeaderPropagation.INSTANCE.get(carrier, "X-B3-TraceId");
assertThat(value).isEqualTo("48485a3953bb6124000000");
carrier.setHeader("b3", "48485a3953bb6124-1234".getBytes());
carrier.setHeader("b3", "48485a3953bb6124000000-1234".getBytes());
String value = MessageHeaderPropagation.INSTANCE.get(carrier, "b3");
assertThat(value).isEqualTo("48485a3953bb6124000000-1234");
}
@Test
public void testGetStringValue() {
MessageHeaderAccessor carrier = carrier();
carrier.setHeader("X-B3-TraceId", "48485a3953bb6124");
carrier.setHeader("X-B3-TraceId", "48485a3953bb61240000000");
String value = MessageHeaderPropagation.INSTANCE.get(carrier, "X-B3-TraceId");
assertThat(value).isEqualTo("48485a3953bb61240000000");
carrier.setHeader("B3", "48485a3953bb6124-1234");
carrier.setHeader("B3", "48485a3953bb61240000000-1234");
String value = MessageHeaderPropagation.INSTANCE.get(carrier, "B3");
assertThat(value).isEqualTo("48485a3953bb61240000000-1234");
}
@Test
public void testGetNullValue() {
MessageHeaderAccessor carrier = carrier();
carrier.setHeader("X-B3-TraceId", "48485a3953bb6124");
carrier.setHeader("X-B3-TraceId", "48485a3953bb61240000000");
carrier.setHeader("B3", "48485a3953bb6124-1234");
carrier.setHeader("B3", "48485a3953bb61240000000-1234");
String value = MessageHeaderPropagation.INSTANCE.get(carrier, "non existent key");
assertThat(value).isNull();
}
@@ -85,7 +85,7 @@ public class MessageHeaderPropagationTest
MessageHeaderAccessor carrier = carrier();
carrier.setHeader(NativeMessageHeaderAccessor.NATIVE_HEADERS,
"{spanTraceId=[123], spanId=[456], spanSampled=[0]}");
MessageHeaderPropagation.INSTANCE.get(carrier, "X-B3-SpanId");
MessageHeaderPropagation.INSTANCE.get(carrier, "b3");
}
@Test
@@ -94,7 +94,7 @@ public class MessageHeaderPropagationTest
carrier.setHeader(NativeMessageHeaderAccessor.NATIVE_HEADERS,
"{spanTraceId=[123], spanId=[456], spanSampled=[0]}");
MessageHeaderPropagation.removeAnyTraceHeaders(carrier,
Collections.singletonList("X-B3-SpanId"));
Collections.singletonList("b3"));
}
@Test
@@ -102,7 +102,7 @@ public class MessageHeaderPropagationTest
MessageHeaderAccessor carrier = carrier();
carrier.setHeader(NativeMessageHeaderAccessor.NATIVE_HEADERS,
"{spanTraceId=[123], spanId=[456], spanSampled=[0]}");
MessageHeaderPropagation.INSTANCE.put(carrier, "X-B3-SpanId", "1234");
MessageHeaderPropagation.INSTANCE.put(carrier, "b3", "1234");
}
}

View File

@@ -40,40 +40,38 @@ public abstract class PropagationSetterTest<C, K> {
@Test
public void set() throws Exception {
K key = keyFactory().create("X-B3-TraceId");
setter().put(carrier(), key, "48485a3953bb6124");
K key = keyFactory().create("b3");
setter().put(carrier(), key, "1");
assertThat(read(carrier(), key)).containsExactly("48485a3953bb6124");
assertThat(read(carrier(), key)).containsExactly("1");
}
@Test
public void set128() throws Exception {
K key = keyFactory().create("X-B3-TraceId");
setter().put(carrier(), key, "463ac35c9f6413ad48485a3953bb6124");
K key = keyFactory().create("b3");
setter().put(carrier(), key, "1");
assertThat(read(carrier(), key))
.containsExactly("463ac35c9f6413ad48485a3953bb6124");
assertThat(read(carrier(), key)).containsExactly("1");
}
@Test
public void setTwoKeys() throws Exception {
K key1 = keyFactory().create("X-B3-TraceId");
K key2 = keyFactory().create("X-B3-SpanId");
setter().put(carrier(), key1, "463ac35c9f6413ad48485a3953bb6124");
setter().put(carrier(), key2, "48485a3953bb6124");
K key1 = keyFactory().create("b3");
K key2 = keyFactory().create("baggage");
setter().put(carrier(), key1, "1");
setter().put(carrier(), key2, "country-code=FO");
assertThat(read(carrier(), key1))
.containsExactly("463ac35c9f6413ad48485a3953bb6124");
assertThat(read(carrier(), key2)).containsExactly("48485a3953bb6124");
assertThat(read(carrier(), key1)).containsExactly("1");
assertThat(read(carrier(), key2)).containsExactly("country-code=FO");
}
@Test
public void reset() throws Exception {
K key = keyFactory().create("X-B3-TraceId");
setter().put(carrier(), key, "48485a3953bb6124");
setter().put(carrier(), key, "463ac35c9f6413ad");
K key = keyFactory().create("b3");
setter().put(carrier(), key, "0");
setter().put(carrier(), key, "1");
assertThat(read(carrier(), key)).containsExactly("463ac35c9f6413ad");
assertThat(read(carrier(), key)).containsExactly("1");
}
}

View File

@@ -17,13 +17,14 @@
package org.springframework.cloud.sleuth.instrument.messaging;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import brave.Tracing;
import brave.propagation.B3Propagation;
import brave.propagation.StrictCurrentTraceContext;
import brave.propagation.TraceContext;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.Test;
import zipkin2.Span;
@@ -45,6 +46,8 @@ import org.springframework.messaging.support.ExecutorSubscribableChannel;
import org.springframework.messaging.support.MessageBuilder;
import org.springframework.messaging.support.NativeMessageHeaderAccessor;
import static brave.propagation.B3Propagation.Format.SINGLE;
import static brave.propagation.B3SingleFormat.parseB3SingleFormat;
import static org.assertj.core.api.Assertions.assertThat;
import static org.springframework.messaging.support.NativeMessageHeaderAccessor.NATIVE_HEADERS;
@@ -55,6 +58,10 @@ public class TracingChannelInterceptorTest {
List<Span> spans = new ArrayList<>();
Tracing tracing = Tracing.newBuilder().currentTraceContext(this.currentTraceContext)
// SINGLE_NO_PARENT more appropriate for messaging, but we check parent
// hereTraceMessageHeaders
.propagationFactory(
B3Propagation.newFactoryBuilder().injectFormat(SINGLE).build())
.spanReporter(this.spans::add).build();
ChannelInterceptor interceptor = TracingChannelInterceptor.create(tracing);
@@ -92,8 +99,7 @@ public class TracingChannelInterceptorTest {
this.channel.send(MessageBuilder.withPayload("foo").build());
assertThat(this.channel.receive().getHeaders()).containsKeys("X-B3-TraceId",
"X-B3-SpanId", "X-B3-Sampled", "nativeHeaders");
assertThat(this.channel.receive().getHeaders()).containsKey("b3");
assertThat(this.spans).hasSize(1).flatExtracting(Span::kind)
.containsExactly(Span.Kind.PRODUCER);
}
@@ -105,8 +111,7 @@ public class TracingChannelInterceptorTest {
this.directChannel.send(MessageBuilder.withPayload("foo").build());
assertThat(this.message).isNotNull();
assertThat(this.message.getHeaders()).containsKeys("X-B3-TraceId", "X-B3-SpanId",
"X-B3-Sampled", "nativeHeaders");
assertThat(this.message.getHeaders()).containsKeys("b3", "nativeHeaders");
assertThat(this.spans).flatExtracting(Span::kind).contains(Span.Kind.CONSUMER,
Span.Kind.PRODUCER);
}
@@ -118,8 +123,7 @@ public class TracingChannelInterceptorTest {
this.channel.send(MessageBuilder.withPayload("foo").build());
assertThat((Map) this.channel.receive().getHeaders().get(NATIVE_HEADERS))
.containsOnlyKeys("X-B3-TraceId", "X-B3-SpanId", "X-B3-Sampled",
"spanTraceId", "spanId", "spanSampled");
.containsOnlyKeys("b3");
}
/**
@@ -132,12 +136,11 @@ public class TracingChannelInterceptorTest {
this.channel.addInterceptor(producerSideOnly(this.interceptor));
this.channel.send(MessageBuilder.withPayload("foo")
.setHeader("X-B3-TraceId", "000000000000000a")
.setHeader("X-B3-ParentSpanId", "000000000000000a")
.setHeader("X-B3-SpanId", "000000000000000b").build());
.setHeader("b3", "000000000000000a-000000000000000b-1").build());
assertThat(this.channel.receive().getHeaders()).containsEntry("X-B3-ParentSpanId",
"000000000000000b");
TraceContext receiveContext = parseB3SingleFormat(
this.channel.receive().getHeaders().get("b3", String.class)).context();
assertThat(receiveContext.parentIdString()).isEqualTo("000000000000000b");
}
@Test
@@ -147,16 +150,16 @@ public class TracingChannelInterceptorTest {
NativeMessageHeaderAccessor accessor = new NativeMessageHeaderAccessor() {
};
accessor.setNativeHeader("X-B3-TraceId", "000000000000000a");
accessor.setNativeHeader("X-B3-ParentSpanId", "000000000000000a");
accessor.setNativeHeader("X-B3-SpanId", "000000000000000b");
accessor.setNativeHeader("b3",
"000000000000000a-000000000000000b-1-000000000000000a");
this.channel.send(MessageBuilder.withPayload("foo")
.copyHeaders(accessor.toMessageHeaders()).build());
assertThat((Map) this.channel.receive().getHeaders().get(NATIVE_HEADERS))
.containsEntry("X-B3-ParentSpanId",
Collections.singletonList("000000000000000b"));
TraceContext receiveContext = parseB3SingleFormat(
((List) ((Map) this.channel.receive().getHeaders().get(NATIVE_HEADERS))
.get("b3")).get(0).toString()).context();
assertThat(receiveContext.parentIdString()).isEqualTo("000000000000000b");
}
/**
@@ -169,8 +172,8 @@ public class TracingChannelInterceptorTest {
this.channel.send(MessageBuilder.withPayload("foo").build());
assertThat(this.channel.receive().getHeaders()).containsKeys("X-B3-TraceId",
"X-B3-SpanId", "X-B3-Sampled", "nativeHeaders");
assertThat(this.channel.receive().getHeaders()).containsKeys("b3",
"nativeHeaders");
assertThat(this.spans).hasSize(1).flatExtracting(Span::kind)
.containsExactly(Span.Kind.CONSUMER);
}
@@ -182,8 +185,7 @@ public class TracingChannelInterceptorTest {
this.channel.send(MessageBuilder.withPayload("foo").build());
assertThat((Map) this.channel.receive().getHeaders().get(NATIVE_HEADERS))
.containsOnlyKeys("X-B3-TraceId", "X-B3-SpanId", "X-B3-Sampled",
"spanTraceId", "spanId", "spanSampled");
.containsOnlyKeys("b3");
}
@Test
@@ -195,8 +197,8 @@ public class TracingChannelInterceptorTest {
channel.send(MessageBuilder.withPayload("foo").build());
assertThat(messages.get(0).getHeaders()).doesNotContainKeys("X-B3-TraceId",
"X-B3-SpanId", "X-B3-Sampled", "nativeHeaders");
assertThat(messages.get(0).getHeaders()).doesNotContainKeys("b3",
"nativeHeaders");
assertThat(this.spans).flatExtracting(Span::kind)
.containsExactly(Span.Kind.CONSUMER, null);
}
@@ -215,8 +217,7 @@ public class TracingChannelInterceptorTest {
channel.send(MessageBuilder.withPayload("foo").build());
assertThat(messages.get(0).getHeaders()).doesNotContainKeys("X-B3-TraceId",
"X-B3-SpanId", "X-B3-Sampled");
assertThat(messages.get(0).getHeaders()).doesNotContainKeys("b3");
}
@Test
@@ -229,7 +230,7 @@ public class TracingChannelInterceptorTest {
channel.send(MessageBuilder.withPayload("foo").build());
assertThat((Map) messages.get(0).getHeaders().get(NATIVE_HEADERS))
.doesNotContainKeys("X-B3-TraceId", "X-B3-SpanId", "X-B3-Sampled");
.doesNotContainKeys("b3");
}
@Test
@@ -264,27 +265,23 @@ public class TracingChannelInterceptorTest {
Map<String, Object> errorChannelHeaders = new HashMap<>();
errorChannelHeaders.put(MessageHeaders.REPLY_CHANNEL, errorsReplyChannel);
errorChannelHeaders.put(MessageHeaders.ERROR_CHANNEL, errorsReplyChannel);
this.channel
.send(new ErrorMessage(
new MessagingException(MessageBuilder.withPayload("hi")
.setHeader(TraceMessageHeaders.TRACE_ID_NAME,
"000000000000000a")
.setHeader(TraceMessageHeaders.SPAN_ID_NAME,
"000000000000000a")
.setReplyChannel(deadReplyChannel)
.setErrorChannel(deadReplyChannel).build()),
errorChannelHeaders));
this.channel.send(new ErrorMessage(
new MessagingException(MessageBuilder.withPayload("hi")
.setHeader("b3", "000000000000000a-000000000000000a")
.setReplyChannel(deadReplyChannel)
.setErrorChannel(deadReplyChannel).build()),
errorChannelHeaders));
this.message = this.channel.receive();
assertThat(this.message).isNotNull();
String spanId = this.message.getHeaders().get(TraceMessageHeaders.SPAN_ID_NAME,
String.class);
assertThat(spanId).isNotNull();
String traceId = this.message.getHeaders().get(TraceMessageHeaders.TRACE_ID_NAME,
String.class);
assertThat(traceId).isEqualTo("000000000000000a");
assertThat(spanId).isNotEqualTo("000000000000000a");
// Parse fails if trace or span ID are missing
TraceContext context = parseB3SingleFormat(
this.message.getHeaders().get("b3", String.class)).context();
assertThat(context.traceIdString()).isEqualTo("000000000000000a");
assertThat(context.spanIdString()).isNotEqualTo("000000000000000a");
assertThat(this.spans).hasSize(2);
assertThat(this.message.getHeaders().getReplyChannel())
.isSameAs(errorsReplyChannel);
@@ -318,21 +315,16 @@ public class TracingChannelInterceptorTest {
public void errorMessageHeadersWithNullPayloadRetained() {
this.channel.addInterceptor(this.interceptor);
Map<String, Object> errorChannelHeaders = new HashMap<>();
errorChannelHeaders.put(TraceMessageHeaders.TRACE_ID_NAME, "000000000000000a");
errorChannelHeaders.put(TraceMessageHeaders.SPAN_ID_NAME, "000000000000000a");
errorChannelHeaders.put("b3", "000000000000000a-000000000000000a");
this.channel.send(new ErrorMessage(new MessagingException("exception"),
errorChannelHeaders));
this.message = this.channel.receive();
assertThat(this.message).isNotNull();
String spanId = this.message.getHeaders().get(TraceMessageHeaders.SPAN_ID_NAME,
String.class);
assertThat(spanId).isNotNull();
String traceId = this.message.getHeaders().get(TraceMessageHeaders.TRACE_ID_NAME,
String.class);
assertThat(traceId).isEqualTo("000000000000000a");
assertThat(spanId).isNotEqualTo("000000000000000a");
TraceContext receiveContext = parseB3SingleFormat(
this.message.getHeaders().get("b3", String.class)).context();
assertThat(receiveContext.traceIdString()).isEqualTo("000000000000000a");
assertThat(receiveContext.spanIdString()).isNotEqualTo("000000000000000a");
assertThat(this.spans).hasSize(2);
}

View File

@@ -41,6 +41,7 @@ import org.springframework.cloud.sleuth.util.ArrayListSpanReporter;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import static java.util.Collections.singletonMap;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.data.MapEntry.entry;
import static org.springframework.boot.test.context.SpringBootTest.WebEnvironment.NONE;
@@ -82,10 +83,8 @@ public class BraveTracerTest {
@Test
public void extractTraceContext() {
Map<String, String> map = new LinkedHashMap<>();
map.put("X-B3-TraceId", "0000000000000001");
map.put("X-B3-SpanId", "0000000000000002");
map.put("X-B3-Sampled", "1");
Map<String, String> map = singletonMap("b3",
"0000000000000001-0000000000000002-1");
BraveSpanContext openTracingContext = this.opentracing
.extract(Format.Builtin.HTTP_HEADERS, new TextMapAdapter(map));
@@ -97,9 +96,7 @@ public class BraveTracerTest {
@Test
public void extractBaggage() {
Map<String, String> map = new LinkedHashMap<>();
map.put("X-B3-TraceId", "0000000000000001");
map.put("X-B3-SpanId", "0000000000000002");
map.put("X-B3-Sampled", "1");
map.put("b3", "0000000000000001-0000000000000002-1");
map.put("country-code", "FO");
BraveSpanContext openTracingContext = this.opentracing
@@ -111,10 +108,8 @@ public class BraveTracerTest {
@Test
public void extractTraceContextTextMap() {
Map<String, String> map = new LinkedHashMap<>();
map.put("X-B3-TraceId", "0000000000000001");
map.put("X-B3-SpanId", "0000000000000002");
map.put("X-B3-Sampled", "1");
Map<String, String> map = singletonMap("b3",
"0000000000000001-0000000000000002-1");
BraveSpanContext openTracingContext = this.opentracing
.extract(Format.Builtin.TEXT_MAP, new TextMapAdapter(map));
@@ -126,9 +121,7 @@ public class BraveTracerTest {
@Test
public void extractTraceContextCaseInsensitive() {
Map<String, String> map = new LinkedHashMap<>();
map.put("X-B3-TraceId", "0000000000000001");
map.put("x-b3-spanid", "0000000000000002");
map.put("x-b3-SaMpLeD", "1");
map.put("B3", "0000000000000001-0000000000000002-1");
map.put("other", "1");
BraveSpanContext openTracingContext = this.opentracing

View File

@@ -36,7 +36,6 @@ import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.springframework.cloud.sleuth.util.ArrayListSpanReporter;
import org.springframework.cloud.sleuth.util.SpanUtil;
import org.springframework.http.HttpMethod;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
@@ -55,13 +54,6 @@ import static org.springframework.test.web.servlet.request.MockMvcRequestBuilder
*/
public class TraceFilterTests {
static final String PARENT_ID = SpanUtil.idToHex(10L);
static final String TRACE_ID_NAME = "X-B3-TraceId";
static final String SPAN_ID_NAME = "X-B3-SpanId";
static final String PARENT_SPAN_ID_NAME = "X-B3-ParentSpanId";
static final String SAMPLED_ID_NAME = "X-B3-Sampled";
static final String SPAN_FLAGS = "X-B3-Flags";
ArrayListSpanReporter reporter = new ArrayListSpanReporter();
Tracing tracing = Tracing.newBuilder()
@@ -152,16 +144,15 @@ public class TraceFilterTests {
@Test
public void startsNewTraceWithParentIdInHeaders() throws Exception {
this.request = builder().header(SPAN_ID_NAME, PARENT_ID)
.header(TRACE_ID_NAME, SpanUtil.idToHex(2L))
.header(PARENT_SPAN_ID_NAME, SpanUtil.idToHex(3L))
this.request = builder()
.header("b3", "0000000000000002-0000000000000003-1-000000000000000a")
.buildRequest(new MockServletContext());
this.filter.doFilter(this.request, this.response, this.filterChain);
then(Tracing.current().tracer().currentSpan()).isNull();
then(this.reporter.getSpans()).hasSize(1);
then(this.reporter.getSpans().get(0).id()).isEqualTo(PARENT_ID);
then(this.reporter.getSpans().get(0).id()).isEqualTo("0000000000000003");
then(this.reporter.getSpans().get(0).tags()).containsEntry("http.path", "/")
.containsEntry("http.method", HttpMethod.GET.toString());
}
@@ -169,10 +160,8 @@ public class TraceFilterTests {
@Test
public void continuesATraceWhenSpanNotSampled() throws Exception {
AtomicReference<Span> span = new AtomicReference<>();
this.request = builder().header(SPAN_ID_NAME, PARENT_ID)
.header(TRACE_ID_NAME, SpanUtil.idToHex(2L))
.header(PARENT_SPAN_ID_NAME, SpanUtil.idToHex(3L))
.header(SAMPLED_ID_NAME, 0).buildRequest(new MockServletContext());
this.request = builder().header("b3", "0000000000000014-000000000000000a-0")
.buildRequest(new MockServletContext());
this.filter.doFilter(this.request, this.response, (req, resp) -> {
this.filterChain.doFilter(req, resp);
@@ -180,7 +169,7 @@ public class TraceFilterTests {
});
then(Tracing.current().tracer().currentSpan()).isNull();
then(span.get().context().traceIdString()).isEqualTo(SpanUtil.idToHex(2L));
then(span.get().context().traceIdString()).isEqualTo("0000000000000014");
}
@Test
@@ -215,8 +204,7 @@ public class TraceFilterTests {
@Test
public void continuesSpanFromHeaders() throws Exception {
this.request = builder().header(SPAN_ID_NAME, PARENT_ID)
.header(TRACE_ID_NAME, SpanUtil.idToHex(20L))
this.request = builder().header("b3", "0000000000000014-000000000000000a")
.buildRequest(new MockServletContext());
this.filter.doFilter(this.request, this.response, this.filterChain);
@@ -232,8 +220,7 @@ public class TraceFilterTests {
.addScopeDecorator(StrictScopeDecorator.create()).build())
.spanReporter(this.reporter).supportsJoin(false).build();
HttpTracing httpTracing = HttpTracing.create(tracing);
this.request = builder().header(SPAN_ID_NAME, PARENT_ID)
.header(TRACE_ID_NAME, SpanUtil.idToHex(20L))
this.request = builder().header("b3", "0000000000000014-000000000000000a")
.buildRequest(new MockServletContext());
TracingFilter.create(httpTracing).doFilter(this.request, this.response,
@@ -241,13 +228,12 @@ public class TraceFilterTests {
then(Tracing.current().tracer().currentSpan()).isNull();
then(this.reporter.getSpans()).hasSize(1);
then(this.reporter.getSpans().get(0).parentId()).isEqualTo(PARENT_ID);
then(this.reporter.getSpans().get(0).parentId()).isEqualTo("000000000000000a");
}
@Test
public void shouldAnnotateSpanWithErrorWhenExceptionIsThrown() throws Exception {
this.request = builder().header(SPAN_ID_NAME, PARENT_ID)
.header(TRACE_ID_NAME, SpanUtil.idToHex(20L))
this.request = builder().header("b3", "0000000000000014-000000000000000a")
.buildRequest(new MockServletContext());
this.filterChain = new MockFilterChain() {
@@ -273,8 +259,7 @@ public class TraceFilterTests {
@Test
public void detachesSpanWhenResponseStatusIsNot2xx() throws Exception {
this.request = builder().header(SPAN_ID_NAME, PARENT_ID)
.header(TRACE_ID_NAME, SpanUtil.idToHex(20L))
this.request = builder().header("b3", "14-a")
.buildRequest(new MockServletContext());
this.response.setStatus(404);
@@ -285,8 +270,7 @@ public class TraceFilterTests {
@Test
public void closesSpanWhenResponseStatusIs2xx() throws Exception {
this.request = builder().header(SPAN_ID_NAME, PARENT_ID)
.header(TRACE_ID_NAME, SpanUtil.idToHex(20L))
this.request = builder().header("b3", "0000000000000014-000000000000000a")
.buildRequest(new MockServletContext());
this.response.setStatus(200);
@@ -298,8 +282,7 @@ public class TraceFilterTests {
@Test
public void closesSpanWhenResponseStatusIs3xx() throws Exception {
this.request = builder().header(SPAN_ID_NAME, PARENT_ID)
.header(TRACE_ID_NAME, SpanUtil.idToHex(20L))
this.request = builder().header("b3", "0000000000000014-000000000000000a")
.buildRequest(new MockServletContext());
this.response.setStatus(302);
@@ -311,8 +294,7 @@ public class TraceFilterTests {
@Test
public void returns400IfSpanIsMalformedAndCreatesANewSpan() throws Exception {
this.request = builder().header(SPAN_ID_NAME, "asd")
.header(TRACE_ID_NAME, SpanUtil.idToHex(20L))
this.request = builder().header("b3", "asd")
.buildRequest(new MockServletContext());
this.filter.doFilter(this.request, this.response, this.filterChain);
@@ -324,9 +306,7 @@ public class TraceFilterTests {
@Test
public void returns200IfSpanParentIsMalformedAndCreatesANewSpan() throws Exception {
this.request = builder().header(SPAN_ID_NAME, PARENT_ID)
.header(PARENT_SPAN_ID_NAME, "-")
.header(TRACE_ID_NAME, SpanUtil.idToHex(20L))
this.request = builder().header("b3", "asd")
.buildRequest(new MockServletContext());
this.filter.doFilter(this.request, this.response, this.filterChain);
@@ -337,10 +317,8 @@ public class TraceFilterTests {
}
@Test
public void samplesASpanRegardlessOfTheSamplerWhenXB3FlagsIsPresentAndSetTo1()
throws Exception {
this.request = builder().header(SPAN_FLAGS, 1)
.buildRequest(new MockServletContext());
public void samplesASpanRegardlessOfTheSamplerWhenDebugIsPresent() throws Exception {
this.request = builder().header("b3", "d").buildRequest(new MockServletContext());
neverSampleFilter().doFilter(this.request, this.response, this.filterChain);
@@ -348,38 +326,10 @@ public class TraceFilterTests {
then(this.reporter.getSpans()).isNotEmpty();
}
@Test
public void doesNotOverrideTheSampledFlagWhenXB3FlagIsSetToOtherValueThan1()
throws Exception {
this.request = builder().header(SPAN_FLAGS, 0)
.buildRequest(new MockServletContext());
this.filter.doFilter(this.request, this.response, this.filterChain);
then(Tracing.current().tracer().currentSpan()).isNull();
then(this.reporter.getSpans()).isNotEmpty();
}
@SuppressWarnings("Duplicates")
@Test
public void samplesWhenDebugFlagIsSetTo1AndOnlySpanIdIsSet() throws Exception {
this.request = builder().header(SPAN_FLAGS, 1)
.header(SPAN_ID_NAME, SpanUtil.idToHex(10L))
.buildRequest(new MockServletContext());
neverSampleFilter().doFilter(this.request, this.response, this.filterChain);
then(Tracing.current().tracer().currentSpan()).isNull();
// It is ok to go without a trace ID, if sampling or debug is set
then(this.reporter.getSpans()).hasSize(1).extracting("id")
.isNotEqualTo(SpanUtil.idToHex(10L));
}
@SuppressWarnings("Duplicates")
@Test
public void usesSamplingMechanismWhenIncomingTraceIsMalformed() throws Exception {
this.request = builder().header(SPAN_FLAGS, 1)
.header(TRACE_ID_NAME, SpanUtil.idToHex(10L))
this.request = builder().header("b3", "asd")
.buildRequest(new MockServletContext());
neverSampleFilter().doFilter(this.request, this.response, this.filterChain);
@@ -407,8 +357,7 @@ public class TraceFilterTests {
@Test
public void samplesASpanDebugFlagWithInterceptor() throws Exception {
this.request = builder().header(SPAN_FLAGS, 1)
.buildRequest(new MockServletContext());
this.request = builder().header("b3", "d").buildRequest(new MockServletContext());
neverSampleFilter().doFilter(this.request, this.response, this.filterChain);

View File

@@ -93,6 +93,7 @@ public class TraceRestTemplateInterceptorTests {
Map<String, String> headers = this.template.getForEntity("/", Map.class)
.getBody();
// Default inject format for client spans is B3 multi
then(headers.get("X-B3-TraceId")).isNotNull();
then(headers.get("X-B3-SpanId")).isNotNull();
}
@@ -109,6 +110,7 @@ public class TraceRestTemplateInterceptorTests {
span.finish();
}
// Default inject format for client spans is B3 multi
then(headers.get("X-B3-TraceId"))
.isEqualTo(SpanUtil.idToHex(span.context().traceId()));
then(headers.get("X-B3-SpanId"))
@@ -205,7 +207,8 @@ public class TraceRestTemplateInterceptorTests {
@RequestMapping("/")
public Map<String, String> home(@RequestHeader HttpHeaders headers) {
this.span = TraceRestTemplateInterceptorTests.this.tracer.currentSpan();
Map<String, String> map = new HashMap<String, String>();
Map<String, String> map = new HashMap<>();
// Default inject format for client spans is B3 multi
addHeaders(map, headers, "X-B3-SpanId", "X-B3-TraceId", "X-B3-ParentSpanId");
return map;
}

View File

@@ -32,6 +32,7 @@ import org.springframework.http.HttpHeaders;
import org.springframework.mock.http.server.reactive.MockServerHttpRequest;
import org.springframework.mock.web.server.MockServerWebExchange;
// This test uses B3 multi format as it is the default for client propagation
public class TraceRequestHttpHeadersFilterTests {
StrictCurrentTraceContext currentTraceContext = StrictCurrentTraceContext.create();

View File

@@ -51,8 +51,7 @@ public class TraceResponseHttpHeadersFilterTests {
HttpHeadersFilter filter = TraceResponseHttpHeadersFilter
.create(this.httpTracing);
HttpHeaders httpHeaders = new HttpHeaders();
httpHeaders.set("X-B3-TraceId", "52f112af7472aff0");
httpHeaders.set("X-B3-SpanId", "53e6ab6fc5dfee58");
httpHeaders.set("b3", "52f112af7472aff0-53e6ab6fc5dfee58");
MockServerHttpRequest request = MockServerHttpRequest.post("foo/bar")
.headers(httpHeaders).build();
MockServerWebExchange exchange = MockServerWebExchange.builder(request).build();
@@ -67,8 +66,7 @@ public class TraceResponseHttpHeadersFilterTests {
HttpHeadersFilter filter = TraceResponseHttpHeadersFilter
.create(this.httpTracing);
HttpHeaders httpHeaders = new HttpHeaders();
httpHeaders.set("X-B3-TraceId", "52f112af7472aff0");
httpHeaders.set("X-B3-SpanId", "53e6ab6fc5dfee58");
httpHeaders.set("b3", "52f112af7472aff0-53e6ab6fc5dfee58");
MockServerHttpRequest request = MockServerHttpRequest.post("foo/bar")
.headers(httpHeaders).build();
MockServerWebExchange exchange = MockServerWebExchange.builder(request).build();

View File

@@ -32,6 +32,9 @@ import javax.servlet.http.HttpServletRequest;
import brave.Span;
import brave.Tracer;
import brave.Tracing;
import brave.baggage.BaggagePropagation;
import brave.propagation.B3Propagation;
import brave.propagation.B3SingleFormat;
import brave.propagation.SamplingFlags;
import brave.propagation.TraceContextOrSamplingFlags;
import brave.sampler.Sampler;
@@ -90,6 +93,8 @@ import org.springframework.web.client.RestTemplate;
import org.springframework.web.reactive.function.client.UnknownHttpStatusCodeException;
import org.springframework.web.reactive.function.client.WebClient;
import static brave.Span.Kind.CLIENT;
import static brave.propagation.B3Propagation.Format.SINGLE_NO_PARENT;
import static org.assertj.core.api.Assertions.fail;
import static org.assertj.core.api.BDDAssertions.then;
@@ -100,11 +105,6 @@ import static org.assertj.core.api.BDDAssertions.then;
@DirtiesContext
public class WebClientTests {
static final String TRACE_ID_NAME = "X-B3-TraceId";
static final String SPAN_ID_NAME = "X-B3-SpanId";
static final String SAMPLED_NAME = "X-B3-Sampled";
static final String PARENT_ID_NAME = "X-B3-ParentSpanId";
private static final Log log = LogFactory.getLog(WebClientTests.class);
@Autowired
@@ -163,8 +163,7 @@ public class WebClientTests {
ResponseEntity<String> response = provider.get(this);
Awaitility.await().atMost(2, TimeUnit.SECONDS).untilAsserted(() -> {
then(getHeader(response, TRACE_ID_NAME)).isNull();
then(getHeader(response, SPAN_ID_NAME)).isNull();
then(getHeader(response, "b3")).isNull();
List<zipkin2.Span> spans = this.reporter.getSpans();
then(spans).isNotEmpty();
Optional<zipkin2.Span> noTraceSpan = new ArrayList<>(spans).stream()
@@ -220,8 +219,7 @@ public class WebClientTests {
try (Tracer.SpanInScope ws = this.tracer.withSpanInScope(span)) {
ResponseEntity<Map<String, String>> response = provider.get(this);
then(response.getBody().get(TRACE_ID_NAME.toLowerCase())).isNotNull();
then(response.getBody().get(SAMPLED_NAME.toLowerCase())).isEqualTo("0");
then(response.getBody().get("b3")).isNotNull().endsWith("-0"); // not sampled
}
finally {
span.finish();
@@ -250,8 +248,7 @@ public class WebClientTests {
// https://github.com/spring-cloud/spring-cloud-sleuth/issues/327
// we don't want to respond with any tracing data
then(getHeader(response, SAMPLED_NAME)).isNull();
then(getHeader(response, TRACE_ID_NAME)).isNull();
then(getHeader(response, "b3")).isNull();
}
finally {
span.finish();
@@ -480,7 +477,7 @@ public class WebClientTests {
AtomicReference<String> traceId = new AtomicReference<>();
try (Tracer.SpanInScope ws = this.tracer.withSpanInScope(span)) {
this.webClientBuilder.filter((request, exchange) -> {
traceId.set(request.headers().getFirst("X-B3-SpanId"));
traceId.set(request.headers().getFirst("b3"));
return exchange.exchange(request);
}).build().get().uri("http://localhost:" + this.port + "/traceid").retrieve()
@@ -531,6 +528,13 @@ public class WebClientTests {
configuration = SimpleLoadBalancerClientConfiguration.class)
public static class TestConfiguration {
@Bean
BaggagePropagation.FactoryBuilder baggagePropagationFactoryBuilder() {
// Use b3 single format as it is less verbose
return BaggagePropagation.newFactoryBuilder(B3Propagation.newFactoryBuilder()
.injectFormat(CLIENT, SINGLE_NO_PARENT).build());
}
@Bean
FooController fooController() {
return new FooController();
@@ -625,26 +629,21 @@ public class WebClientTests {
@RestController
public static class FooController {
@Autowired
Tracer tracer;
Span span;
@RequestMapping(value = "/notrace", method = RequestMethod.GET)
public String notrace(
@RequestHeader(name = TRACE_ID_NAME, required = false) String traceId) {
then(traceId).isNotNull();
@RequestHeader(name = "b3", required = false) String b3Single) {
then(b3Single).isNotNull();
return "OK";
}
@RequestMapping(value = "/traceid", method = RequestMethod.GET)
public String traceId(@RequestHeader(TRACE_ID_NAME) String traceId,
@RequestHeader(SPAN_ID_NAME) String spanId,
@RequestHeader(PARENT_ID_NAME) String parentId) {
then(traceId).isNotEmpty();
then(parentId).isNotEmpty();
then(spanId).isNotEmpty();
return traceId;
public String traceId(@RequestHeader("b3") String b3Single) {
TraceContextOrSamplingFlags traceContext = B3SingleFormat
.parseB3SingleFormat(b3Single);
then(traceContext.context()).isNotNull();
return b3Single;
}
@RequestMapping("/")
@@ -657,12 +656,10 @@ public class WebClientTests {
}
@RequestMapping("/noresponse")
public void noResponse(@RequestHeader(TRACE_ID_NAME) String traceId,
@RequestHeader(SPAN_ID_NAME) String spanId,
@RequestHeader(PARENT_ID_NAME) String parentId) {
then(traceId).isNotEmpty();
then(parentId).isNotEmpty();
then(spanId).isNotEmpty();
public void noResponse(@RequestHeader("b3") String b3Single) {
TraceContextOrSamplingFlags traceContext = B3SingleFormat
.parseB3SingleFormat(b3Single);
then(traceContext.context()).isNotNull();
}
public Span getSpan() {

View File

@@ -30,6 +30,7 @@ import org.springframework.http.ResponseEntity;
import org.springframework.web.client.RestTemplate;
import static org.assertj.core.api.BDDAssertions.then;
import static tools.SpanUtil.idToHex;
/**
* Runnable that will send a request via the provide rest template to the given url. It
@@ -39,9 +40,6 @@ import static org.assertj.core.api.BDDAssertions.then;
*/
public class RequestSendingRunnable implements Runnable {
static final String TRACE_ID_NAME = "X-B3-TraceId";
static final String SPAN_ID_NAME = "X-B3-SpanId";
private static final Log log = LogFactory.getLog(RequestSendingRunnable.class);
private final RestTemplate restTemplate;
@@ -75,8 +73,7 @@ public class RequestSendingRunnable implements Runnable {
private RequestEntity<Void> requestWithTraceId() {
HttpHeaders headers = new HttpHeaders();
headers.add(TRACE_ID_NAME, SpanUtil.idToHex(this.traceId));
headers.add(SPAN_ID_NAME, SpanUtil.idToHex(this.spanId));
headers.add("b3", idToHex(this.traceId) + "-" + idToHex(this.spanId));
URI uri = URI.create(this.url);
RequestEntity<Void> requestEntity = new RequestEntity<>(headers, HttpMethod.GET,
uri);

View File

@@ -100,10 +100,10 @@ public class ITTracingChannelInterceptorTests implements MessageHandler {
// formerly known as TraceChannelInterceptorTest.executableSpanCreation
@Test
public void propagatesNoopSpan() {
this.directChannel.send(
MessageBuilder.withPayload("hi").setHeader("X-B3-Sampled", "0").build());
this.directChannel
.send(MessageBuilder.withPayload("hi").setHeader("b3", "0").build());
assertThat(this.message.getHeaders()).containsEntry("X-B3-Sampled", "0");
assertThat(this.message.getHeaders()).containsEntry("b3", "0");
assertThat(this.currentSpan.isNoop()).isTrue();
}

View File

@@ -19,6 +19,8 @@ package org.springframework.cloud.sleuth.instrument.messaging;
import brave.Span;
import brave.Tracer;
import brave.Tracing;
import brave.propagation.B3SingleFormat;
import brave.propagation.TraceContext;
import brave.sampler.Sampler;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.Test;
@@ -80,19 +82,12 @@ public class TraceContextPropagationChannelInterceptorTests {
Message<?> message = this.channel.receive(0);
assertThat(message).as("message was null").isNotNull();
String spanId = message.getHeaders().get(TraceMessageHeaders.SPAN_ID_NAME,
String.class);
assertThat(spanId).as("spanId was equal to parent's id")
String b3 = message.getHeaders().get("b3", String.class);
// Trace and Span IDs are implicitly checked
TraceContext extracted = B3SingleFormat.parseB3SingleFormat(b3).context();
assertThat(extracted.spanIdString()).as("spanId was equal to parent's id")
.isNotEqualTo(expectedSpanId);
String traceId = message.getHeaders().get(TraceMessageHeaders.TRACE_ID_NAME,
String.class);
assertThat(traceId).as("traceId was null").isNotNull();
String parentId = message.getHeaders().get(TraceMessageHeaders.PARENT_ID_NAME,
String.class);
assertThat(parentId).as("parentId was not equal to parent's id")
.isEqualTo(this.reporter.getSpans().get(0).id());
}
@Configuration

View File

@@ -19,6 +19,8 @@ package org.springframework.cloud.sleuth.instrument.messaging;
import brave.Span;
import brave.Tracer;
import brave.Tracing;
import brave.propagation.B3SingleFormat;
import brave.propagation.TraceContext;
import brave.sampler.Sampler;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.Test;
@@ -83,21 +85,12 @@ public class TraceStreamChannelInterceptorTests {
Message<?> message = this.channel.receive(0);
assertThat(message).as("message was null").isNotNull();
String spanId = message.getHeaders().get(TraceMessageHeaders.SPAN_ID_NAME,
String.class);
assertThat(spanId).as("spanId was equal to parent's id")
String b3 = message.getHeaders().get("b3", String.class);
// Trace and Span IDs are implicitly checked
TraceContext extracted = B3SingleFormat.parseB3SingleFormat(b3).context();
assertThat(extracted.spanIdString()).as("spanId was equal to parent's id")
.isNotEqualTo(expectedSpanId);
String traceId = message.getHeaders().get(TraceMessageHeaders.TRACE_ID_NAME,
String.class);
assertThat(traceId).as("traceId was null").isNotNull();
String parentId = message.getHeaders().get(TraceMessageHeaders.PARENT_ID_NAME,
String.class);
// [0] - producer
// [1] - http:testsendmessage
assertThat(parentId).as("parentId was not equal to parent's id")
.isEqualTo(this.reporter.getSpans().get(1).id());
}
@Configuration

View File

@@ -28,14 +28,15 @@ import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletResponse;
import brave.Span;
import brave.baggage.BaggagePropagation;
import brave.http.HttpTracing;
import brave.propagation.B3Propagation;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.web.servlet.context.ServletWebServerInitializedEvent;
import org.springframework.cloud.sleuth.util.SpanUtil;
import org.springframework.context.ApplicationListener;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@@ -49,6 +50,9 @@ import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;
import org.springframework.web.filter.GenericFilterBean;
import static brave.Span.Kind.CLIENT;
import static brave.propagation.B3Propagation.Format.SINGLE_NO_PARENT;
import static brave.propagation.B3SingleFormat.writeB3SingleFormat;
import static org.assertj.core.api.BDDAssertions.then;
import static org.springframework.boot.test.context.SpringBootTest.WebEnvironment.RANDOM_PORT;
@@ -57,9 +61,6 @@ import static org.springframework.boot.test.context.SpringBootTest.WebEnvironmen
@DirtiesContext
public class TraceCustomFilterResponseInjectorTests {
static final String TRACE_ID_NAME = "X-B3-TraceId";
static final String SPAN_ID_NAME = "X-B3-SpanId";
@Autowired
RestTemplate restTemplate;
@@ -80,7 +81,7 @@ public class TraceCustomFilterResponseInjectorTests {
ResponseEntity<Map> responseEntity = this.restTemplate.exchange(requestEntity,
Map.class);
then(responseEntity.getHeaders()).containsKeys(TRACE_ID_NAME, SPAN_ID_NAME)
then(responseEntity.getHeaders()).containsKey("b3")
.as("Trace headers must be present in response headers");
}
@@ -90,6 +91,13 @@ public class TraceCustomFilterResponseInjectorTests {
int port;
@Bean
BaggagePropagation.FactoryBuilder baggagePropagationFactoryBuilder() {
// Use b3 single format as it is less verbose
return BaggagePropagation.newFactoryBuilder(B3Propagation.newFactoryBuilder()
.injectFormat(CLIENT, SINGLE_NO_PARENT).build());
}
// tag::configuration[]
@Bean
HttpResponseInjectingTraceFilter responseInjectingTraceFilter(
@@ -129,9 +137,7 @@ public class TraceCustomFilterResponseInjectorTests {
FilterChain filterChain) throws IOException, ServletException {
HttpServletResponse response = (HttpServletResponse) servletResponse;
Span currentSpan = this.httpTracing.tracing().tracer().currentSpan();
response.addHeader("X-B3-TraceId", currentSpan.context().traceIdString());
response.addHeader("X-B3-SpanId",
SpanUtil.idToHex(currentSpan.context().spanId()));
response.addHeader("b3", writeB3SingleFormat(currentSpan.context()));
filterChain.doFilter(request, response);
}

View File

@@ -69,12 +69,6 @@ import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.
@SpringBootTest(classes = TraceFilterIntegrationTests.Config.class)
public class TraceFilterIntegrationTests extends AbstractMvcIntegrationTest {
static final String TRACE_ID_NAME = "X-B3-TraceId";
static final String SPAN_ID_NAME = "X-B3-SpanId";
static final String SAMPLED_NAME = "X-B3-Sampled";
private static Log logger = LogFactory.getLog(TraceFilterIntegrationTests.class);
private static Span span;
@Autowired
@@ -244,72 +238,69 @@ public class TraceFilterIntegrationTests extends AbstractMvcIntegrationTest {
}
private MvcResult whenSentPingWithTraceId(Long passedTraceId) throws Exception {
return sendPingWithTraceId(TRACE_ID_NAME, passedTraceId);
return sendPingWithTraceId(passedTraceId);
}
private MvcResult whenSentInfoWithTraceId(Long passedTraceId) throws Exception {
return sendRequestWithTraceId("/additionalContextPath/info", TRACE_ID_NAME,
passedTraceId);
return sendRequestWithTraceId("/additionalContextPath/info", passedTraceId);
}
private MvcResult whenSentFutureWithTraceId(Long passedTraceId) throws Exception {
return sendRequestWithTraceId("/future", TRACE_ID_NAME, passedTraceId);
return sendRequestWithTraceId("/future", passedTraceId);
}
private MvcResult whenSentDeferredWithTraceId(Long passedTraceId) throws Exception {
return sendDeferredWithTraceId(TRACE_ID_NAME, passedTraceId);
return sendDeferredWithTraceId(passedTraceId);
}
private MvcResult whenSentToNonExistentEndpointWithTraceId(Long passedTraceId)
throws Exception {
return sendRequestWithTraceId("/exception/nonExistent", TRACE_ID_NAME,
passedTraceId, HttpStatus.NOT_FOUND);
return sendRequestWithTraceId("/exception/nonExistent", passedTraceId,
HttpStatus.NOT_FOUND);
}
private MvcResult whenSentToExceptionThrowingEndpoint(Long passedTraceId)
throws Exception {
return sendRequestWithTraceId("/throwsException", TRACE_ID_NAME, passedTraceId,
return sendRequestWithTraceId("/throwsException", passedTraceId,
HttpStatus.INTERNAL_SERVER_ERROR);
}
private MvcResult sendPingWithTraceId(String headerName, Long traceId)
throws Exception {
return sendRequestWithTraceId("/ping", headerName, traceId);
private MvcResult sendPingWithTraceId(Long traceId) throws Exception {
return sendRequestWithTraceId("/ping", traceId);
}
private MvcResult sendDeferredWithTraceId(String headerName, Long traceId)
throws Exception {
return sendRequestWithTraceId("/deferred", headerName, traceId);
private MvcResult sendDeferredWithTraceId(Long traceId) throws Exception {
return sendRequestWithTraceId("/deferred", traceId);
}
private MvcResult sendRequestWithTraceId(String path, String headerName, Long traceId)
throws Exception {
private MvcResult sendRequestWithTraceId(String path, Long traceId) throws Exception {
return this.mockMvc
.perform(MockMvcRequestBuilders.get(path).accept(MediaType.TEXT_PLAIN)
.header(headerName, SpanUtil.idToHex(traceId))
.header(SPAN_ID_NAME, SpanUtil.idToHex(new Random().nextLong())))
.header("b3",
SpanUtil.idToHex(traceId) + "-"
+ SpanUtil.idToHex(new Random().nextLong())))
.andReturn();
}
private MvcResult whenSentRequestWithTraceIdAndNoSpanId(Long traceId)
throws Exception {
return this.mockMvc
.perform(MockMvcRequestBuilders.get("/ping").accept(MediaType.TEXT_PLAIN)
.header(TRACE_ID_NAME, SpanUtil.idToHex(traceId)))
return this.mockMvc.perform(MockMvcRequestBuilders.get("/ping")
.accept(MediaType.TEXT_PLAIN).header("b3", SpanUtil.idToHex(traceId)))
.andReturn();
}
private MvcResult sendRequestWithTraceId(String path, String headerName, Long traceId,
HttpStatus status) throws Exception {
private MvcResult sendRequestWithTraceId(String path, Long traceId, HttpStatus status)
throws Exception {
return this.mockMvc
.perform(MockMvcRequestBuilders.get(path).accept(MediaType.TEXT_PLAIN)
.header(headerName, SpanUtil.idToHex(traceId))
.header(SPAN_ID_NAME, SpanUtil.idToHex(new Random().nextLong())))
.header("b3",
SpanUtil.idToHex(traceId) + "-"
+ SpanUtil.idToHex(new Random().nextLong())))
.andExpect(status().is(status.value())).andReturn();
}
private boolean notSampledHeaderIsPresent(MvcResult mvcResult) {
return "0".equals(mvcResult.getResponse().getHeader(SAMPLED_NAME));
return "0".equals(mvcResult.getResponse().getHeader("b3"));
}
@EnableAutoConfiguration

View File

@@ -52,9 +52,6 @@ public class GH1102Tests {
@Autowired
TestRetry testRetry;
@Autowired
ArrayListSpanReporter reporter;
@LocalServerPort
int port;
@@ -73,6 +70,7 @@ public class GH1102Tests {
foo.finish();
}
// Default inject format for client spans is B3 multi
BDDAssertions.then(this.testRetry.getHttpHeaders().get("x-b3-traceid"))
.hasSize(1);
}

View File

@@ -155,8 +155,7 @@ public class TraceWebFluxTests {
private ClientResponse whenNonSampledRequestIsSent(int port) {
Mono<ClientResponse> exchange = WebClient.create().get()
.uri("http://localhost:" + port + "/api/c2/10")
.header("X-B3-SpanId", EXPECTED_TRACE_ID)
.header("X-B3-TraceId", EXPECTED_TRACE_ID).header("X-B3-Sampled", "0")
.header("b3", EXPECTED_TRACE_ID + "-" + EXPECTED_TRACE_ID + "-0")
.exchange();
return exchange.block();
}