Auto-configure CompositeSpanHandler with Brave

Closes gh-32753
pull/33505/head
Andy Wilkinson 2 years ago
parent ff16f6d6c6
commit 4700a00d94

@ -53,7 +53,11 @@ import io.micrometer.tracing.brave.bridge.BraveHttpClientHandler;
import io.micrometer.tracing.brave.bridge.BraveHttpServerHandler;
import io.micrometer.tracing.brave.bridge.BravePropagator;
import io.micrometer.tracing.brave.bridge.BraveTracer;
import io.micrometer.tracing.brave.bridge.CompositeSpanHandler;
import io.micrometer.tracing.brave.bridge.W3CPropagation;
import io.micrometer.tracing.exporter.SpanExportingPredicate;
import io.micrometer.tracing.exporter.SpanFilter;
import io.micrometer.tracing.exporter.SpanReporter;
import org.springframework.beans.factory.ObjectProvider;
import org.springframework.boot.autoconfigure.AutoConfiguration;
@ -64,6 +68,7 @@ import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.Ordered;
import org.springframework.core.annotation.Order;
import org.springframework.core.env.Environment;
@ -87,6 +92,15 @@ public class BraveAutoConfiguration {
*/
private static final String DEFAULT_APPLICATION_NAME = "application";
@Bean
@ConditionalOnMissingBean
@Order(Ordered.HIGHEST_PRECEDENCE)
CompositeSpanHandler compositeSpanHandler(ObjectProvider<SpanExportingPredicate> predicates,
ObjectProvider<SpanReporter> reporters, ObjectProvider<SpanFilter> filters) {
return new CompositeSpanHandler(predicates.orderedStream().toList(), reporters.orderedStream().toList(),
filters.orderedStream().toList());
}
@Bean
@ConditionalOnMissingBean
public Tracing braveTracing(Environment environment, List<SpanHandler> spanHandlers,

@ -16,11 +16,14 @@
package org.springframework.boot.actuate.autoconfigure.tracing;
import java.util.Collections;
import brave.Span;
import brave.Tracer;
import brave.Tracing;
import brave.baggage.BaggagePropagation;
import brave.baggage.CorrelationScopeConfig.SingleCorrelationField;
import brave.handler.SpanHandler;
import brave.http.HttpClientHandler;
import brave.http.HttpClientRequest;
import brave.http.HttpClientResponse;
@ -37,16 +40,22 @@ import io.micrometer.tracing.brave.bridge.BraveBaggageManager;
import io.micrometer.tracing.brave.bridge.BraveHttpClientHandler;
import io.micrometer.tracing.brave.bridge.BraveHttpServerHandler;
import io.micrometer.tracing.brave.bridge.BraveTracer;
import io.micrometer.tracing.brave.bridge.CompositeSpanHandler;
import io.micrometer.tracing.brave.bridge.W3CPropagation;
import io.micrometer.tracing.exporter.SpanExportingPredicate;
import io.micrometer.tracing.exporter.SpanFilter;
import io.micrometer.tracing.exporter.SpanReporter;
import org.assertj.core.api.InstanceOfAssertFactories;
import org.junit.jupiter.api.Test;
import org.mockito.Answers;
import org.springframework.boot.actuate.autoconfigure.tracing.BraveAutoConfigurationTests.SpanHandlerConfiguration.AdditionalSpanHandler;
import org.springframework.boot.autoconfigure.AutoConfigurations;
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.core.annotation.Order;
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.Mockito.mock;
@ -81,6 +90,7 @@ class BraveAutoConfigurationTests {
assertThat(context).hasSingleBean(BraveTracer.class);
assertThat(context).hasSingleBean(BraveHttpServerHandler.class);
assertThat(context).hasSingleBean(BraveHttpClientHandler.class);
assertThat(context).hasSingleBean(CompositeSpanHandler.class);
});
}
@ -115,6 +125,8 @@ class BraveAutoConfigurationTests {
assertThat(context).hasSingleBean(HttpServerHandler.class);
assertThat(context).hasBean("customHttpClientHandler");
assertThat(context).hasSingleBean(HttpClientHandler.class);
assertThat(context).hasBean("customCompositeSpanHandler");
assertThat(context).hasSingleBean(CompositeSpanHandler.class);
});
}
@ -237,6 +249,108 @@ class BraveAutoConfigurationTests {
});
}
@Test
@SuppressWarnings("rawtypes")
void compositeSpanHandlerShouldBeFirstSpanHandler() {
this.contextRunner.withUserConfiguration(SpanHandlerConfiguration.class).run((context) -> {
Tracing tracing = context.getBean(Tracing.class);
assertThat(tracing).extracting("tracer.spanHandler.delegate.handlers")
.asInstanceOf(InstanceOfAssertFactories.array(SpanHandler[].class))
.extracting((handler) -> (Class) handler.getClass())
.containsExactly(CompositeSpanHandler.class, AdditionalSpanHandler.class);
});
}
@Test
void compositeSpanHandlerUsesFilterPredicateAndReportersInOrder() {
this.contextRunner.withUserConfiguration(CompositeSpanHandlerComponentsConfiguration.class).run((context) -> {
CompositeSpanHandlerComponentsConfiguration components = context
.getBean(CompositeSpanHandlerComponentsConfiguration.class);
CompositeSpanHandler composite = context.getBean(CompositeSpanHandler.class);
assertThat(composite).extracting("spanFilters").asList().containsExactly(components.filter1,
components.filter2);
assertThat(composite).extracting("filters").asList().containsExactly(components.predicate2,
components.predicate1);
assertThat(composite).extracting("reporters").asList().containsExactly(components.reporter1,
components.reporter3, components.reporter2);
});
}
@Configuration(proxyBeanMethods = false)
static class CompositeSpanHandlerComponentsConfiguration {
private final SpanFilter filter1 = mock(SpanFilter.class);
private final SpanFilter filter2 = mock(SpanFilter.class);
private final SpanExportingPredicate predicate1 = mock(SpanExportingPredicate.class);
private final SpanExportingPredicate predicate2 = mock(SpanExportingPredicate.class);
private final SpanReporter reporter1 = mock(SpanReporter.class);
private final SpanReporter reporter2 = mock(SpanReporter.class);
private final SpanReporter reporter3 = mock(SpanReporter.class);
@Bean
@Order(1)
SpanFilter filter1() {
return this.filter1;
}
@Bean
@Order(2)
SpanFilter filter2() {
return this.filter2;
}
@Bean
@Order(2)
SpanExportingPredicate predicate1() {
return this.predicate1;
}
@Bean
@Order(1)
SpanExportingPredicate predicate2() {
return this.predicate2;
}
@Bean
@Order(1)
SpanReporter reporter1() {
return this.reporter1;
}
@Bean
@Order(3)
SpanReporter reporter2() {
return this.reporter2;
}
@Bean
@Order(2)
SpanReporter reporter3() {
return this.reporter3;
}
}
@Configuration(proxyBeanMethods = false)
static class SpanHandlerConfiguration {
@Bean
SpanHandler additionalSpanHandler() {
return new AdditionalSpanHandler();
}
static class AdditionalSpanHandler extends SpanHandler {
}
}
@Configuration(proxyBeanMethods = false)
private static class CustomConfiguration {
@ -302,6 +416,11 @@ class BraveAutoConfigurationTests {
return mock(BraveHttpClientHandler.class);
}
@Bean
CompositeSpanHandler customCompositeSpanHandler() {
return new CompositeSpanHandler(Collections.emptyList(), Collections.emptyList(), Collections.emptyList());
}
}
}

Loading…
Cancel
Save