Adapted new configuration to support backwards compatibility in case another tracing system extends from spring-cloud-sleuth-zipkin (like spring-cloud-gcp-trace)

This commit is contained in:
Tim Ysewyn
2019-01-16 21:46:28 +01:00
parent d8381b88c9
commit 453d942829
7 changed files with 203 additions and 37 deletions

View File

@@ -19,9 +19,7 @@ package org.springframework.cloud.sleuth.zipkin2;
import java.util.concurrent.TimeUnit;
import zipkin2.Span;
import zipkin2.codec.BytesEncoder;
import zipkin2.reporter.AsyncReporter;
import zipkin2.reporter.InMemoryReporterMetrics;
import zipkin2.reporter.Reporter;
import zipkin2.reporter.ReporterMetrics;
import zipkin2.reporter.Sender;
@@ -86,18 +84,11 @@ public class ZipkinAutoConfiguration {
@Bean(REPORTER_BEAN_NAME)
@ConditionalOnMissingBean(name = REPORTER_BEAN_NAME)
public Reporter<Span> reporter(ReporterMetrics reporterMetrics,
ZipkinProperties zipkin, @Qualifier(SENDER_BEAN_NAME) Sender sender,
BytesEncoder<Span> spanBytesEncoder) {
ZipkinProperties zipkin, @Qualifier(SENDER_BEAN_NAME) Sender sender) {
// historical constraint. Note: AsyncReporter supports memory bounds
return AsyncReporter.builder(sender).queuedMaxSpans(1000)
.messageTimeout(zipkin.getMessageTimeout(), TimeUnit.SECONDS)
.metrics(reporterMetrics).build(spanBytesEncoder);
}
@Bean
@ConditionalOnMissingBean
public BytesEncoder<Span> spanBytesEncoder(ZipkinProperties zipkinProperties) {
return zipkinProperties.getEncoder();
.metrics(reporterMetrics).build(zipkin.getEncoder());
}
@Bean
@@ -107,18 +98,6 @@ public class ZipkinAutoConfiguration {
return new DefaultZipkinRestTemplateCustomizer(zipkinProperties);
}
/**
* Deprecated because this is moved to {@link TraceAutoConfiguration}. Left for
* backwards compatibility reasons.
* @deprecated
*/
@Bean
@ConditionalOnMissingBean
@Deprecated
ReporterMetrics zipkinReporterMetrics() {
return new InMemoryReporterMetrics();
}
@Configuration
@ConditionalOnMissingBean(EndpointLocator.class)
@ConditionalOnProperty(value = "spring.zipkin.locator.discovery.enabled", havingValue = "false", matchIfMissing = true)

View File

@@ -0,0 +1,149 @@
/*
* 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
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.cloud.sleuth.zipkin2;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;
import zipkin2.Span;
import zipkin2.codec.BytesEncoder;
import zipkin2.reporter.AsyncReporter;
import zipkin2.reporter.InMemoryReporterMetrics;
import zipkin2.reporter.Reporter;
import zipkin2.reporter.ReporterMetrics;
import zipkin2.reporter.Sender;
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
import org.springframework.boot.autoconfigure.AutoConfigureAfter;
import org.springframework.boot.autoconfigure.condition.ConditionOutcome;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.autoconfigure.condition.SpringBootCondition;
import org.springframework.cloud.sleuth.autoconfig.TraceAutoConfiguration;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ConditionContext;
import org.springframework.context.annotation.Conditional;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.ConfigurationCondition;
import org.springframework.core.type.AnnotatedTypeMetadata;
import org.springframework.util.Assert;
/**
* {@link org.springframework.boot.autoconfigure.EnableAutoConfiguration
* Auto-configuration} that will provide backwards compatibility to be able to support
* multiple tracing systems on the classpath.
*
* Needs to be auto-configured before {@link ZipkinAutoConfiguration} in order to create a
* {@link Reporter<Span> span reporter} if needed.
*
* @author Tim Ysewyn
* @since 2.1.0
* @see ZipkinAutoConfiguration
* @deprecated
*/
@Configuration
@ConditionalOnProperty(value = { "spring.sleuth.enabled",
"spring.zipkin.enabled" }, matchIfMissing = true)
@AutoConfigureAfter({ ZipkinAutoConfiguration.class })
@Deprecated
public class ZipkinBackwardsCompatibilityAutoConfiguration {
/**
* Reporter that is depending on a {@link Sender} bean which is created in another
* auto-configuration than {@link ZipkinAutoConfiguration}.
*/
@Bean
@Conditional(BackwardsCompatibilityCondition.class)
@Deprecated
public Reporter<Span> reporter(ReporterMetrics reporterMetrics,
ZipkinProperties zipkin, BytesEncoder<Span> spanBytesEncoder,
DefaultListableBeanFactory beanFactory) {
List<String> beanNames = new ArrayList<>(
Arrays.asList(beanFactory.getBeanNamesForType(Sender.class)));
beanNames.remove(ZipkinAutoConfiguration.SENDER_BEAN_NAME);
Sender sender = (Sender) beanFactory.getBean(beanNames.get(0));
// historical constraint. Note: AsyncReporter supports memory bounds
return AsyncReporter.builder(sender).queuedMaxSpans(1000)
.messageTimeout(zipkin.getMessageTimeout(), TimeUnit.SECONDS)
.metrics(reporterMetrics).build(spanBytesEncoder);
}
/**
* Only used for creating a reporter bean with the method above
* @deprecated
*/
@Bean
@ConditionalOnMissingBean
@Deprecated
public BytesEncoder<Span> spanBytesEncoder(ZipkinProperties zipkinProperties) {
return zipkinProperties.getEncoder();
}
/**
* Deprecated because this is moved to {@link TraceAutoConfiguration}. Left for
* backwards compatibility reasons.
* @deprecated
*/
@Bean
@ConditionalOnMissingBean
@Deprecated
ReporterMetrics zipkinReporterMetrics() {
return new InMemoryReporterMetrics();
}
static class BackwardsCompatibilityCondition extends SpringBootCondition
implements ConfigurationCondition {
@Override
public ConfigurationPhase getConfigurationPhase() {
return ConfigurationPhase.REGISTER_BEAN;
}
@Override
public ConditionOutcome getMatchOutcome(ConditionContext context,
AnnotatedTypeMetadata metadata) {
Assert.isInstanceOf(DefaultListableBeanFactory.class,
context.getBeanFactory());
DefaultListableBeanFactory listableBeanFactory = (DefaultListableBeanFactory) context
.getBeanFactory();
int foundSenders = listableBeanFactory
.getBeanNamesForType(Sender.class).length;
// Previously we supported 1 Sender bean at a time
// which could be overridden by another auto-configuration.
// Now we support both the overridden bean and our default zipkinSender bean.
if (foundSenders < 2) {
return ConditionOutcome.noMatch(
"We don't support backwards compatibility for more than 2 Sender beans");
}
int foundReporters = listableBeanFactory
.getBeanNamesForType(Reporter.class).length;
// Check if we need to provide a Reporter bean for the overridden Sender bean
if (foundReporters == foundSenders) {
return ConditionOutcome.noMatch(
"Both tracing systems already define their own Reporter bean");
}
return ConditionOutcome.match();
}
}
}

View File

@@ -35,7 +35,7 @@ import zipkin2.reporter.kafka11.KafkaSender;
@Configuration
@ConditionalOnClass(ByteArraySerializer.class)
@ConditionalOnBean(KafkaProperties.class)
@ConditionalOnMissingBean(Sender.class)
@ConditionalOnMissingBean(name = ZipkinAutoConfiguration.SENDER_BEAN_NAME)
@Conditional(ZipkinSenderCondition.class)
@ConditionalOnProperty(value = "spring.zipkin.sender.type", havingValue = "kafka")
class ZipkinKafkaSenderConfiguration {

View File

@@ -30,7 +30,7 @@ import zipkin2.reporter.amqp.RabbitMQSender;
@Configuration
@ConditionalOnBean(CachingConnectionFactory.class)
@ConditionalOnMissingBean(Sender.class)
@ConditionalOnMissingBean(name = ZipkinAutoConfiguration.SENDER_BEAN_NAME)
@Conditional(ZipkinSenderCondition.class)
class ZipkinRabbitSenderConfiguration {

View File

@@ -43,7 +43,7 @@ import org.springframework.web.client.RestTemplate;
import zipkin2.reporter.Sender;
@Configuration
@ConditionalOnMissingBean(Sender.class)
@ConditionalOnMissingBean(name = ZipkinAutoConfiguration.SENDER_BEAN_NAME)
@Conditional(ZipkinSenderCondition.class)
@EnableConfigurationProperties(ZipkinSenderProperties.class)
class ZipkinRestTemplateSenderConfiguration {
@@ -52,7 +52,6 @@ class ZipkinRestTemplateSenderConfiguration {
ZipkinUrlExtractor extractor;
@Bean(ZipkinAutoConfiguration.SENDER_BEAN_NAME)
@ConditionalOnMissingBean(name = ZipkinAutoConfiguration.SENDER_BEAN_NAME)
public Sender restTemplateSender(ZipkinProperties zipkin,
ZipkinRestTemplateCustomizer zipkinRestTemplateCustomizer) {
RestTemplate restTemplate = new ZipkinRestTemplateWrapper(zipkin, this.extractor);

View File

@@ -1,3 +1,4 @@
# Auto Configuration
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
org.springframework.cloud.sleuth.zipkin2.ZipkinAutoConfiguration
org.springframework.cloud.sleuth.zipkin2.ZipkinAutoConfiguration,\
org.springframework.cloud.sleuth.zipkin2.ZipkinBackwardsCompatibilityAutoConfiguration

View File

@@ -79,7 +79,7 @@ public class ZipkinAutoConfigurationTests {
this.server.url("/").toString());
this.context.register(ZipkinAutoConfiguration.class,
PropertyPlaceholderAutoConfiguration.class, TraceAutoConfiguration.class,
Config.class);
Config.class, ZipkinBackwardsCompatibilityAutoConfiguration.class);
this.context.refresh();
Span span = this.context.getBean(Tracing.class).tracer().nextSpan().name("foo")
.tag("foo", "bar").start();
@@ -106,7 +106,7 @@ public class ZipkinAutoConfigurationTests {
environment().setProperty("spring.zipkin.encoder", "JSON_V1");
this.context.register(ZipkinAutoConfiguration.class,
PropertyPlaceholderAutoConfiguration.class, TraceAutoConfiguration.class,
Config.class);
Config.class, ZipkinBackwardsCompatibilityAutoConfiguration.class);
this.context.refresh();
Span span = this.context.getBean(Tracing.class).tracer().nextSpan().name("foo")
.tag("foo", "bar").start();
@@ -124,9 +124,11 @@ public class ZipkinAutoConfigurationTests {
public void overrideRabbitMQQueue() throws Exception {
this.context = new AnnotationConfigApplicationContext();
environment().setProperty("spring.zipkin.rabbitmq.queue", "zipkin2");
environment().setProperty("spring.zipkin.sender.type", "rabbit");
this.context.register(PropertyPlaceholderAutoConfiguration.class,
RabbitAutoConfiguration.class, ZipkinAutoConfiguration.class,
TraceAutoConfiguration.class);
TraceAutoConfiguration.class,
ZipkinBackwardsCompatibilityAutoConfiguration.class);
this.context.refresh();
then(this.context.getBean(Sender.class)).isInstanceOf(RabbitMQSender.class);
@@ -141,7 +143,8 @@ public class ZipkinAutoConfigurationTests {
environment().setProperty("spring.zipkin.sender.type", "kafka");
this.context.register(PropertyPlaceholderAutoConfiguration.class,
KafkaAutoConfiguration.class, ZipkinAutoConfiguration.class,
TraceAutoConfiguration.class);
TraceAutoConfiguration.class,
ZipkinBackwardsCompatibilityAutoConfiguration.class);
this.context.refresh();
then(this.context.getBean(Sender.class)).isInstanceOf(KafkaSender.class);
@@ -155,7 +158,8 @@ public class ZipkinAutoConfigurationTests {
environment().setProperty("spring.zipkin.sender.type", "web");
this.context.register(PropertyPlaceholderAutoConfiguration.class,
RabbitAutoConfiguration.class, KafkaAutoConfiguration.class,
ZipkinAutoConfiguration.class, TraceAutoConfiguration.class);
ZipkinAutoConfiguration.class, TraceAutoConfiguration.class,
ZipkinBackwardsCompatibilityAutoConfiguration.class);
this.context.refresh();
then(this.context.getBean(Sender.class).getClass().getName())
@@ -170,7 +174,8 @@ public class ZipkinAutoConfigurationTests {
environment().setProperty("spring.zipkin.sender.type", "WEB");
this.context.register(PropertyPlaceholderAutoConfiguration.class,
RabbitAutoConfiguration.class, KafkaAutoConfiguration.class,
ZipkinAutoConfiguration.class, TraceAutoConfiguration.class);
ZipkinAutoConfiguration.class, TraceAutoConfiguration.class,
ZipkinBackwardsCompatibilityAutoConfiguration.class);
this.context.refresh();
then(this.context.getBean(Sender.class).getClass().getName())
@@ -184,7 +189,8 @@ public class ZipkinAutoConfigurationTests {
this.context = new AnnotationConfigApplicationContext();
this.context.register(PropertyPlaceholderAutoConfiguration.class,
RabbitAutoConfiguration.class, KafkaAutoConfiguration.class,
ZipkinAutoConfiguration.class, TraceAutoConfiguration.class);
ZipkinAutoConfiguration.class, TraceAutoConfiguration.class,
ZipkinBackwardsCompatibilityAutoConfiguration.class);
this.context.refresh();
then(this.context.getBean(Sender.class)).isInstanceOf(RabbitMQSender.class);
@@ -199,7 +205,8 @@ public class ZipkinAutoConfigurationTests {
this.server.url("/").toString());
this.context.register(ZipkinAutoConfiguration.class,
PropertyPlaceholderAutoConfiguration.class, TraceAutoConfiguration.class,
Config.class, MultipleReportersConfig.class);
Config.class, MultipleReportersConfig.class,
ZipkinBackwardsCompatibilityAutoConfiguration.class);
this.context.refresh();
then(this.context.getBeansOfType(Sender.class)).hasSize(2);
@@ -226,12 +233,33 @@ public class ZipkinAutoConfigurationTests {
Awaitility.await().untilAsserted(() -> then(sender.isSpanSent()).isTrue());
}
@Test
public void supportsMultipleReportersWithBackwardsCompatibilty() throws Exception {
this.context = new AnnotationConfigApplicationContext();
environment().setProperty("spring.zipkin.base-url",
this.server.url("/").toString());
this.context.register(ZipkinAutoConfiguration.class,
PropertyPlaceholderAutoConfiguration.class, TraceAutoConfiguration.class,
Config.class, BackwardsCompatibilityConfig.class,
ZipkinBackwardsCompatibilityAutoConfiguration.class);
this.context.refresh();
then(this.context.getBeansOfType(Sender.class)).hasSize(2);
then(this.context.getBeansOfType(Sender.class))
.containsKeys(ZipkinAutoConfiguration.SENDER_BEAN_NAME, "rabbitSender");
then(this.context.getBeansOfType(Reporter.class)).hasSize(2);
then(this.context.getBeansOfType(Reporter.class))
.containsKeys(ZipkinAutoConfiguration.REPORTER_BEAN_NAME, "reporter");
}
@Test
public void shouldOverrideDefaultBeans() {
this.context = new AnnotationConfigApplicationContext();
this.context.register(ZipkinAutoConfiguration.class,
PropertyPlaceholderAutoConfiguration.class, TraceAutoConfiguration.class,
Config.class, MyConfig.class);
Config.class, MyConfig.class,
ZipkinBackwardsCompatibilityAutoConfiguration.class);
this.context.refresh();
then(this.context.getBeansOfType(Sender.class)).hasSize(1);
@@ -337,6 +365,16 @@ public class ZipkinAutoConfigurationTests {
}
@Configuration
protected static class BackwardsCompatibilityConfig {
@Bean
Sender rabbitSender() {
return RabbitMQSender.create("localhost");
}
}
// tag::override_default_beans[]
@Configuration