Ensures that there are no issues with context setup when picking custom propagation type (#1989)
fixes gh-1987
This commit is contained in:
committed by
GitHub
parent
e9d55a3af0
commit
8b61684168
@@ -105,7 +105,11 @@ class BraveBaggageConfiguration {
|
||||
// See #1643
|
||||
@Bean
|
||||
@ConditionalOnMissingBean
|
||||
PropagationFactorySupplier defaultPropagationFactorySupplier() {
|
||||
PropagationFactorySupplier defaultPropagationFactorySupplier(SleuthPropagationProperties properties) {
|
||||
if (properties.getType().contains(PropagationType.CUSTOM)) {
|
||||
throw new IllegalStateException(
|
||||
"Please register a bean with the following signature [extends Propagation.Factory implements Propagation<String>] to override the default Sleuth behaviour or [implements PropagationFactorySupplier] to reuse it.");
|
||||
}
|
||||
return () -> B3Propagation.newFactoryBuilder().injectFormat(B3Propagation.Format.SINGLE_NO_PARENT).build();
|
||||
}
|
||||
|
||||
@@ -131,7 +135,6 @@ class BraveBaggageConfiguration {
|
||||
@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",
|
||||
sleuthBaggageProperties.getLocalFields());
|
||||
for (String fieldName : localFields) {
|
||||
|
||||
@@ -0,0 +1,102 @@
|
||||
/*
|
||||
* Copyright 2013-2021 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.brave.baggage;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import brave.internal.propagation.StringPropagationAdapter;
|
||||
import brave.propagation.Propagation;
|
||||
import brave.propagation.TraceContext;
|
||||
import brave.propagation.TraceContextOrSamplingFlags;
|
||||
import org.assertj.core.api.BDDAssertions;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import org.springframework.boot.actuate.autoconfigure.security.servlet.ManagementWebSecurityAutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.mongo.MongoAutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.quartz.QuartzAutoConfiguration;
|
||||
import org.springframework.boot.test.context.runner.ApplicationContextRunner;
|
||||
import org.springframework.cloud.gateway.config.GatewayAutoConfiguration;
|
||||
import org.springframework.cloud.gateway.config.GatewayClassPathWarningAutoConfiguration;
|
||||
import org.springframework.cloud.gateway.config.GatewayMetricsAutoConfiguration;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
||||
public class CustomPropagationFactoryTests {
|
||||
|
||||
@Test
|
||||
void should_fail_to_start_the_context_when_propagation_type_custom_and_no_custom_propagation_provided() {
|
||||
new ApplicationContextRunner().withUserConfiguration(Config.class)
|
||||
.withPropertyValues("spring.sleuth.propagation.type=custom")
|
||||
.run(context -> BDDAssertions.then(context).hasFailed());
|
||||
}
|
||||
|
||||
@Test
|
||||
void should_start_the_context_when_propagation_type_custom_and_no_custom_propagation_provided() {
|
||||
new ApplicationContextRunner().withUserConfiguration(CustomConfig.class)
|
||||
.withPropertyValues("spring.sleuth.propagation.type=custom").run(context -> BDDAssertions.then(context)
|
||||
.hasNotFailed().getBean(CustomConfig.CustomPropagation.class));
|
||||
}
|
||||
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
@EnableAutoConfiguration(exclude = { GatewayClassPathWarningAutoConfiguration.class, GatewayAutoConfiguration.class,
|
||||
GatewayMetricsAutoConfiguration.class, ManagementWebSecurityAutoConfiguration.class,
|
||||
MongoAutoConfiguration.class, QuartzAutoConfiguration.class })
|
||||
static class Config {
|
||||
|
||||
}
|
||||
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
@EnableAutoConfiguration(exclude = { GatewayClassPathWarningAutoConfiguration.class, GatewayAutoConfiguration.class,
|
||||
GatewayMetricsAutoConfiguration.class, ManagementWebSecurityAutoConfiguration.class,
|
||||
MongoAutoConfiguration.class, QuartzAutoConfiguration.class })
|
||||
static class CustomConfig {
|
||||
|
||||
@Bean
|
||||
CustomPropagation customPropagation() {
|
||||
return new CustomPropagation();
|
||||
}
|
||||
|
||||
static class CustomPropagation extends Propagation.Factory implements Propagation<String> {
|
||||
|
||||
@Override
|
||||
public List<String> keys() {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
@Override
|
||||
public <R> TraceContext.Injector<R> injector(Setter<R, String> setter) {
|
||||
return (traceContext, request) -> {
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
public <R> TraceContext.Extractor<R> extractor(Getter<R, String> getter) {
|
||||
return request -> TraceContextOrSamplingFlags.EMPTY;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <K> Propagation<K> create(KeyFactory<K> keyFactory) {
|
||||
return StringPropagationAdapter.create(this, keyFactory);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -84,7 +84,7 @@ class CompositePropagationFactory extends Propagation.Factory implements Propaga
|
||||
W3CPropagation w3CPropagation = new W3CPropagation(braveBaggageManager, localFields);
|
||||
this.mapping.put(PropagationType.W3C, new AbstractMap.SimpleEntry<>(w3CPropagation, w3CPropagation.get()));
|
||||
LazyPropagationFactory lazyPropagationFactory = new LazyPropagationFactory(
|
||||
beanFactory.getBeanProvider(Factory.class));
|
||||
beanFactory.getBeanProvider(PropagationFactorySupplier.class));
|
||||
this.mapping.put(PropagationType.CUSTOM,
|
||||
new AbstractMap.SimpleEntry<>(lazyPropagationFactory, lazyPropagationFactory.get()));
|
||||
}
|
||||
@@ -161,17 +161,17 @@ class CompositePropagationFactory extends Propagation.Factory implements Propaga
|
||||
@SuppressWarnings("unchecked")
|
||||
private static final class LazyPropagationFactory extends Propagation.Factory {
|
||||
|
||||
private final ObjectProvider<Propagation.Factory> delegate;
|
||||
private final ObjectProvider<PropagationFactorySupplier> delegate;
|
||||
|
||||
private volatile Propagation.Factory propagationFactory;
|
||||
|
||||
private LazyPropagationFactory(ObjectProvider<Propagation.Factory> delegate) {
|
||||
private LazyPropagationFactory(ObjectProvider<PropagationFactorySupplier> delegate) {
|
||||
this.delegate = delegate;
|
||||
}
|
||||
|
||||
private Propagation.Factory propagationFactory() {
|
||||
if (this.propagationFactory == null) {
|
||||
this.propagationFactory = this.delegate.getIfAvailable(() -> NoOpPropagation.INSTANCE);
|
||||
this.propagationFactory = this.delegate.getIfAvailable(() -> () -> NoOpPropagation.INSTANCE).get();
|
||||
}
|
||||
return this.propagationFactory;
|
||||
}
|
||||
|
||||
@@ -40,7 +40,8 @@ public enum PropagationType {
|
||||
W3C,
|
||||
|
||||
/**
|
||||
* Custom propagation type.
|
||||
* Custom propagation type. If picked, requires bean registration overriding the
|
||||
* default propagation mechanisms.
|
||||
*/
|
||||
CUSTOM
|
||||
|
||||
|
||||
@@ -1,120 +0,0 @@
|
||||
/*
|
||||
* Copyright 2013-2021 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.bridge;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
|
||||
import brave.internal.codec.HexCodec;
|
||||
import brave.internal.propagation.StringPropagationAdapter;
|
||||
import brave.propagation.Propagation;
|
||||
import brave.propagation.TraceContext;
|
||||
import brave.propagation.TraceContextOrSamplingFlags;
|
||||
import org.assertj.core.api.BDDAssertions;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.mockito.Mockito;
|
||||
|
||||
import org.springframework.beans.factory.BeanFactory;
|
||||
import org.springframework.cloud.loadbalancer.support.SimpleObjectProvider;
|
||||
import org.springframework.cloud.sleuth.brave.propagation.PropagationType;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
class CompositePropagationFactorySupplierTests {
|
||||
|
||||
@Test
|
||||
void should_pick_custom_registered_propagation_when_custom_mode_picked() {
|
||||
BeanFactory beanFactory = Mockito.mock(BeanFactory.class);
|
||||
Mockito.when(beanFactory.getBeanProvider(BraveBaggageManager.class))
|
||||
.thenReturn(new SimpleObjectProvider(new BraveBaggageManager()));
|
||||
Mockito.when(beanFactory.getBeanProvider(Propagation.Factory.class))
|
||||
.thenReturn(new SimpleObjectProvider(new CustomTracePropagation()));
|
||||
Mockito.when(beanFactory.getBeanProvider(Propagation.class))
|
||||
.thenReturn(new SimpleObjectProvider(new CustomTracePropagation()));
|
||||
|
||||
CompositePropagationFactorySupplier supplier = new CompositePropagationFactorySupplier(beanFactory,
|
||||
Collections.emptyList(), Collections.singletonList(PropagationType.CUSTOM));
|
||||
|
||||
BDDAssertions.then(supplier.get().get().keys()).containsExactly(CustomTraceExtractor.CUSTOM_TRACE_HEADER);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
class CustomTracePropagation extends Propagation.Factory implements Propagation<String> {
|
||||
|
||||
public static final List<String> KEYS = Collections.singletonList(CustomTraceExtractor.CUSTOM_TRACE_HEADER);
|
||||
|
||||
@Override
|
||||
public List<String> keys() {
|
||||
return KEYS;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <R> TraceContext.Injector<R> injector(Setter<R, String> setter) {
|
||||
return (traceContext, request) -> {
|
||||
String trace = traceContext.traceIdString() + ":" + traceContext.spanIdString();
|
||||
setter.put(request, CustomTraceExtractor.CUSTOM_TRACE_HEADER, trace);
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
public <R> TraceContext.Extractor<R> extractor(Getter<R, String> getter) {
|
||||
Objects.requireNonNull(getter);
|
||||
return new CustomTraceExtractor<>(getter);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <K> Propagation<K> create(KeyFactory<K> keyFactory) {
|
||||
return StringPropagationAdapter.create(this, keyFactory);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
class CustomTraceExtractor<R> implements TraceContext.Extractor<R> {
|
||||
|
||||
static final String CUSTOM_TRACE_HEADER = "x-custom-trace";
|
||||
|
||||
final Propagation.Getter<R, String> getter;
|
||||
|
||||
CustomTraceExtractor(Propagation.Getter<R, String> getter) {
|
||||
this.getter = getter;
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("ReturnCount")
|
||||
public TraceContextOrSamplingFlags extract(R request) {
|
||||
String traceString = getter.get(request, CUSTOM_TRACE_HEADER);
|
||||
if (!StringUtils.hasText(traceString)) {
|
||||
return TraceContextOrSamplingFlags.EMPTY;
|
||||
}
|
||||
String[] trace = traceString.split(":");
|
||||
if (trace.length != 2) {
|
||||
return TraceContextOrSamplingFlags.EMPTY;
|
||||
}
|
||||
|
||||
try {
|
||||
TraceContext traceContext = TraceContext.newBuilder().traceId(HexCodec.lowerHexToUnsignedLong(trace[0]))
|
||||
.spanId(HexCodec.lowerHexToUnsignedLong(trace[1])).build();
|
||||
|
||||
return TraceContextOrSamplingFlags.create(traceContext);
|
||||
}
|
||||
catch (NumberFormatException ex) {
|
||||
return TraceContextOrSamplingFlags.EMPTY;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user