Only propgate b3 baggage when b3 picked; fixes gh-1781

This commit is contained in:
Marcin Grzejszczak
2020-11-24 17:24:08 +01:00
parent 65d9a1c484
commit d3e8a16052
9 changed files with 315 additions and 4 deletions

View File

@@ -91,7 +91,7 @@ public class BraveAutoConfiguration {
CurrentTraceContext currentTraceContext, Sampler sampler, SleuthProperties sleuthProperties,
@Nullable List<SpanHandler> spanHandlers, @Nullable List<TracingCustomizer> tracingCustomizers) {
Tracing.Builder builder = Tracing.newBuilder().sampler(sampler)
.localServiceName(StringUtils.isEmpty(serviceName) ? DEFAULT_SERVICE_NAME : serviceName)
.localServiceName(!StringUtils.hasText(serviceName) ? DEFAULT_SERVICE_NAME : serviceName)
.propagationFactory(factory).currentTraceContext(currentTraceContext)
.traceId128Bit(sleuthProperties.isTraceId128()).supportsJoin(sleuthProperties.isSupportsJoin());
if (spanHandlers != null) {

View File

@@ -49,6 +49,7 @@ import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.cloud.sleuth.autoconfig.SleuthBaggageProperties;
import org.springframework.cloud.sleuth.brave.propagation.PropagationFactorySupplier;
import org.springframework.cloud.sleuth.brave.propagation.PropagationType;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Conditional;
import org.springframework.context.annotation.Configuration;
@@ -125,9 +126,10 @@ class BraveBaggageConfiguration {
@Bean
@ConditionalOnMissingBean
Propagation.Factory sleuthPropagation(BaggagePropagation.FactoryBuilder factoryBuilder,
Propagation.Factory sleuthPropagationWithB3Baggage(BaggagePropagation.FactoryBuilder factoryBuilder,
@Qualifier(BAGGAGE_KEYS) List<String> baggageKeys, @Qualifier(LOCAL_KEYS) List<String> localKeys,
@Qualifier(PROPAGATION_KEYS) List<String> propagationKeys, SleuthBaggageProperties sleuthBaggageProperties,
SleuthPropagationProperties sleuthPropagationProperties, PropagationFactorySupplier supplier,
@Nullable List<BaggagePropagationCustomizer> baggagePropagationCustomizers) {
Set<String> localFields = redirectOldPropertyToNew(LOCAL_KEYS, localKeys, "spring.sleuth.baggage.local-fields",
@@ -159,7 +161,13 @@ class BraveBaggageConfiguration {
customizer.customize(factoryBuilder);
}
}
return factoryBuilder.build();
Propagation.Factory delegate = factoryBuilder.build();
Propagation.Factory factoryFromSupplier = supplier.get();
final boolean hasB3 = sleuthPropagationProperties.getType().contains(PropagationType.B3);
if (hasB3) {
return delegate;
}
return new BaggageFactoryWrapper(delegate, factoryFromSupplier);
}
static Set<String> redirectOldPropertyToNew(String oldProperty, List<String> oldValue, String newProperty,
@@ -290,4 +298,65 @@ class BraveBaggageConfiguration {
}
static class BaggageFactoryWrapper extends Propagation.Factory {
private final Propagation.Factory delegate;
private final Propagation.Factory factoryFromSupplier;
BaggageFactoryWrapper(Propagation.Factory delegate, Propagation.Factory factoryFromSupplier) {
this.delegate = delegate;
this.factoryFromSupplier = factoryFromSupplier;
}
@Override
public boolean supportsJoin() {
return delegate.supportsJoin();
}
@Override
public boolean requires128BitTraceId() {
return delegate.requires128BitTraceId();
}
@Override
public Propagation<String> get() {
Propagation<String> propagation = delegate.get();
return delegateWithoutB3Baggage(factoryFromSupplier, propagation);
}
@Override
public TraceContext decorate(TraceContext context) {
return delegate.decorate(context);
}
@Override
public <K> Propagation<K> create(Propagation.KeyFactory<K> keyFactory) {
Propagation<K> propagation = delegate.create(keyFactory);
return delegateWithoutB3Baggage(factoryFromSupplier, propagation);
}
private <K> Propagation<K> delegateWithoutB3Baggage(Propagation.Factory factoryFromSupplier,
Propagation<K> propagation) {
return new Propagation<K>() {
@Override
public List<K> keys() {
return propagation.keys();
}
@Override
public <R> TraceContext.Injector<R> injector(Setter<R, K> setter) {
// We don't want to inject baggage in the Brave way
return factoryFromSupplier.get().injector((Setter<R, String>) setter);
}
@Override
public <R> TraceContext.Extractor<R> extractor(Getter<R, K> getter) {
return propagation.extractor(getter);
}
};
}
};
}

View File

@@ -33,8 +33,13 @@ import org.springframework.cloud.sleuth.BaggageManager;
import org.springframework.cloud.sleuth.autoconfig.SleuthBaggageProperties;
import org.springframework.cloud.sleuth.otel.propagation.BaggageTextMapPropagator;
import org.springframework.cloud.sleuth.otel.propagation.CompositeTextMapPropagator;
import org.springframework.cloud.sleuth.otel.propagation.PropagationType;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Condition;
import org.springframework.context.annotation.ConditionContext;
import org.springframework.context.annotation.Conditional;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.type.AnnotatedTypeMetadata;
/**
* {@link org.springframework.boot.autoconfigure.EnableAutoConfiguration
@@ -74,7 +79,7 @@ class OtelPropagationConfiguration {
}
@Configuration(proxyBeanMethods = false)
@ConditionalOnProperty(name = "spring.sleuth.otel.propagation.sleuth-baggage.enabled", matchIfMissing = true)
@Conditional(B3PresentOrPropertyEnabledCondition.class)
static class BaggagePropagatorConfiguration {
@Bean
@@ -84,4 +89,16 @@ class OtelPropagationConfiguration {
}
static class B3PresentOrPropertyEnabledCondition implements Condition {
@Override
public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
String type = context.getEnvironment().getProperty("spring.sleuth.propagation.type", "").toLowerCase();
boolean sleuthBaggageEnabled = context.getEnvironment()
.getProperty("spring.sleuth.otel.propagation.sleuth-baggage.enabled", Boolean.class, false);
return type.contains(PropagationType.B3.toString().toLowerCase()) || sleuthBaggageEnabled;
}
}
}

View File

@@ -84,6 +84,16 @@
<groupId>org.awaitility</groupId>
<artifactId>awaitility</artifactId>
</dependency>
<dependency>
<groupId>com.squareup.okhttp3</groupId>
<artifactId>mockwebserver</artifactId>
</dependency>
<dependency>
<groupId>com.squareup.okhttp3</groupId>
<artifactId>okhttp</artifactId>
<!-- Kotlin... -->
<version>4.8.0</version>
</dependency>
</dependencies>
</project>

View File

@@ -0,0 +1,55 @@
/*
* Copyright 2013-2020 the original author or 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
*
* https://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 org.springframework.cloud.sleuth.brave.baggage;
import brave.sampler.Sampler;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.cloud.sleuth.brave.BraveTestSpanHandler;
import org.springframework.cloud.sleuth.test.TestSpanHandler;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.test.context.ContextConfiguration;
/**
* @author Taras Danylchuk
*/
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.NONE)
@ContextConfiguration(classes = W3CBaggageTests.Config.class)
public class W3CBaggageTests extends org.springframework.cloud.sleuth.baggage.W3CBaggageTests {
@Configuration(proxyBeanMethods = false)
static class Config {
@Bean
TestSpanHandler testSpanHandlerSupplier(brave.test.TestSpanHandler testSpanHandler) {
return new BraveTestSpanHandler(testSpanHandler);
}
@Bean
Sampler alwaysSampler() {
return Sampler.ALWAYS_SAMPLE;
}
@Bean
brave.test.TestSpanHandler braveTestSpanHandler() {
return new brave.test.TestSpanHandler();
}
}
}

View File

@@ -0,0 +1,99 @@
/*
* Copyright 2013-2020 the original author or 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
*
* https://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 org.springframework.cloud.sleuth.baggage;
import java.io.IOException;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;
import okhttp3.mockwebserver.MockResponse;
import okhttp3.mockwebserver.MockWebServer;
import okhttp3.mockwebserver.RecordedRequest;
import org.assertj.core.api.BDDAssertions;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.cloud.sleuth.BaggageInScope;
import org.springframework.cloud.sleuth.Span;
import org.springframework.cloud.sleuth.Tracer;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.TestPropertySource;
import org.springframework.web.client.RestTemplate;
/**
* @author Taras Danylchuk
*/
@ContextConfiguration(classes = W3CBaggageTests.TestConfig.class)
@TestPropertySource(properties = { "spring.sleuth.baggage.remote-fields[0]=foo", "spring.sleuth.propagation.type=W3C" })
public abstract class W3CBaggageTests {
@Autowired
Tracer tracer;
@Autowired
RestTemplate restTemplate;
@Autowired
MockWebServer mockWebServer;
@Test
@SuppressWarnings("unchecked")
public void shouldProduceOnlyW3cBaggageEntries() throws InterruptedException {
this.mockWebServer.enqueue(new MockResponse().setBody("hello"));
Span span = this.tracer.nextSpan();
try (Tracer.SpanInScope spanInScope = this.tracer.withSpan(span.start())) {
try (BaggageInScope bs = this.tracer.createBaggage("foo").set("bar")) {
// when
this.restTemplate.getForObject(this.mockWebServer.url("/baggage").toString(), String.class);
// then
RecordedRequest request = this.mockWebServer.takeRequest(1, TimeUnit.SECONDS);
Map<String, List<String>> map = request.getHeaders().toMultimap();
BDDAssertions.then(map).doesNotContainKey("foo");
List<String> baggage = map.get("baggage");
BDDAssertions.then(baggage.stream().anyMatch(s -> s.contains("foo=bar"))).isTrue();
}
finally {
span.end();
}
}
}
@EnableAutoConfiguration
@Configuration(proxyBeanMethods = false)
static class TestConfig {
@Bean
RestTemplate restTemplate() {
return new RestTemplate();
}
@Bean
MockWebServer mockWebServer() throws IOException {
MockWebServer mockWebServer = new MockWebServer();
mockWebServer.start();
return mockWebServer;
}
}
}

View File

@@ -90,6 +90,16 @@
<groupId>org.awaitility</groupId>
<artifactId>awaitility</artifactId>
</dependency>
<dependency>
<groupId>com.squareup.okhttp3</groupId>
<artifactId>mockwebserver</artifactId>
</dependency>
<dependency>
<groupId>com.squareup.okhttp3</groupId>
<artifactId>okhttp</artifactId>
<!-- Kotlin... -->
<version>4.8.0</version>
</dependency>
</dependencies>
</project>

View File

@@ -35,6 +35,7 @@ import org.springframework.context.ApplicationListener;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.TestPropertySource;
import static java.util.Arrays.asList;
import static org.assertj.core.api.BDDAssertions.then;
@@ -42,6 +43,7 @@ import static org.springframework.boot.test.context.SpringBootTest.WebEnvironmen
@SpringBootTest(webEnvironment = RANDOM_PORT)
@ContextConfiguration(classes = MultipleHopsIntegrationTests.Config.class)
@TestPropertySource(properties = "spring.sleuth.otel.propagation.sleuth-baggage.enabled=true")
public class MultipleHopsIntegrationTests
extends org.springframework.cloud.sleuth.baggage.multiple.MultipleHopsIntegrationTests {

View File

@@ -0,0 +1,49 @@
/*
* Copyright 2013-2020 the original author or 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
*
* https://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 org.springframework.cloud.sleuth.otel.bridge;
import io.opentelemetry.sdk.trace.samplers.Sampler;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.cloud.sleuth.otel.OtelTestSpanHandler;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.test.context.ContextConfiguration;
/**
* @author Taras Danylchuk
*/
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.NONE)
@ContextConfiguration(classes = W3CBaggageTests.Config.class)
public class W3CBaggageTests extends org.springframework.cloud.sleuth.baggage.W3CBaggageTests {
@Configuration(proxyBeanMethods = false)
static class Config {
@Bean
OtelTestSpanHandler testSpanHandlerSupplier() {
return new OtelTestSpanHandler(new ArrayListSpanProcessor());
}
@Bean
Sampler alwaysSampler() {
return Sampler.alwaysOn();
}
}
}