Auto-configure CompositeSpanHandler with Brave
Closes gh-32753
This commit is contained in:
@@ -53,7 +53,11 @@ import io.micrometer.tracing.brave.bridge.BraveHttpClientHandler;
|
|||||||
import io.micrometer.tracing.brave.bridge.BraveHttpServerHandler;
|
import io.micrometer.tracing.brave.bridge.BraveHttpServerHandler;
|
||||||
import io.micrometer.tracing.brave.bridge.BravePropagator;
|
import io.micrometer.tracing.brave.bridge.BravePropagator;
|
||||||
import io.micrometer.tracing.brave.bridge.BraveTracer;
|
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.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.beans.factory.ObjectProvider;
|
||||||
import org.springframework.boot.autoconfigure.AutoConfiguration;
|
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.boot.context.properties.EnableConfigurationProperties;
|
||||||
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.core.Ordered;
|
||||||
import org.springframework.core.annotation.Order;
|
import org.springframework.core.annotation.Order;
|
||||||
import org.springframework.core.env.Environment;
|
import org.springframework.core.env.Environment;
|
||||||
|
|
||||||
@@ -87,6 +92,15 @@ public class BraveAutoConfiguration {
|
|||||||
*/
|
*/
|
||||||
private static final String DEFAULT_APPLICATION_NAME = "application";
|
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
|
@Bean
|
||||||
@ConditionalOnMissingBean
|
@ConditionalOnMissingBean
|
||||||
public Tracing braveTracing(Environment environment, List<SpanHandler> spanHandlers,
|
public Tracing braveTracing(Environment environment, List<SpanHandler> spanHandlers,
|
||||||
|
|||||||
@@ -16,11 +16,14 @@
|
|||||||
|
|
||||||
package org.springframework.boot.actuate.autoconfigure.tracing;
|
package org.springframework.boot.actuate.autoconfigure.tracing;
|
||||||
|
|
||||||
|
import java.util.Collections;
|
||||||
|
|
||||||
import brave.Span;
|
import brave.Span;
|
||||||
import brave.Tracer;
|
import brave.Tracer;
|
||||||
import brave.Tracing;
|
import brave.Tracing;
|
||||||
import brave.baggage.BaggagePropagation;
|
import brave.baggage.BaggagePropagation;
|
||||||
import brave.baggage.CorrelationScopeConfig.SingleCorrelationField;
|
import brave.baggage.CorrelationScopeConfig.SingleCorrelationField;
|
||||||
|
import brave.handler.SpanHandler;
|
||||||
import brave.http.HttpClientHandler;
|
import brave.http.HttpClientHandler;
|
||||||
import brave.http.HttpClientRequest;
|
import brave.http.HttpClientRequest;
|
||||||
import brave.http.HttpClientResponse;
|
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.BraveHttpClientHandler;
|
||||||
import io.micrometer.tracing.brave.bridge.BraveHttpServerHandler;
|
import io.micrometer.tracing.brave.bridge.BraveHttpServerHandler;
|
||||||
import io.micrometer.tracing.brave.bridge.BraveTracer;
|
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.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.assertj.core.api.InstanceOfAssertFactories;
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
import org.mockito.Answers;
|
import org.mockito.Answers;
|
||||||
|
|
||||||
|
import org.springframework.boot.actuate.autoconfigure.tracing.BraveAutoConfigurationTests.SpanHandlerConfiguration.AdditionalSpanHandler;
|
||||||
import org.springframework.boot.autoconfigure.AutoConfigurations;
|
import org.springframework.boot.autoconfigure.AutoConfigurations;
|
||||||
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.core.annotation.Order;
|
||||||
|
|
||||||
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;
|
||||||
@@ -81,6 +90,7 @@ class BraveAutoConfigurationTests {
|
|||||||
assertThat(context).hasSingleBean(BraveTracer.class);
|
assertThat(context).hasSingleBean(BraveTracer.class);
|
||||||
assertThat(context).hasSingleBean(BraveHttpServerHandler.class);
|
assertThat(context).hasSingleBean(BraveHttpServerHandler.class);
|
||||||
assertThat(context).hasSingleBean(BraveHttpClientHandler.class);
|
assertThat(context).hasSingleBean(BraveHttpClientHandler.class);
|
||||||
|
assertThat(context).hasSingleBean(CompositeSpanHandler.class);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -115,6 +125,8 @@ class BraveAutoConfigurationTests {
|
|||||||
assertThat(context).hasSingleBean(HttpServerHandler.class);
|
assertThat(context).hasSingleBean(HttpServerHandler.class);
|
||||||
assertThat(context).hasBean("customHttpClientHandler");
|
assertThat(context).hasBean("customHttpClientHandler");
|
||||||
assertThat(context).hasSingleBean(HttpClientHandler.class);
|
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)
|
@Configuration(proxyBeanMethods = false)
|
||||||
private static class CustomConfiguration {
|
private static class CustomConfiguration {
|
||||||
|
|
||||||
@@ -302,6 +416,11 @@ class BraveAutoConfigurationTests {
|
|||||||
return mock(BraveHttpClientHandler.class);
|
return mock(BraveHttpClientHandler.class);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
CompositeSpanHandler customCompositeSpanHandler() {
|
||||||
|
return new CompositeSpanHandler(Collections.emptyList(), Collections.emptyList(), Collections.emptyList());
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user