Merge pull request #37640 from jonatan-ivanov

* pr/37640:
  Add auto-configuration for SpanAspect

Closes gh-37640
pull/37768/head
Moritz Halbritter 1 year ago
commit 4d65fbd49c

@ -17,17 +17,26 @@
package org.springframework.boot.actuate.autoconfigure.tracing;
import io.micrometer.tracing.Tracer;
import io.micrometer.tracing.annotation.DefaultNewSpanParser;
import io.micrometer.tracing.annotation.ImperativeMethodInvocationProcessor;
import io.micrometer.tracing.annotation.MethodInvocationProcessor;
import io.micrometer.tracing.annotation.NewSpanParser;
import io.micrometer.tracing.annotation.SpanAspect;
import io.micrometer.tracing.annotation.SpanTagAnnotationHandler;
import io.micrometer.tracing.handler.DefaultTracingObservationHandler;
import io.micrometer.tracing.handler.PropagatingReceiverTracingObservationHandler;
import io.micrometer.tracing.handler.PropagatingSenderTracingObservationHandler;
import io.micrometer.tracing.propagation.Propagator;
import org.aspectj.weaver.Advice;
import org.springframework.beans.factory.ObjectProvider;
import org.springframework.boot.autoconfigure.AutoConfiguration;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.Ordered;
import org.springframework.core.annotation.Order;
@ -35,10 +44,12 @@ import org.springframework.core.annotation.Order;
* {@link EnableAutoConfiguration Auto-configuration} for the Micrometer Tracing API.
*
* @author Moritz Halbritter
* @author Jonatan Ivanov
* @since 3.0.0
*/
@AutoConfiguration
@ConditionalOnClass(Tracer.class)
@ConditionalOnBean(Tracer.class)
public class MicrometerTracingAutoConfiguration {
/**
@ -60,7 +71,6 @@ public class MicrometerTracingAutoConfiguration {
@Bean
@ConditionalOnMissingBean
@ConditionalOnBean(Tracer.class)
@Order(DEFAULT_TRACING_OBSERVATION_HANDLER_ORDER)
public DefaultTracingObservationHandler defaultTracingObservationHandler(Tracer tracer) {
return new DefaultTracingObservationHandler(tracer);
@ -68,7 +78,7 @@ public class MicrometerTracingAutoConfiguration {
@Bean
@ConditionalOnMissingBean
@ConditionalOnBean({ Tracer.class, Propagator.class })
@ConditionalOnBean(Propagator.class)
@Order(SENDER_TRACING_OBSERVATION_HANDLER_ORDER)
public PropagatingSenderTracingObservationHandler<?> propagatingSenderTracingObservationHandler(Tracer tracer,
Propagator propagator) {
@ -77,11 +87,39 @@ public class MicrometerTracingAutoConfiguration {
@Bean
@ConditionalOnMissingBean
@ConditionalOnBean({ Tracer.class, Propagator.class })
@ConditionalOnBean(Propagator.class)
@Order(RECEIVER_TRACING_OBSERVATION_HANDLER_ORDER)
public PropagatingReceiverTracingObservationHandler<?> propagatingReceiverTracingObservationHandler(Tracer tracer,
Propagator propagator) {
return new PropagatingReceiverTracingObservationHandler<>(tracer, propagator);
}
@Configuration(proxyBeanMethods = false)
@ConditionalOnClass(Advice.class)
static class SpanAspectConfiguration {
@Bean
@ConditionalOnMissingBean
DefaultNewSpanParser newSpanParser() {
return new DefaultNewSpanParser();
}
@Bean
@ConditionalOnMissingBean
ImperativeMethodInvocationProcessor imperativeMethodInvocationProcessor(NewSpanParser newSpanParser,
Tracer tracer, ObjectProvider<SpanTagAnnotationHandler> spanTagAnnotationHandler) {
ImperativeMethodInvocationProcessor methodInvocationProcessor = new ImperativeMethodInvocationProcessor(
newSpanParser, tracer);
spanTagAnnotationHandler.ifAvailable(methodInvocationProcessor::setSpanTagAnnotationHandler);
return methodInvocationProcessor;
}
@Bean
@ConditionalOnMissingBean
SpanAspect spanAspect(MethodInvocationProcessor methodInvocationProcessor) {
return new SpanAspect(methodInvocationProcessor);
}
}
}

@ -19,18 +19,27 @@ package org.springframework.boot.actuate.autoconfigure.tracing;
import java.util.List;
import io.micrometer.tracing.Tracer;
import io.micrometer.tracing.annotation.DefaultNewSpanParser;
import io.micrometer.tracing.annotation.ImperativeMethodInvocationProcessor;
import io.micrometer.tracing.annotation.MethodInvocationProcessor;
import io.micrometer.tracing.annotation.NewSpanParser;
import io.micrometer.tracing.annotation.SpanAspect;
import io.micrometer.tracing.annotation.SpanTagAnnotationHandler;
import io.micrometer.tracing.handler.DefaultTracingObservationHandler;
import io.micrometer.tracing.handler.PropagatingReceiverTracingObservationHandler;
import io.micrometer.tracing.handler.PropagatingSenderTracingObservationHandler;
import io.micrometer.tracing.handler.TracingObservationHandler;
import io.micrometer.tracing.propagation.Propagator;
import org.aspectj.weaver.Advice;
import org.junit.jupiter.api.Test;
import org.springframework.boot.autoconfigure.AutoConfigurations;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.test.context.FilteredClassLoader;
import org.springframework.boot.test.context.runner.ApplicationContextRunner;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.test.util.ReflectionTestUtils;
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.Mockito.mock;
@ -39,6 +48,7 @@ import static org.mockito.Mockito.mock;
* Tests for {@link MicrometerTracingAutoConfiguration}.
*
* @author Moritz Halbritter
* @author Jonatan Ivanov
*/
class MicrometerTracingAutoConfigurationTests {
@ -52,6 +62,9 @@ class MicrometerTracingAutoConfigurationTests {
assertThat(context).hasSingleBean(DefaultTracingObservationHandler.class);
assertThat(context).hasSingleBean(PropagatingReceiverTracingObservationHandler.class);
assertThat(context).hasSingleBean(PropagatingSenderTracingObservationHandler.class);
assertThat(context).hasSingleBean(DefaultNewSpanParser.class);
assertThat(context).hasSingleBean(ImperativeMethodInvocationProcessor.class);
assertThat(context).hasSingleBean(SpanAspect.class);
});
}
@ -75,14 +88,21 @@ class MicrometerTracingAutoConfigurationTests {
@Test
void shouldBackOffOnCustomBeans() {
this.contextRunner.withUserConfiguration(CustomConfiguration.class).run((context) -> {
assertThat(context).hasBean("customDefaultTracingObservationHandler");
assertThat(context).hasSingleBean(DefaultTracingObservationHandler.class);
assertThat(context).hasBean("customPropagatingReceiverTracingObservationHandler");
assertThat(context).hasSingleBean(PropagatingReceiverTracingObservationHandler.class);
assertThat(context).hasBean("customPropagatingSenderTracingObservationHandler");
assertThat(context).hasSingleBean(PropagatingSenderTracingObservationHandler.class);
});
this.contextRunner.withUserConfiguration(TracerConfiguration.class, CustomConfiguration.class)
.run((context) -> {
assertThat(context).hasBean("customDefaultTracingObservationHandler");
assertThat(context).hasSingleBean(DefaultTracingObservationHandler.class);
assertThat(context).hasBean("customPropagatingReceiverTracingObservationHandler");
assertThat(context).hasSingleBean(PropagatingReceiverTracingObservationHandler.class);
assertThat(context).hasBean("customPropagatingSenderTracingObservationHandler");
assertThat(context).hasSingleBean(PropagatingSenderTracingObservationHandler.class);
assertThat(context).hasBean("customDefaultNewSpanParser");
assertThat(context).hasSingleBean(DefaultNewSpanParser.class);
assertThat(context).hasBean("customImperativeMethodInvocationProcessor");
assertThat(context).hasSingleBean(ImperativeMethodInvocationProcessor.class);
assertThat(context).hasBean("customSpanAspect");
assertThat(context).hasSingleBean(SpanAspect.class);
});
}
@Test
@ -91,6 +111,9 @@ class MicrometerTracingAutoConfigurationTests {
assertThat(context).doesNotHaveBean(DefaultTracingObservationHandler.class);
assertThat(context).doesNotHaveBean(PropagatingReceiverTracingObservationHandler.class);
assertThat(context).doesNotHaveBean(PropagatingSenderTracingObservationHandler.class);
assertThat(context).doesNotHaveBean(DefaultNewSpanParser.class);
assertThat(context).doesNotHaveBean(ImperativeMethodInvocationProcessor.class);
assertThat(context).doesNotHaveBean(SpanAspect.class);
});
}
@ -100,17 +123,47 @@ class MicrometerTracingAutoConfigurationTests {
assertThat(context).doesNotHaveBean(DefaultTracingObservationHandler.class);
assertThat(context).doesNotHaveBean(PropagatingReceiverTracingObservationHandler.class);
assertThat(context).doesNotHaveBean(PropagatingSenderTracingObservationHandler.class);
assertThat(context).doesNotHaveBean(DefaultNewSpanParser.class);
assertThat(context).doesNotHaveBean(ImperativeMethodInvocationProcessor.class);
assertThat(context).doesNotHaveBean(SpanAspect.class);
});
}
@Test
void shouldNotSupplyBeansIfAspectjIsMissing() {
this.contextRunner.withUserConfiguration(TracerConfiguration.class)
.withClassLoader(new FilteredClassLoader(Advice.class))
.run((context) -> {
assertThat(context).doesNotHaveBean(DefaultNewSpanParser.class);
assertThat(context).doesNotHaveBean(ImperativeMethodInvocationProcessor.class);
assertThat(context).doesNotHaveBean(SpanAspect.class);
});
}
@Test
void shouldNotSupplyBeansIfPropagatorIsMissing() {
this.contextRunner.withUserConfiguration(TracerConfiguration.class).run((context) -> {
assertThat(context).doesNotHaveBean(PropagatingSenderTracingObservationHandler.class);
assertThat(context).doesNotHaveBean(PropagatingReceiverTracingObservationHandler.class);
assertThat(context).hasSingleBean(DefaultNewSpanParser.class);
assertThat(context).hasSingleBean(ImperativeMethodInvocationProcessor.class);
assertThat(context).hasSingleBean(SpanAspect.class);
});
}
@Test
void shouldConfigureSpanTagAnnotationHandler() {
this.contextRunner.withUserConfiguration(TracerConfiguration.class, SpanTagAnnotationHandlerConfiguration.class)
.run((context) -> {
assertThat(context).hasSingleBean(DefaultNewSpanParser.class);
assertThat(context).hasSingleBean(SpanAspect.class);
assertThat(ReflectionTestUtils.getField(context.getBean(ImperativeMethodInvocationProcessor.class),
"spanTagAnnotationHandler"))
.isSameAs(context.getBean(SpanTagAnnotationHandler.class));
});
}
@Configuration(proxyBeanMethods = false)
private static class TracerConfiguration {
@ -149,6 +202,34 @@ class MicrometerTracingAutoConfigurationTests {
return mock(PropagatingSenderTracingObservationHandler.class);
}
@Bean
DefaultNewSpanParser customDefaultNewSpanParser() {
return new DefaultNewSpanParser();
}
@Bean
@ConditionalOnMissingBean
ImperativeMethodInvocationProcessor customImperativeMethodInvocationProcessor(NewSpanParser newSpanParser,
Tracer tracer) {
return new ImperativeMethodInvocationProcessor(newSpanParser, tracer);
}
@Bean
@ConditionalOnMissingBean
SpanAspect customSpanAspect(MethodInvocationProcessor methodInvocationProcessor) {
return new SpanAspect(methodInvocationProcessor);
}
}
@Configuration(proxyBeanMethods = false)
private static class SpanTagAnnotationHandlerConfiguration {
@Bean
SpanTagAnnotationHandler spanTagAnnotationHandler() {
return new SpanTagAnnotationHandler((aClass) -> null, (aClass) -> null);
}
}
}

Loading…
Cancel
Save