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; package org.springframework.boot.actuate.autoconfigure.tracing;
import io.micrometer.tracing.Tracer; 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.DefaultTracingObservationHandler;
import io.micrometer.tracing.handler.PropagatingReceiverTracingObservationHandler; import io.micrometer.tracing.handler.PropagatingReceiverTracingObservationHandler;
import io.micrometer.tracing.handler.PropagatingSenderTracingObservationHandler; import io.micrometer.tracing.handler.PropagatingSenderTracingObservationHandler;
import io.micrometer.tracing.propagation.Propagator; 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.AutoConfiguration;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration; import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean; import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.Ordered; import org.springframework.core.Ordered;
import org.springframework.core.annotation.Order; 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. * {@link EnableAutoConfiguration Auto-configuration} for the Micrometer Tracing API.
* *
* @author Moritz Halbritter * @author Moritz Halbritter
* @author Jonatan Ivanov
* @since 3.0.0 * @since 3.0.0
*/ */
@AutoConfiguration @AutoConfiguration
@ConditionalOnClass(Tracer.class) @ConditionalOnClass(Tracer.class)
@ConditionalOnBean(Tracer.class)
public class MicrometerTracingAutoConfiguration { public class MicrometerTracingAutoConfiguration {
/** /**
@ -60,7 +71,6 @@ public class MicrometerTracingAutoConfiguration {
@Bean @Bean
@ConditionalOnMissingBean @ConditionalOnMissingBean
@ConditionalOnBean(Tracer.class)
@Order(DEFAULT_TRACING_OBSERVATION_HANDLER_ORDER) @Order(DEFAULT_TRACING_OBSERVATION_HANDLER_ORDER)
public DefaultTracingObservationHandler defaultTracingObservationHandler(Tracer tracer) { public DefaultTracingObservationHandler defaultTracingObservationHandler(Tracer tracer) {
return new DefaultTracingObservationHandler(tracer); return new DefaultTracingObservationHandler(tracer);
@ -68,7 +78,7 @@ public class MicrometerTracingAutoConfiguration {
@Bean @Bean
@ConditionalOnMissingBean @ConditionalOnMissingBean
@ConditionalOnBean({ Tracer.class, Propagator.class }) @ConditionalOnBean(Propagator.class)
@Order(SENDER_TRACING_OBSERVATION_HANDLER_ORDER) @Order(SENDER_TRACING_OBSERVATION_HANDLER_ORDER)
public PropagatingSenderTracingObservationHandler<?> propagatingSenderTracingObservationHandler(Tracer tracer, public PropagatingSenderTracingObservationHandler<?> propagatingSenderTracingObservationHandler(Tracer tracer,
Propagator propagator) { Propagator propagator) {
@ -77,11 +87,39 @@ public class MicrometerTracingAutoConfiguration {
@Bean @Bean
@ConditionalOnMissingBean @ConditionalOnMissingBean
@ConditionalOnBean({ Tracer.class, Propagator.class }) @ConditionalOnBean(Propagator.class)
@Order(RECEIVER_TRACING_OBSERVATION_HANDLER_ORDER) @Order(RECEIVER_TRACING_OBSERVATION_HANDLER_ORDER)
public PropagatingReceiverTracingObservationHandler<?> propagatingReceiverTracingObservationHandler(Tracer tracer, public PropagatingReceiverTracingObservationHandler<?> propagatingReceiverTracingObservationHandler(Tracer tracer,
Propagator propagator) { Propagator propagator) {
return new PropagatingReceiverTracingObservationHandler<>(tracer, 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 java.util.List;
import io.micrometer.tracing.Tracer; 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.DefaultTracingObservationHandler;
import io.micrometer.tracing.handler.PropagatingReceiverTracingObservationHandler; import io.micrometer.tracing.handler.PropagatingReceiverTracingObservationHandler;
import io.micrometer.tracing.handler.PropagatingSenderTracingObservationHandler; import io.micrometer.tracing.handler.PropagatingSenderTracingObservationHandler;
import io.micrometer.tracing.handler.TracingObservationHandler; import io.micrometer.tracing.handler.TracingObservationHandler;
import io.micrometer.tracing.propagation.Propagator; import io.micrometer.tracing.propagation.Propagator;
import org.aspectj.weaver.Advice;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
import org.springframework.boot.autoconfigure.AutoConfigurations; 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.FilteredClassLoader;
import org.springframework.boot.test.context.runner.ApplicationContextRunner; import org.springframework.boot.test.context.runner.ApplicationContextRunner;
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Configuration;
import org.springframework.test.util.ReflectionTestUtils;
import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.Mockito.mock; import static org.mockito.Mockito.mock;
@ -39,6 +48,7 @@ import static org.mockito.Mockito.mock;
* Tests for {@link MicrometerTracingAutoConfiguration}. * Tests for {@link MicrometerTracingAutoConfiguration}.
* *
* @author Moritz Halbritter * @author Moritz Halbritter
* @author Jonatan Ivanov
*/ */
class MicrometerTracingAutoConfigurationTests { class MicrometerTracingAutoConfigurationTests {
@ -52,6 +62,9 @@ class MicrometerTracingAutoConfigurationTests {
assertThat(context).hasSingleBean(DefaultTracingObservationHandler.class); assertThat(context).hasSingleBean(DefaultTracingObservationHandler.class);
assertThat(context).hasSingleBean(PropagatingReceiverTracingObservationHandler.class); assertThat(context).hasSingleBean(PropagatingReceiverTracingObservationHandler.class);
assertThat(context).hasSingleBean(PropagatingSenderTracingObservationHandler.class); assertThat(context).hasSingleBean(PropagatingSenderTracingObservationHandler.class);
assertThat(context).hasSingleBean(DefaultNewSpanParser.class);
assertThat(context).hasSingleBean(ImperativeMethodInvocationProcessor.class);
assertThat(context).hasSingleBean(SpanAspect.class);
}); });
} }
@ -75,13 +88,20 @@ class MicrometerTracingAutoConfigurationTests {
@Test @Test
void shouldBackOffOnCustomBeans() { void shouldBackOffOnCustomBeans() {
this.contextRunner.withUserConfiguration(CustomConfiguration.class).run((context) -> { this.contextRunner.withUserConfiguration(TracerConfiguration.class, CustomConfiguration.class)
.run((context) -> {
assertThat(context).hasBean("customDefaultTracingObservationHandler"); assertThat(context).hasBean("customDefaultTracingObservationHandler");
assertThat(context).hasSingleBean(DefaultTracingObservationHandler.class); assertThat(context).hasSingleBean(DefaultTracingObservationHandler.class);
assertThat(context).hasBean("customPropagatingReceiverTracingObservationHandler"); assertThat(context).hasBean("customPropagatingReceiverTracingObservationHandler");
assertThat(context).hasSingleBean(PropagatingReceiverTracingObservationHandler.class); assertThat(context).hasSingleBean(PropagatingReceiverTracingObservationHandler.class);
assertThat(context).hasBean("customPropagatingSenderTracingObservationHandler"); assertThat(context).hasBean("customPropagatingSenderTracingObservationHandler");
assertThat(context).hasSingleBean(PropagatingSenderTracingObservationHandler.class); 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);
}); });
} }
@ -91,6 +111,9 @@ class MicrometerTracingAutoConfigurationTests {
assertThat(context).doesNotHaveBean(DefaultTracingObservationHandler.class); assertThat(context).doesNotHaveBean(DefaultTracingObservationHandler.class);
assertThat(context).doesNotHaveBean(PropagatingReceiverTracingObservationHandler.class); assertThat(context).doesNotHaveBean(PropagatingReceiverTracingObservationHandler.class);
assertThat(context).doesNotHaveBean(PropagatingSenderTracingObservationHandler.class); assertThat(context).doesNotHaveBean(PropagatingSenderTracingObservationHandler.class);
assertThat(context).doesNotHaveBean(DefaultNewSpanParser.class);
assertThat(context).doesNotHaveBean(ImperativeMethodInvocationProcessor.class);
assertThat(context).doesNotHaveBean(SpanAspect.class);
}); });
} }
@ -100,6 +123,20 @@ class MicrometerTracingAutoConfigurationTests {
assertThat(context).doesNotHaveBean(DefaultTracingObservationHandler.class); assertThat(context).doesNotHaveBean(DefaultTracingObservationHandler.class);
assertThat(context).doesNotHaveBean(PropagatingReceiverTracingObservationHandler.class); assertThat(context).doesNotHaveBean(PropagatingReceiverTracingObservationHandler.class);
assertThat(context).doesNotHaveBean(PropagatingSenderTracingObservationHandler.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);
}); });
} }
@ -108,6 +145,22 @@ class MicrometerTracingAutoConfigurationTests {
this.contextRunner.withUserConfiguration(TracerConfiguration.class).run((context) -> { this.contextRunner.withUserConfiguration(TracerConfiguration.class).run((context) -> {
assertThat(context).doesNotHaveBean(PropagatingSenderTracingObservationHandler.class); assertThat(context).doesNotHaveBean(PropagatingSenderTracingObservationHandler.class);
assertThat(context).doesNotHaveBean(PropagatingReceiverTracingObservationHandler.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));
}); });
} }
@ -149,6 +202,34 @@ class MicrometerTracingAutoConfigurationTests {
return mock(PropagatingSenderTracingObservationHandler.class); 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