Skip to content

Commit

Permalink
Add auto-configuration for SpanAspect
Browse files Browse the repository at this point in the history
  • Loading branch information
jonatan-ivanov authored and mhalbritter committed Oct 5, 2023
1 parent cfb6ee2 commit 346db8e
Show file tree
Hide file tree
Showing 2 changed files with 130 additions and 11 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -17,28 +17,39 @@
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;

/**
* {@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 {

/**
Expand All @@ -60,15 +71,14 @@ public class MicrometerTracingAutoConfiguration {

@Bean
@ConditionalOnMissingBean
@ConditionalOnBean(Tracer.class)
@Order(DEFAULT_TRACING_OBSERVATION_HANDLER_ORDER)
public DefaultTracingObservationHandler defaultTracingObservationHandler(Tracer tracer) {
return new DefaultTracingObservationHandler(tracer);
}

@Bean
@ConditionalOnMissingBean
@ConditionalOnBean({ Tracer.class, Propagator.class })
@ConditionalOnBean(Propagator.class)
@Order(SENDER_TRACING_OBSERVATION_HANDLER_ORDER)
public PropagatingSenderTracingObservationHandler<?> propagatingSenderTracingObservationHandler(Tracer tracer,
Propagator propagator) {
Expand All @@ -77,11 +87,39 @@ public PropagatingSenderTracingObservationHandler<?> propagatingSenderTracingObs

@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);
}

}

}
Original file line number Diff line number Diff line change
Expand Up @@ -19,18 +19,27 @@
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;
Expand All @@ -39,6 +48,7 @@
* Tests for {@link MicrometerTracingAutoConfiguration}.
*
* @author Moritz Halbritter
* @author Jonatan Ivanov
*/
class MicrometerTracingAutoConfigurationTests {

Expand All @@ -52,6 +62,9 @@ void shouldSupplyBeans() {
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);
});
}

Expand All @@ -75,14 +88,21 @@ void shouldSupplyBeansInCorrectOrder() {

@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
Expand All @@ -91,6 +111,9 @@ void shouldNotSupplyBeansIfMicrometerIsMissing() {
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);
});
}

Expand All @@ -100,17 +123,47 @@ void shouldNotSupplyBeansIfTracerIsMissing() {
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 {

Expand Down Expand Up @@ -149,6 +202,34 @@ PropagatingSenderTracingObservationHandler<?> customPropagatingSenderTracingObse
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);
}

}

}

0 comments on commit 346db8e

Please sign in to comment.