diff --git a/pom.xml b/pom.xml index 1e2ac5e3d..bf62ea1f7 100644 --- a/pom.xml +++ b/pom.xml @@ -272,7 +272,7 @@ Elmhurst.BUILD-SNAPSHOT 2.0.0.BUILD-SNAPSHOT 2.0.0.BUILD-SNAPSHOT - 4.17.1 + 4.17.2 2.5.1 2.0.0.RELEASE diff --git a/spring-cloud-sleuth-core/pom.xml b/spring-cloud-sleuth-core/pom.xml index 1f766b3f2..c6c3e2124 100644 --- a/spring-cloud-sleuth-core/pom.xml +++ b/spring-cloud-sleuth-core/pom.xml @@ -91,6 +91,11 @@ spring-integration-core true + + org.springframework.amqp + spring-rabbit + true + org.springframework.security.oauth spring-security-oauth2 @@ -164,6 +169,10 @@ io.zipkin.brave brave-instrumentation-spring-web + + io.zipkin.brave + brave-instrumentation-spring-rabbit + io.zipkin.brave brave-instrumentation-httpclient diff --git a/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/messaging/SleuthMessagingProperties.java b/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/messaging/SleuthMessagingProperties.java new file mode 100644 index 000000000..d9dd514e1 --- /dev/null +++ b/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/messaging/SleuthMessagingProperties.java @@ -0,0 +1,81 @@ +/* + * Copyright 2013-2018 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.instrument.messaging; + +import org.springframework.boot.context.properties.ConfigurationProperties; + +/** + * @author Marcin Grzejszczak + * @since 2.0.0 + */ +@ConfigurationProperties("spring.sleuth") +public class SleuthMessagingProperties { + + private Integration integration = new Integration(); + + private Messaging messaging = new Messaging(); + + public Integration getIntegration() { + return this.integration; + } + + public void setIntegration(Integration integration) { + this.integration = integration; + } + + public Messaging getMessaging() { + return this.messaging; + } + + public void setMessaging(Messaging messaging) { + this.messaging = messaging; + } + + public static class Integration { + private boolean enabled; + + public boolean isEnabled() { + return this.enabled; + } + + public void setEnabled(boolean enabled) { + this.enabled = enabled; + } + } + + public static class Messaging { + private boolean enabled; + + private String remoteServiceName = "mq-service"; + + public boolean isEnabled() { + return this.enabled; + } + + public void setEnabled(boolean enabled) { + this.enabled = enabled; + } + + public String getRemoteServiceName() { + return this.remoteServiceName; + } + + public void setRemoteServiceName(String remoteServiceName) { + this.remoteServiceName = remoteServiceName; + } + } +} diff --git a/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/messaging/TraceMessagingAutoConfiguration.java b/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/messaging/TraceMessagingAutoConfiguration.java new file mode 100644 index 000000000..18ad7716a --- /dev/null +++ b/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/messaging/TraceMessagingAutoConfiguration.java @@ -0,0 +1,100 @@ +/* + * Copyright 2013-2018 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.instrument.messaging; + +import brave.Tracing; +import brave.spring.rabbit.SpringRabbitTracing; +import org.springframework.amqp.rabbit.config.SimpleRabbitListenerContainerFactory; +import org.springframework.amqp.rabbit.core.RabbitTemplate; +import org.springframework.beans.BeansException; +import org.springframework.beans.factory.BeanFactory; +import org.springframework.beans.factory.config.BeanPostProcessor; +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; +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; +import org.springframework.boot.context.properties.EnableConfigurationProperties; +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} that registers a tracing instrumentation of + * messaging components. + * + * @author Marcin Grzejszczak + * @since 2.0.0 + */ +@Configuration +@ConditionalOnBean(Tracing.class) +@AutoConfigureAfter({ TraceAutoConfiguration.class }) +@ConditionalOnProperty(value = "spring.sleuth.messaging.enabled", matchIfMissing = true) +@EnableConfigurationProperties(SleuthMessagingProperties.class) +public class TraceMessagingAutoConfiguration { + + @Configuration + @ConditionalOnClass(RabbitTemplate.class) + protected static class SleuthRabbitConfiguration { + @Bean + @ConditionalOnMissingBean + SpringRabbitTracing springRabbitTracing(Tracing tracing, + SleuthMessagingProperties properties) { + return SpringRabbitTracing.newBuilder(tracing) + .remoteServiceName(properties.getMessaging() + .getRemoteServiceName()) + .build(); + } + + @Bean + // for tests + @ConditionalOnMissingBean + SleuthRabbitBeanPostProcessor sleuthRabbitBeanPostProcessor(BeanFactory beanFactory) { + return new SleuthRabbitBeanPostProcessor(beanFactory); + } + } +} + +class SleuthRabbitBeanPostProcessor implements BeanPostProcessor { + + private final BeanFactory beanFactory; + private SpringRabbitTracing tracing; + + SleuthRabbitBeanPostProcessor(BeanFactory beanFactory) { + this.beanFactory = beanFactory; + } + + @Override public Object postProcessBeforeInitialization(Object bean, String beanName) + throws BeansException { + if (bean instanceof RabbitTemplate) { + return rabbitTracing() + .decorateRabbitTemplate((RabbitTemplate) bean); + } else if (bean instanceof SimpleRabbitListenerContainerFactory) { + return rabbitTracing() + .decorateSimpleRabbitListenerContainerFactory((SimpleRabbitListenerContainerFactory) bean); + } + return bean; + } + + SpringRabbitTracing rabbitTracing() { + if (this.tracing == null) { + this.tracing = this.beanFactory.getBean(SpringRabbitTracing.class); + } + return this.tracing; + } +} \ No newline at end of file diff --git a/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/messaging/TraceSpringIntegrationAutoConfiguration.java b/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/messaging/TraceSpringIntegrationAutoConfiguration.java index cec06b7a5..39a3adf8c 100644 --- a/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/messaging/TraceSpringIntegrationAutoConfiguration.java +++ b/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/messaging/TraceSpringIntegrationAutoConfiguration.java @@ -22,7 +22,6 @@ import org.springframework.boot.autoconfigure.condition.ConditionalOnBean; 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.TraceKeys; import org.springframework.cloud.sleuth.autoconfig.TraceAutoConfiguration; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; @@ -43,7 +42,7 @@ import org.springframework.integration.config.GlobalChannelInterceptor; @ConditionalOnBean(Tracing.class) @AutoConfigureAfter({ TraceAutoConfiguration.class }) @ConditionalOnProperty(value = "spring.sleuth.integration.enabled", matchIfMissing = true) -@EnableConfigurationProperties(TraceKeys.class) +@EnableConfigurationProperties(SleuthMessagingProperties.class) public class TraceSpringIntegrationAutoConfiguration { @Bean diff --git a/spring-cloud-sleuth-core/src/main/resources/META-INF/spring.factories b/spring-cloud-sleuth-core/src/main/resources/META-INF/spring.factories index 6ade66073..122fb754a 100644 --- a/spring-cloud-sleuth-core/src/main/resources/META-INF/spring.factories +++ b/spring-cloud-sleuth-core/src/main/resources/META-INF/spring.factories @@ -17,6 +17,7 @@ org.springframework.cloud.sleuth.instrument.rxjava.RxJavaAutoConfiguration,\ org.springframework.cloud.sleuth.instrument.reactor.TraceReactorAutoConfiguration,\ org.springframework.cloud.sleuth.instrument.web.TraceWebFluxAutoConfiguration,\ org.springframework.cloud.sleuth.instrument.zuul.TraceZuulAutoConfiguration,\ +org.springframework.cloud.sleuth.instrument.messaging.TraceMessagingAutoConfiguration,\ org.springframework.cloud.sleuth.instrument.messaging.TraceSpringIntegrationAutoConfiguration,\ org.springframework.cloud.sleuth.instrument.messaging.websocket.TraceWebSocketAutoConfiguration,\ org.springframework.cloud.sleuth.instrument.opentracing.OpentracingAutoConfiguration diff --git a/spring-cloud-sleuth-core/src/test/java/org/springframework/cloud/sleuth/instrument/messaging/TraceMessagingAutoConfigurationTests.java b/spring-cloud-sleuth-core/src/test/java/org/springframework/cloud/sleuth/instrument/messaging/TraceMessagingAutoConfigurationTests.java new file mode 100644 index 000000000..bde8d9f59 --- /dev/null +++ b/spring-cloud-sleuth-core/src/test/java/org/springframework/cloud/sleuth/instrument/messaging/TraceMessagingAutoConfigurationTests.java @@ -0,0 +1,95 @@ +/* + * Copyright 2013-2018 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.instrument.messaging; + +import brave.sampler.Sampler; +import brave.spring.rabbit.SpringRabbitTracing; +import com.rabbitmq.client.Channel; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.BDDMockito; +import org.mockito.Mock; +import org.springframework.amqp.AmqpException; +import org.springframework.amqp.core.Message; +import org.springframework.amqp.core.MessageProperties; +import org.springframework.amqp.rabbit.connection.CachingConnectionFactory; +import org.springframework.amqp.rabbit.connection.Connection; +import org.springframework.amqp.rabbit.connection.ConnectionFactory; +import org.springframework.amqp.rabbit.connection.ConnectionListener; +import org.springframework.amqp.rabbit.core.RabbitTemplate; +import org.springframework.beans.BeansException; +import org.springframework.beans.factory.BeanFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.autoconfigure.EnableAutoConfiguration; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.boot.test.mock.mockito.SpyBean; +import org.springframework.cloud.sleuth.util.ArrayListSpanReporter; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.test.context.junit4.SpringRunner; + +import static org.assertj.core.api.BDDAssertions.then; + +/** + * @author Marcin Grzejszczak + */ +@RunWith(SpringRunner.class) +@SpringBootTest(classes = TraceMessagingAutoConfigurationTests.Config.class, + webEnvironment = SpringBootTest.WebEnvironment.NONE) +public class TraceMessagingAutoConfigurationTests { + + @Autowired RabbitTemplate rabbitTemplate; + @Autowired ArrayListSpanReporter reporter; + @Autowired TestSleuthRabbitBeanPostProcessor postProcessor; + + @Test + public void should_wrap_rabbit_template() { + then(this.rabbitTemplate).isNotNull(); + then(this.postProcessor.rabbitTracingCalled).isTrue(); + } + + @Configuration + @EnableAutoConfiguration + protected static class Config { + @Bean Sampler sampler() { + return Sampler.ALWAYS_SAMPLE; + } + + @Bean ArrayListSpanReporter reporter() { + return new ArrayListSpanReporter(); + } + + @Bean SleuthRabbitBeanPostProcessor postProcessor(BeanFactory beanFactory) { + return new TestSleuthRabbitBeanPostProcessor(beanFactory); + } + } +} + +class TestSleuthRabbitBeanPostProcessor extends SleuthRabbitBeanPostProcessor { + + boolean rabbitTracingCalled = false; + + TestSleuthRabbitBeanPostProcessor(BeanFactory beanFactory) { + super(beanFactory); + } + + @Override SpringRabbitTracing rabbitTracing() { + this.rabbitTracingCalled = true; + return super.rabbitTracing(); + } +} \ No newline at end of file diff --git a/spring-cloud-sleuth-core/src/test/java/org/springframework/cloud/sleuth/instrument/web/client/exception/WebClientExceptionTests.java b/spring-cloud-sleuth-core/src/test/java/org/springframework/cloud/sleuth/instrument/web/client/exception/WebClientExceptionTests.java index 83cc1fea6..3c9181428 100644 --- a/spring-cloud-sleuth-core/src/test/java/org/springframework/cloud/sleuth/instrument/web/client/exception/WebClientExceptionTests.java +++ b/spring-cloud-sleuth-core/src/test/java/org/springframework/cloud/sleuth/instrument/web/client/exception/WebClientExceptionTests.java @@ -106,8 +106,7 @@ public class WebClientExceptionTests { then(this.tracer.tracer().currentSpan()).isNull(); then(this.reporter.getSpans()).isNotEmpty(); - then(this.reporter.getSpans().get(0).tags().get("error")) - .contains("invalid.host.to.break.tests"); + then(this.reporter.getSpans().get(0).tags()).containsKey("error"); } Object[] parametersForShouldCloseSpanUponException() {