Stops configuring ExtraFieldPropagation. Starts configuring BaggagePropagation (#1602)

This commit is contained in:
Adrian Cole
2020-04-06 16:38:32 +08:00
committed by GitHub
parent 0b838a796d
commit dcefd7b4db
19 changed files with 353 additions and 298 deletions

View File

@@ -33,7 +33,7 @@
<maven.compiler.target>1.8</maven.compiler.target>
<maven.compiler.source>1.8</maven.compiler.source>
<spring-boot.version>2.3.0.BUILD-SNAPSHOT</spring-boot.version>
<brave.version>5.11.1</brave.version>
<brave.version>5.11.2</brave.version>
<okhttp.version>3.14.6</okhttp.version>
</properties>

View File

@@ -250,7 +250,7 @@
<spring-cloud-stream.version>Horsham.BUILD-SNAPSHOT</spring-cloud-stream.version>
<spring-cloud-netflix.version>3.0.0.BUILD-SNAPSHOT</spring-cloud-netflix.version>
<spring-cloud-openfeign.version>3.0.0.BUILD-SNAPSHOT</spring-cloud-openfeign.version>
<brave.version>5.11.1</brave.version>
<brave.version>5.11.2</brave.version>
<spring-security-boot-autoconfigure.version>2.1.7.RELEASE</spring-security-boot-autoconfigure.version>
<disable.nohttp.checks>false</disable.nohttp.checks>
<okhttp.version>3.14.6</okhttp.version>

View File

@@ -0,0 +1,116 @@
/*
* Copyright 2013-2019 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.autoconfig;
import java.util.LinkedHashSet;
import java.util.Set;
import brave.baggage.BaggageField;
import brave.baggage.BaggageFields;
import brave.baggage.BaggagePropagationConfig;
import brave.baggage.BaggagePropagationConfig.SingleBaggageField;
import brave.baggage.CorrelationScopeConfig;
import brave.baggage.CorrelationScopeConfig.SingleCorrelationField;
import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.env.Environment;
/**
* Wire up property-based {@linkplain BaggagePropagationConfig} and
* {@link CorrelationScopeConfig} so that they appear as if they were defined one-by-one.
* This allows users to contribute configs and also for us to use the list of them above.
*/
@Configuration(proxyBeanMethods = false)
@ConditionalOnProperty(value = "spring.sleuth.enabled", matchIfMissing = true)
public class PropertyBasedBaggageConfiguration implements BeanFactoryPostProcessor {
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) {
Environment env = beanFactory.getBean(Environment.class);
Set<SingleBaggageField> baggageConfigs = parseBaggageConfigsFromProperty(env);
for (SingleBaggageField config : baggageConfigs) {
beanFactory.registerSingleton(config.field().name() + "BaggageField", config);
}
Set<SingleCorrelationField> correlationConfigs = parseCorrelationConfigsFromProperty(
env);
for (SingleCorrelationField config : correlationConfigs) {
beanFactory.registerSingleton(config.name() + "CorrelationField", config);
}
}
static Set<SingleBaggageField> parseBaggageConfigsFromProperty(Environment env) {
Set<SingleBaggageField> baggageConfigs = new LinkedHashSet<>();
for (String key : collectKeysOfType(env, "local")) {
baggageConfigs.add(SingleBaggageField.local(BaggageField.create(key)));
}
for (String key : collectKeysOfType(env, "propagation")) {
baggageConfigs.add(SingleBaggageField.remote(BaggageField.create(key)));
}
for (String key : collectKeysOfType(env, "baggage")) {
baggageConfigs.add(SingleBaggageField.newBuilder(BaggageField.create(key))
.addKeyName("baggage-" + key) // for HTTP
.addKeyName("baggage_" + key) // for messaging
.build());
}
return baggageConfigs;
}
static Set<SingleCorrelationField> parseCorrelationConfigsFromProperty(
Environment env) {
Set<SingleCorrelationField> correlationConfigs = new LinkedHashSet<>();
correlationConfigs.add(SingleCorrelationField.create(BaggageFields.TRACE_ID));
correlationConfigs.add(SingleCorrelationField.create(BaggageFields.PARENT_ID));
correlationConfigs.add(SingleCorrelationField.create(BaggageFields.SPAN_ID));
correlationConfigs.add(SingleCorrelationField.newBuilder(BaggageFields.SAMPLED)
.name("spanExportable").build());
for (String key : collectKeysOfType(env, "log.slf4j.whitelisted-mdc")) {
// For backwards compatibility set all fields dirty, so that any changes made
// by MDC directly are reverted.
correlationConfigs.add(SingleCorrelationField
.newBuilder(BaggageField.create(key)).dirty().build());
}
return correlationConfigs;
}
static Set<String> collectKeysOfType(Environment env, String type) {
String propertyName = "spring.sleuth." + type + "-keys";
Set<String> result = new LinkedHashSet<>();
for (String key : env.getProperty(propertyName, "").split(",")) {
if (key == null) {
continue;
}
key = key.trim();
if (key.isEmpty()) {
continue;
}
result.add(key);
}
return result;
}
}

View File

@@ -19,6 +19,9 @@ package org.springframework.cloud.sleuth.autoconfig;
import java.util.ArrayList;
import java.util.List;
import brave.baggage.BaggageField;
import brave.baggage.BaggagePropagationConfig;
import org.springframework.boot.context.properties.ConfigurationProperties;
/**
@@ -46,8 +49,7 @@ public class SleuthProperties {
* be prefixed with `baggage` before the actual key. This property is set in order to
* be backward compatible with previous Sleuth versions.
*
* @see brave.propagation.ExtraFieldPropagation.FactoryBuilder#addPrefixedFields(String,
* java.util.Collection)
* @see BaggagePropagationConfig.SingleBaggageField.Builder#addKeyName(String)
*/
private List<String> baggageKeys = new ArrayList<>();
@@ -58,7 +60,7 @@ public class SleuthProperties {
* <p>
* Note: {@code fieldName} will be implicitly lower-cased.
*
* @see brave.propagation.ExtraFieldPropagation.FactoryBuilder#addField(String)
* @see BaggagePropagationConfig.SingleBaggageField#remote(BaggageField)
*/
private List<String> propagationKeys = new ArrayList<>();
@@ -66,7 +68,7 @@ public class SleuthProperties {
* Same as {@link #propagationKeys} except that this field is not propagated to remote
* services.
*
* @see brave.propagation.ExtraFieldPropagation.FactoryBuilder#addRedactedField(String)
* @see BaggagePropagationConfig.SingleBaggageField#local(BaggageField)
*/
private List<String> localKeys = new ArrayList<>();

View File

@@ -25,12 +25,14 @@ import brave.ErrorParser;
import brave.Tracer;
import brave.Tracing;
import brave.TracingCustomizer;
import brave.baggage.BaggagePropagation;
import brave.baggage.BaggagePropagationConfig;
import brave.baggage.BaggagePropagationCustomizer;
import brave.handler.FinishedSpanHandler;
import brave.propagation.B3Propagation;
import brave.propagation.CurrentTraceContext;
import brave.propagation.CurrentTraceContext.ScopeDecorator;
import brave.propagation.CurrentTraceContextCustomizer;
import brave.propagation.ExtraFieldCustomizer;
import brave.propagation.ExtraFieldPropagation;
import brave.propagation.Propagation;
import brave.propagation.ThreadLocalCurrentTraceContext;
import brave.sampler.Sampler;
@@ -44,6 +46,7 @@ import zipkin2.reporter.ReporterMetrics;
import zipkin2.reporter.metrics.micrometer.MicrometerReporterMetrics;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.AutoConfigureAfter;
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
@@ -70,6 +73,7 @@ import org.springframework.util.StringUtils;
@Configuration(proxyBeanMethods = false)
@ConditionalOnProperty(value = "spring.sleuth.enabled", matchIfMissing = true)
@EnableConfigurationProperties(SleuthProperties.class)
@AutoConfigureAfter(PropertyBasedBaggageConfiguration.class)
public class TraceAutoConfiguration {
/**
@@ -89,7 +93,7 @@ public class TraceAutoConfiguration {
List<CurrentTraceContext.ScopeDecorator> scopeDecorators = new ArrayList<>();
@Autowired(required = false)
ExtraFieldPropagation.FactoryBuilder extraFieldPropagationFactoryBuilder;
List<BaggagePropagationCustomizer> baggagePropagationCustomizers = new ArrayList<>();
@Autowired(required = false)
List<TracingCustomizer> tracingCustomizers = new ArrayList<>();
@@ -97,9 +101,6 @@ public class TraceAutoConfiguration {
@Autowired(required = false)
List<CurrentTraceContextCustomizer> currentTraceContextCustomizers = new ArrayList<>();
@Autowired(required = false)
List<ExtraFieldCustomizer> extraFieldCustomizers = new ArrayList<>();
@Bean
@ConditionalOnMissingBean
// NOTE: stable bean name as might be used outside sleuth
@@ -143,42 +144,24 @@ public class TraceAutoConfiguration {
return new DefaultSpanNamer();
}
/**
* 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.
*/
@Bean
@ConditionalOnMissingBean
Propagation.Factory sleuthPropagation(SleuthProperties sleuthProperties) {
if (sleuthProperties.getBaggageKeys().isEmpty()
&& sleuthProperties.getPropagationKeys().isEmpty()
&& extraFieldCustomizers.isEmpty()
&& this.extraFieldPropagationFactoryBuilder == null
&& sleuthProperties.getLocalKeys().isEmpty()) {
return B3Propagation.FACTORY;
}
ExtraFieldPropagation.FactoryBuilder factoryBuilder;
if (this.extraFieldPropagationFactoryBuilder != null) {
factoryBuilder = this.extraFieldPropagationFactoryBuilder;
}
else {
factoryBuilder = ExtraFieldPropagation
.newFactoryBuilder(B3Propagation.FACTORY);
}
if (!sleuthProperties.getBaggageKeys().isEmpty()) {
factoryBuilder = factoryBuilder
// for HTTP
.addPrefixedFields("baggage-", sleuthProperties.getBaggageKeys())
// for messaging
.addPrefixedFields("baggage_", sleuthProperties.getBaggageKeys());
}
if (!sleuthProperties.getPropagationKeys().isEmpty()) {
for (String key : sleuthProperties.getPropagationKeys()) {
factoryBuilder = factoryBuilder.addField(key);
}
}
if (!sleuthProperties.getLocalKeys().isEmpty()) {
for (String key : sleuthProperties.getLocalKeys()) {
factoryBuilder = factoryBuilder.addRedactedField(key);
}
}
for (ExtraFieldCustomizer customizer : this.extraFieldCustomizers) {
BaggagePropagation.FactoryBuilder baggagePropagationFactoryBuilder() {
return BaggagePropagation.newFactoryBuilder(B3Propagation.FACTORY);
}
@Bean
@ConditionalOnMissingBean
Propagation.Factory sleuthPropagation(
BaggagePropagation.FactoryBuilder factoryBuilder,
List<BaggagePropagationConfig> baggageConfig) {
baggageConfig.forEach(factoryBuilder::add);
for (BaggagePropagationCustomizer customizer : this.baggagePropagationCustomizers) {
customizer.customize(factoryBuilder);
}
return factoryBuilder.build();
@@ -186,7 +169,7 @@ public class TraceAutoConfiguration {
@Bean
CurrentTraceContext sleuthCurrentTraceContext(CurrentTraceContext.Builder builder) {
for (CurrentTraceContext.ScopeDecorator scopeDecorator : this.scopeDecorators) {
for (ScopeDecorator scopeDecorator : this.scopeDecorators) {
builder.addScopeDecorator(scopeDecorator);
}
for (CurrentTraceContextCustomizer customizer : this.currentTraceContextCustomizers) {

View File

@@ -16,22 +16,28 @@
package org.springframework.cloud.sleuth.log;
import brave.propagation.CurrentTraceContext;
import java.util.List;
import brave.baggage.CorrelationScopeConfig;
import brave.baggage.CorrelationScopeDecorator;
import brave.context.slf4j.MDCScopeDecorator;
import brave.propagation.CurrentTraceContext.ScopeDecorator;
import org.slf4j.MDC;
import org.springframework.boot.autoconfigure.AutoConfigureAfter;
import org.springframework.boot.autoconfigure.AutoConfigureBefore;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.cloud.sleuth.autoconfig.SleuthProperties;
import org.springframework.cloud.sleuth.autoconfig.PropertyBasedBaggageConfiguration;
import org.springframework.cloud.sleuth.autoconfig.TraceAutoConfiguration;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/**
* {@link org.springframework.boot.autoconfigure.EnableAutoConfiguration
* Auto-configuration} adds a {@link Slf4jScopeDecorator} that prints tracing information
* in the logs.
* Auto-configuration} adds a {@link CorrelationScopeDecorator} that prints tracing
* information in the logs.
* <p>
*
* @author Spencer Gibb
@@ -41,6 +47,7 @@ import org.springframework.context.annotation.Configuration;
@Configuration(proxyBeanMethods = false)
@ConditionalOnProperty(value = "spring.sleuth.enabled", matchIfMissing = true)
@AutoConfigureBefore(TraceAutoConfiguration.class)
@AutoConfigureAfter(PropertyBasedBaggageConfiguration.class)
public class SleuthLogAutoConfiguration {
/**
@@ -54,10 +61,12 @@ public class SleuthLogAutoConfiguration {
@Bean
@ConditionalOnProperty(value = "spring.sleuth.log.slf4j.enabled",
matchIfMissing = true)
static CurrentTraceContext.ScopeDecorator slf4jSpanDecorator(
SleuthProperties sleuthProperties,
SleuthSlf4jProperties sleuthSlf4jProperties) {
return new Slf4jScopeDecorator(sleuthProperties, sleuthSlf4jProperties);
ScopeDecorator correlationScopeDecorator(
List<CorrelationScopeConfig> correlationScopeConfigs) {
CorrelationScopeDecorator.Builder builder = MDCScopeDecorator.newBuilder();
builder.clear();
correlationScopeConfigs.forEach(builder::add);
return builder.build();
}
}

View File

@@ -19,6 +19,8 @@ package org.springframework.cloud.sleuth.log;
import java.util.ArrayList;
import java.util.List;
import brave.context.slf4j.MDCScopeDecorator;
import org.springframework.boot.context.properties.ConfigurationProperties;
/**
@@ -31,7 +33,7 @@ import org.springframework.boot.context.properties.ConfigurationProperties;
public class SleuthSlf4jProperties {
/**
* Enable a {@link Slf4jScopeDecorator} that prints tracing information in the logs.
* Enable a {@link MDCScopeDecorator} that prints tracing information in the logs.
*/
private boolean enabled = true;

View File

@@ -1,98 +0,0 @@
/*
* Copyright 2013-2019 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.log;
import java.util.LinkedHashSet;
import java.util.Set;
import java.util.TreeSet;
import brave.baggage.BaggageField;
import brave.baggage.BaggageFields;
import brave.baggage.CorrelationField;
import brave.baggage.CorrelationScopeDecorator;
import brave.context.slf4j.MDCScopeDecorator;
import brave.propagation.CurrentTraceContext.Scope;
import brave.propagation.CurrentTraceContext.ScopeDecorator;
import brave.propagation.TraceContext;
import org.slf4j.MDC;
import org.springframework.cloud.sleuth.autoconfig.SleuthProperties;
/**
* Adds {@linkplain MDC} properties "traceId", "parentId", "spanId" and "spanExportable"
* when a {@link brave.Tracer#currentSpan() span is current}. These can be used in log
* correlation. Supports backward compatibility of MDC entries by adding legacy "X-B3"
* entries to MDC context "X-B3-TraceId", "X-B3-ParentSpanId", "X-B3-SpanId" and
* "X-B3-Sampled"
*
* @author Marcin Grzejszczak
* @since 2.1.0
*/
final class Slf4jScopeDecorator implements ScopeDecorator {
// Backward compatibility for all logging patterns
private static final ScopeDecorator LEGACY_IDS = MDCScopeDecorator.newBuilder()
.clear()
.addField(CorrelationField.newBuilder(BaggageFields.TRACE_ID)
.name("X-B3-TraceId").build())
.addField(CorrelationField.newBuilder(BaggageFields.PARENT_ID)
.name("X-B3-ParentSpanId").build())
.addField(CorrelationField.newBuilder(BaggageFields.SPAN_ID)
.name("X-B3-SpanId").build())
.addField(CorrelationField.newBuilder(BaggageFields.SAMPLED)
.name("X-Span-Export").build())
.build();
private final ScopeDecorator delegate;
Slf4jScopeDecorator(SleuthProperties sleuthProperties,
SleuthSlf4jProperties sleuthSlf4jProperties) {
CorrelationScopeDecorator.Builder builder = MDCScopeDecorator.newBuilder().clear()
.addField(CorrelationField.create(BaggageFields.TRACE_ID))
.addField(CorrelationField.create(BaggageFields.PARENT_ID))
.addField(CorrelationField.create(BaggageFields.SPAN_ID))
.addField(CorrelationField.newBuilder(BaggageFields.SAMPLED)
.name("spanExportable").build());
Set<String> whitelist = new TreeSet<>(String.CASE_INSENSITIVE_ORDER);
whitelist.addAll(sleuthSlf4jProperties.getWhitelistedMdcKeys());
// Note: we are adding all the keys as-is because correlation context doesn't
// prefix, only ExtraFieldPropagation does
Set<String> retained = new LinkedHashSet<>();
retained.addAll(sleuthProperties.getBaggageKeys());
retained.addAll(sleuthProperties.getLocalKeys());
retained.addAll(sleuthProperties.getPropagationKeys());
retained.retainAll(whitelist);
// For backwards compatibility set all fields dirty, so that any changes made by
// MDC directly are reverted.
for (String name : retained) {
builder.addField(CorrelationField.newBuilder(BaggageField.create(name))
.dirty().build());
}
this.delegate = builder.build();
}
@Override
public Scope decorateScope(TraceContext context, Scope scope) {
return LEGACY_IDS.decorateScope(context, delegate.decorateScope(context, scope));
}
}

View File

@@ -21,7 +21,6 @@ import brave.handler.FinishedSpanHandler;
import org.springframework.boot.autoconfigure.AutoConfigureBefore;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.cloud.sleuth.autoconfig.SleuthProperties;
import org.springframework.cloud.sleuth.autoconfig.TraceAutoConfiguration;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@@ -42,11 +41,9 @@ public class SleuthTagPropagationAutoConfiguration {
protected static class TagPropagationConfiguration {
@Bean
static FinishedSpanHandler sleuthFinishedSpanHandler(
SleuthProperties sleuthProperties,
FinishedSpanHandler sleuthFinishedSpanHandler(
SleuthTagPropagationProperties tagPropagationProperties) {
return new TagPropagationFinishedSpanHandler(sleuthProperties,
tagPropagationProperties);
return new TagPropagationFinishedSpanHandler(tagPropagationProperties);
}
}

View File

@@ -16,51 +16,38 @@
package org.springframework.cloud.sleuth.propagation;
import java.util.AbstractMap;
import java.util.Arrays;
import java.util.List;
import java.util.LinkedHashSet;
import java.util.Set;
import java.util.TreeSet;
import brave.Tags;
import brave.baggage.BaggageField;
import brave.handler.FinishedSpanHandler;
import brave.handler.MutableSpan;
import brave.propagation.ExtraFieldPropagation;
import brave.propagation.TraceContext;
import org.springframework.cloud.sleuth.autoconfig.SleuthProperties;
import static java.util.Objects.nonNull;
/**
* Finish span handler which adds extra propagation fields to span tags, so spans could be
* looked up by its baggage.
* Finish span handler which adds baggage to span tags, so spans could be looked up by a
* baggage name.
*
* @author Taras Danylchuk
* @since 2.1.0
*/
public class TagPropagationFinishedSpanHandler extends FinishedSpanHandler {
private final SleuthProperties sleuthProperties;
private final Set<BaggageField> baggageToTag = new LinkedHashSet<>();
private final SleuthTagPropagationProperties tagPropagationProperties;
public TagPropagationFinishedSpanHandler(SleuthProperties sleuthProperties,
public TagPropagationFinishedSpanHandler(
SleuthTagPropagationProperties tagPropagationProperties) {
this.sleuthProperties = sleuthProperties;
this.tagPropagationProperties = tagPropagationProperties;
Set<String> keys = new TreeSet<>(String.CASE_INSENSITIVE_ORDER);
keys.addAll(tagPropagationProperties.getWhitelistedKeys());
keys.forEach(key -> baggageToTag.add(BaggageField.create(key)));
}
@Override
public boolean handle(TraceContext context, MutableSpan span) {
for (List<String> strings : Arrays.asList(this.sleuthProperties.getBaggageKeys(),
this.sleuthProperties.getPropagationKeys())) {
for (String key : strings) {
if (this.tagPropagationProperties.getWhitelistedKeys().contains(key)) {
AbstractMap.SimpleEntry<String, String> entry = new AbstractMap.SimpleEntry<>(
key, ExtraFieldPropagation.get(context, key));
if (nonNull(entry.getValue())) {
span.tag(entry.getKey(), entry.getValue());
}
}
}
for (BaggageField field : baggageToTag) {
Tags.BAGGAGE_FIELD.tag(field, context, span);
}
return true;
}

View File

@@ -2,6 +2,7 @@
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
org.springframework.cloud.sleuth.annotation.SleuthAnnotationAutoConfiguration,\
org.springframework.cloud.sleuth.sampler.SamplerAutoConfiguration,\
org.springframework.cloud.sleuth.autoconfig.PropertyBasedBaggageConfiguration,\
org.springframework.cloud.sleuth.autoconfig.TraceAutoConfiguration,\
org.springframework.cloud.sleuth.log.SleuthLogAutoConfiguration,\
org.springframework.cloud.sleuth.propagation.SleuthTagPropagationAutoConfiguration,\

View File

@@ -17,10 +17,10 @@
package org.springframework.cloud.sleuth.autoconfig;
import brave.TracingCustomizer;
import brave.baggage.BaggagePropagationCustomizer;
import brave.http.HttpTracingCustomizer;
import brave.messaging.MessagingTracingCustomizer;
import brave.propagation.CurrentTraceContextCustomizer;
import brave.propagation.ExtraFieldCustomizer;
import brave.propagation.Propagation;
import brave.rpc.RpcTracingCustomizer;
import brave.sampler.Sampler;
@@ -61,7 +61,7 @@ public class TraceAutoConfigurationCustomizersTests {
}
@Test
public void should_apply_extra_field_customizer_when_no_extra_properties_are_defined() {
public void should_apply_baggage_customizer_when_no_baggage_properties_are_defined() {
this.contextRunner.run((context) -> {
Customizers bean = context.getBean(Customizers.class);
@@ -76,7 +76,7 @@ public class TraceAutoConfigurationCustomizersTests {
private void shouldApplyCustomizations(Customizers bean) {
then(bean.tracingCustomizerApplied).isTrue();
then(bean.contextCustomizerApplied).isTrue();
then(bean.extraFieldCustomizerApplied).isTrue();
then(bean.baggagePropagationCustomizerApplied).isTrue();
then(bean.httpCustomizerApplied).isTrue();
then(bean.rpcCustomizerApplied).isTrue();
}
@@ -99,7 +99,7 @@ public class TraceAutoConfigurationCustomizersTests {
boolean contextCustomizerApplied;
boolean extraFieldCustomizerApplied;
boolean baggagePropagationCustomizerApplied;
boolean httpCustomizerApplied;
@@ -118,8 +118,8 @@ public class TraceAutoConfigurationCustomizersTests {
}
@Bean
ExtraFieldCustomizer sleuthExtraFieldCustomizer() {
return builder -> extraFieldCustomizerApplied = true;
BaggagePropagationCustomizer sleuthBaggagePropagationCustomizer() {
return builder -> baggagePropagationCustomizerApplied = true;
}
@Bean

View File

@@ -16,9 +16,9 @@
package org.springframework.cloud.sleuth.autoconfig;
import brave.baggage.BaggagePropagation;
import brave.propagation.B3Propagation;
import brave.propagation.B3SinglePropagation;
import brave.propagation.ExtraFieldPropagation;
import brave.propagation.Propagation;
import org.assertj.core.api.BDDAssertions;
import org.junit.jupiter.api.Test;
@@ -34,7 +34,9 @@ import org.springframework.context.support.GenericApplicationContext;
public class TraceAutoConfigurationPropagationCustomizationTests {
private final ApplicationContextRunner contextRunner = new ApplicationContextRunner()
.withConfiguration(AutoConfigurations.of(TraceAutoConfiguration.class));
.withConfiguration(
AutoConfigurations.of(PropertyBasedBaggageConfiguration.class,
TraceAutoConfiguration.class));
@Test
public void stillCreatesDefault() {
@@ -49,7 +51,7 @@ public class TraceAutoConfigurationPropagationCustomizationTests {
this.contextRunner.withPropertyValues("spring.sleuth.baggage-keys=my-baggage")
.run((context) -> {
BDDAssertions.then(context.getBean(Propagation.Factory.class))
.hasFieldOrPropertyWithValue("delegate.delegate",
.hasFieldOrPropertyWithValue("delegate",
B3Propagation.FACTORY);
});
}
@@ -79,19 +81,17 @@ public class TraceAutoConfigurationPropagationCustomizationTests {
public void allowsCustomizationOfBuilder() {
this.contextRunner.withPropertyValues("spring.sleuth.baggage-keys=my-baggage")
.withUserConfiguration(CustomPropagationFactoryBuilderConfig.class)
.run((context) -> {
BDDAssertions.then(context.getBean(Propagation.Factory.class))
.hasFieldOrPropertyWithValue("delegate.delegate",
B3SinglePropagation.FACTORY);
});
.run((context) -> BDDAssertions
.then(context.getBean(Propagation.Factory.class))
.extracting("delegate").isSameAs(B3SinglePropagation.FACTORY));
}
@Configuration
static class CustomPropagationFactoryBuilderConfig {
@Bean
public ExtraFieldPropagation.FactoryBuilder factoryBuilder() {
return ExtraFieldPropagation.newFactoryBuilder(B3SinglePropagation.FACTORY);
public BaggagePropagation.FactoryBuilder b3Single() {
return BaggagePropagation.newFactoryBuilder(B3SinglePropagation.FACTORY);
}
}

View File

@@ -16,9 +16,16 @@
package org.springframework.cloud.sleuth.autoconfig;
import brave.propagation.B3Propagation;
import brave.propagation.ExtraFieldPropagation;
import java.util.List;
import brave.Tracing;
import brave.baggage.BaggageField;
import brave.baggage.BaggagePropagation;
import brave.baggage.BaggagePropagationConfig;
import brave.baggage.BaggagePropagationConfig.SingleBaggageField;
import brave.propagation.B3SinglePropagation;
import brave.propagation.Propagation;
import brave.propagation.TraceContextOrSamplingFlags;
import io.micrometer.core.instrument.MeterRegistry;
import io.micrometer.core.instrument.simple.SimpleMeterRegistry;
import org.assertj.core.api.BDDAssertions;
@@ -27,6 +34,7 @@ import zipkin2.reporter.InMemoryReporterMetrics;
import zipkin2.reporter.ReporterMetrics;
import zipkin2.reporter.metrics.micrometer.MicrometerReporterMetrics;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.AutoConfigurations;
import org.springframework.boot.test.context.FilteredClassLoader;
import org.springframework.boot.test.context.runner.ApplicationContextRunner;
@@ -36,7 +44,9 @@ import org.springframework.context.annotation.Configuration;
public class TraceAutoConfigurationTests {
private final ApplicationContextRunner contextRunner = new ApplicationContextRunner()
.withConfiguration(AutoConfigurations.of(TraceAutoConfiguration.class));
.withConfiguration(
AutoConfigurations.of(PropertyBasedBaggageConfiguration.class,
TraceAutoConfiguration.class));
@Test
public void should_apply_micrometer_reporter_metrics_when_meter_registry_bean_present() {
@@ -77,25 +87,81 @@ public class TraceAutoConfigurationTests {
}
@Test
public void should_use_local_keys_from_properties() {
this.contextRunner.withUserConfiguration(WithLocalKeys.class).run((context -> {
final Propagation.Factory bean = context.getBean(Propagation.Factory.class);
BDDAssertions.then(bean).isInstanceOf(ExtraFieldPropagation.Factory.class);
}));
public void should_use_baggageBean() {
this.contextRunner.withUserConfiguration(WithBaggageBeans.class, Baggage.class)
.run((context -> {
final Baggage bean = context.getBean(Baggage.class);
BDDAssertions.then(bean.fields).containsOnly(
BaggageField.create("userId"),
BaggageField.create("userName"));
}));
}
@Test
public void should_use_extraFieldPropagationFactoryBuilder_bean() {
this.contextRunner
.withUserConfiguration(WithExtraFieldPropagationFactoryBuilderBean.class)
.run((context -> {
final Propagation.Factory bean = context
.getBean(Propagation.Factory.class);
BDDAssertions.then(bean)
.isInstanceOf(ExtraFieldPropagation.Factory.class);
public void should_use_local_keys_from_properties() {
this.contextRunner.withPropertyValues("spring.sleuth.local-keys=test-key")
.withUserConfiguration(Baggage.class).run((context -> {
final Baggage bean = context.getBean(Baggage.class);
BDDAssertions.then(bean.fields)
.containsExactly(BaggageField.create("test-key"));
}));
}
@Test
public void should_combine_baggage_beans_and_properties() {
this.contextRunner.withPropertyValues("spring.sleuth.local-keys=test-key")
.withUserConfiguration(WithBaggageBeans.class, Baggage.class)
.run((context -> {
final Baggage bean = context.getBean(Baggage.class);
BDDAssertions.then(bean.fields).containsOnly(
BaggageField.create("userId"),
BaggageField.create("userName"),
BaggageField.create("test-key"));
}));
}
@Test
public void should_use_baggagePropagationFactoryBuilder_bean() {
// BaggagePropagation.FactoryBuilder unwraps itself if there are no baggage fields
// defined
this.contextRunner
.withUserConfiguration(WithBaggagePropagationFactoryBuilderBean.class)
.run((context -> BDDAssertions
.then(context.getBean(Propagation.Factory.class))
.isSameAs(B3SinglePropagation.FACTORY)));
}
@Configuration
static class Baggage {
List<BaggageField> fields;
@Autowired
Baggage(Tracing tracing) {
// When predefined baggage fields exist, the result !=
// TraceContextOrSamplingFlags.EMPTY
TraceContextOrSamplingFlags emptyExtraction = tracing.propagation()
.extractor((c, k) -> null).extract(Boolean.TRUE);
fields = BaggageField.getAll(emptyExtraction);
}
}
@Configuration
static class WithBaggageBeans {
@Bean
BaggagePropagationConfig userId() {
return SingleBaggageField.remote(BaggageField.create("userId"));
}
@Bean
BaggagePropagationConfig userName() {
return SingleBaggageField.remote(BaggageField.create("userName"));
}
}
@Configuration
static class WithMeterRegistry {
@@ -107,23 +173,11 @@ public class TraceAutoConfigurationTests {
}
@Configuration
static class WithLocalKeys {
static class WithBaggagePropagationFactoryBuilderBean {
@Bean
SleuthProperties sleuthProperties() {
final SleuthProperties sleuthProperties = new SleuthProperties();
sleuthProperties.getLocalKeys().add("test-key");
return sleuthProperties;
}
}
@Configuration
static class WithExtraFieldPropagationFactoryBuilderBean {
@Bean
ExtraFieldPropagation.FactoryBuilder extraFieldPropagationFactoryBuilderBean() {
return ExtraFieldPropagation.newFactoryBuilder(B3Propagation.FACTORY);
BaggagePropagation.FactoryBuilder baggagePropagationFactoryBuilderBean() {
return BaggagePropagation.newFactoryBuilder(B3SinglePropagation.FACTORY);
}
}

View File

@@ -20,7 +20,9 @@ import java.util.Arrays;
import java.util.List;
import brave.Span;
import brave.Tags;
import brave.Tracer;
import brave.baggage.BaggageField;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
@@ -73,6 +75,11 @@ public class DemoApplication {
@RequestHeader HttpHeaders headers) {
this.sender.send(message);
this.httpSpan = this.tracer.currentSpan();
// tag what was propagated
BaggageField baz = BaggageField.getByName(httpSpan.context(), "baz");
Tags.BAGGAGE_FIELD.tag(baz, httpSpan);
return new Greeting(message);
}

View File

@@ -18,12 +18,17 @@ package org.springframework.cloud.sleuth.instrument.multiple;
import java.net.URI;
import java.util.Collections;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;
import brave.Span;
import brave.Tags;
import brave.Tracer;
import brave.propagation.ExtraFieldPropagation;
import brave.Tracer.SpanInScope;
import brave.Tracing;
import brave.baggage.BaggageField;
import brave.baggage.BaggagePropagationConfig;
import brave.baggage.BaggagePropagationConfig.SingleBaggageField;
import brave.sampler.Sampler;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
@@ -40,24 +45,24 @@ import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
import org.springframework.http.RequestEntity;
import org.springframework.test.context.ActiveProfiles;
import org.springframework.test.context.TestPropertySource;
import org.springframework.web.client.RestTemplate;
import static java.util.Arrays.asList;
import static java.util.concurrent.TimeUnit.SECONDS;
import static java.util.stream.Collectors.toList;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.BDDAssertions.then;
import static org.awaitility.Awaitility.await;
import static org.springframework.boot.test.context.SpringBootTest.WebEnvironment.RANDOM_PORT;
@TestPropertySource(
properties = { "spring.application.name=multiplehopsintegrationtests" })
@SpringBootTest(classes = MultipleHopsIntegrationTests.Config.class,
webEnvironment = RANDOM_PORT)
@ActiveProfiles("baggage")
webEnvironment = RANDOM_PORT, properties = { "spring.sleuth.baggage-keys=baz",
"spring.sleuth.propagation-keys=foo" })
public class MultipleHopsIntegrationTests {
@Autowired
Tracing tracing;
@Autowired
Tracer tracer;
@@ -79,7 +84,7 @@ public class MultipleHopsIntegrationTests {
}
@Test
public void should_prepare_spans_for_export() throws Exception {
public void should_prepare_spans_for_export() {
this.restTemplate.getForObject(
"http://localhost:" + this.config.port + "/greeting", String.class);
@@ -98,38 +103,28 @@ public class MultipleHopsIntegrationTests {
.containsAll(asList("words", "counts", "greetings"));
}
// issue #237 - baggage
@Test
// Notes:
// * path-prefix header propagation can't reliably support mixed case, due to http/2
// downcasing
// * Since not all tokenizers are case insensitive, mixed case can break correlation
// * Brave's ExtraFieldPropagation downcases due to the above
// * This code should probably test the side-effect on http headers
// * the assumption all correlation fields (baggage) are saved to a span is an
// interesting one
// * should all correlation fields (baggage) be added to the MDC context?
// * Until below, a configuration item of a correlation field whitelist is needed
// * https://github.com/openzipkin/brave/pull/577
// * probably needed anyway as an empty whitelist is a nice way to disable the feature
public void should_propagate_the_baggage() throws Exception {
public void should_propagate_the_baggage() {
// TODO: make a DemoBaggage type instead of saying to use the api directly
BaggageField foo = BaggageField.create("foo");
BaggageField bar = BaggageField.create("bar");
BaggageField baz = BaggageField.create("baz");
// tag::baggage[]
Span initialSpan = this.tracer.nextSpan().name("span").start();
ExtraFieldPropagation.set(initialSpan.context(), "foo", "bar");
ExtraFieldPropagation.set(initialSpan.context(), "UPPER_CASE", "someValue");
foo.updateValue(initialSpan.context(), "1");
bar.updateValue(initialSpan.context(), "2");
// end::baggage[]
try (Tracer.SpanInScope ws = this.tracer.withSpanInScope(initialSpan)) {
try (SpanInScope ws = this.tracer.withSpanInScope(initialSpan)) {
// tag::baggage_tag[]
initialSpan.tag("foo",
ExtraFieldPropagation.get(initialSpan.context(), "foo"));
initialSpan.tag("UPPER_CASE",
ExtraFieldPropagation.get(initialSpan.context(), "UPPER_CASE"));
Tags.BAGGAGE_FIELD.tag(foo, initialSpan);
Tags.BAGGAGE_FIELD.tag(bar, initialSpan);
// end::baggage_tag[]
// set baz in a header not with the api explicitly
HttpHeaders headers = new HttpHeaders();
headers.put("baggage-baz", Collections.singletonList("baz"));
headers.put("baggage-bizarreCASE", Collections.singletonList("value"));
headers.put("baggage-baz", Collections.singletonList("3"));
RequestEntity requestEntity = new RequestEntity(headers, HttpMethod.GET,
URI.create("http://localhost:" + this.config.port + "/greeting"));
this.restTemplate.exchange(requestEntity, String.class);
@@ -137,29 +132,29 @@ public class MultipleHopsIntegrationTests {
finally {
initialSpan.finish();
}
await().atMost(5, SECONDS).untilAsserted(() -> {
then(this.reporter.getSpans()).isNotEmpty();
});
then(this.application.allSpans()).as("All have foo")
.allMatch(span -> "bar".equals(baggage(span, "foo")));
then(this.application.allSpans()).as("All have UPPER_CASE")
.allMatch(span -> "someValue".equals(baggage(span, "UPPER_CASE")));
then(this.application.allSpans().stream()
.filter(span -> "baz".equals(baggage(span, "baz")))
.collect(Collectors.toList())).as("Someone has baz").isNotEmpty();
then(this.reporter.getSpans().stream()
.filter(span -> span.tags().containsKey("foo")
&& span.tags().containsKey("UPPER_CASE"))
.collect(Collectors.toList())).as("Someone has foo and UPPER_CASE tags")
.isNotEmpty();
then(this.application.allSpans().stream()
.filter(span -> "value".equals(baggage(span, "bizarreCASE")))
.collect(Collectors.toList())).isNotEmpty();
}
List<zipkin2.Span> withBagTags = this.reporter.getSpans().stream()
.filter(s -> s.tags().containsKey(foo.name())).collect(toList());
private String baggage(Span span, String name) {
return ExtraFieldPropagation.get(span.context(), name);
// set with tag api
then(withBagTags).as("only initialSpan was bag tagged").hasSize(1);
assertThat(withBagTags.get(0).tags()).containsEntry("foo", "1")
.containsEntry("bar", "2");
// set with baggage api
then(this.application.allSpans()).as("All have foo")
.allMatch(span -> "1".equals(foo.getValue(span.context())));
then(this.application.allSpans()).as("All have bar")
.allMatch(span -> "2".equals(bar.getValue(span.context())));
// baz is not tagged in the initial span, only downstream!
then(this.application.allSpans()).as("All downstream have baz")
.filteredOn(span -> !span.equals(initialSpan))
.allMatch(span -> "3".equals(baz.getValue(span.context())));
}
@Configuration
@@ -174,6 +169,11 @@ public class MultipleHopsIntegrationTests {
this.port = event.getSource().getPort();
}
@Bean
BaggagePropagationConfig notInProperties() {
return SingleBaggageField.remote(BaggageField.create("bar"));
}
@Bean
RestTemplate restTemplate() {
return new RestTemplate();

View File

@@ -18,8 +18,9 @@ package org.springframework.cloud.sleuth.log;
import brave.Span;
import brave.Tracer;
import brave.baggage.CorrelationField;
import brave.baggage.CorrelationScopeConfig.SingleCorrelationField;
import brave.propagation.CurrentTraceContext.Scope;
import brave.propagation.CurrentTraceContext.ScopeDecorator;
import brave.propagation.ExtraFieldPropagation;
import org.assertj.core.api.InstanceOfAssertFactories;
import org.junit.jupiter.api.AfterEach;
@@ -51,7 +52,7 @@ public class Slf4JSpanLoggerTest {
Tracer tracer;
@Autowired
Slf4jScopeDecorator slf4jScopeDecorator;
ScopeDecorator slf4jScopeDecorator;
Span span;
@@ -173,10 +174,11 @@ public class Slf4JSpanLoggerTest {
@Test
public void should_only_include_whitelist() {
assertThat(this.slf4jScopeDecorator).extracting("delegate.fields")
.asInstanceOf(InstanceOfAssertFactories.array(CorrelationField[].class))
.extracting(CorrelationField::name).containsExactly("traceId", "parentId",
"spanId", "spanExportable", "my-baggage", "my-local",
assertThat(this.slf4jScopeDecorator).extracting("fields")
.asInstanceOf(
InstanceOfAssertFactories.array(SingleCorrelationField[].class))
.extracting(SingleCorrelationField::name).containsOnly("traceId",
"parentId", "spanId", "spanExportable", "my-baggage", "my-local",
"my-propagation"); // my-baggage-two is not in the whitelist
}

View File

@@ -1,7 +0,0 @@
spring.sleuth:
baggage-keys:
- baz
- bizarrecase
propagation-keys:
- foo
- upper_case

View File

@@ -31,8 +31,8 @@
<name>spring-cloud-sleuth-dependencies</name>
<description>Spring Cloud Sleuth Dependencies</description>
<properties>
<brave.version>5.11.1</brave.version>
<brave.opentracing.version>0.36.1</brave.opentracing.version>
<brave.version>5.11.2</brave.version>
<brave.opentracing.version>0.36.2</brave.opentracing.version>
<grpc.spring.boot.version>3.4.1</grpc.spring.boot.version>
</properties>
<dependencyManagement>