Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -32,20 +32,16 @@
import zipkin2.reporter.SpanBytesEncoder;
import zipkin2.reporter.brave.AsyncZipkinSpanHandler;
import zipkin2.reporter.brave.MutableSpanBytesEncoder;
import zipkin2.reporter.urlconnection.URLConnectionSender;

import org.springframework.beans.factory.ObjectProvider;
import org.springframework.boot.actuate.autoconfigure.tracing.ConditionalOnEnabledTracing;
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.boot.web.client.RestTemplateBuilder;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
import org.springframework.web.client.RestTemplate;
import org.springframework.web.reactive.function.client.WebClient;

/**
* Configurations for Zipkin. Those are imported by {@link ZipkinAutoConfiguration}.
Expand All @@ -56,99 +52,11 @@
class ZipkinConfigurations {

@Configuration(proxyBeanMethods = false)
@Import({ UrlConnectionSenderConfiguration.class, WebClientSenderConfiguration.class,
RestTemplateSenderConfiguration.class, HttpClientSenderConfiguration.class })
@Import({ HttpClientSenderConfiguration.class })
static class SenderConfiguration {

}

@Configuration(proxyBeanMethods = false)
@ConditionalOnClass(URLConnectionSender.class)
@EnableConfigurationProperties(ZipkinProperties.class)
static class UrlConnectionSenderConfiguration {

@Bean
@ConditionalOnMissingBean(BytesMessageSender.class)
URLConnectionSender urlConnectionSender(ZipkinProperties properties, Encoding encoding,
ObjectProvider<ZipkinConnectionDetails> connectionDetailsProvider,
ObjectProvider<HttpEndpointSupplier.Factory> endpointSupplierFactoryProvider) {
ZipkinConnectionDetails connectionDetails = connectionDetailsProvider
.getIfAvailable(() -> new PropertiesZipkinConnectionDetails(properties));
HttpEndpointSupplier.Factory endpointSupplierFactory = endpointSupplierFactoryProvider
.getIfAvailable(HttpEndpointSuppliers::constantFactory);
URLConnectionSender.Builder builder = URLConnectionSender.newBuilder();
builder.connectTimeout((int) properties.getConnectTimeout().toMillis());
builder.readTimeout((int) properties.getReadTimeout().toMillis());
builder.endpointSupplierFactory(endpointSupplierFactory);
builder.endpoint(connectionDetails.getSpanEndpoint());
builder.encoding(encoding);
return builder.build();
}

}

@Configuration(proxyBeanMethods = false)
@ConditionalOnClass(RestTemplate.class)
@EnableConfigurationProperties(ZipkinProperties.class)
static class RestTemplateSenderConfiguration {

@Bean
@ConditionalOnMissingBean(BytesMessageSender.class)
@SuppressWarnings({ "deprecation", "removal" })
ZipkinRestTemplateSender restTemplateSender(ZipkinProperties properties, Encoding encoding,
ObjectProvider<ZipkinRestTemplateBuilderCustomizer> customizers,
ObjectProvider<ZipkinConnectionDetails> connectionDetailsProvider,
ObjectProvider<HttpEndpointSupplier.Factory> endpointSupplierFactoryProvider) {
ZipkinConnectionDetails connectionDetails = connectionDetailsProvider
.getIfAvailable(() -> new PropertiesZipkinConnectionDetails(properties));
HttpEndpointSupplier.Factory endpointSupplierFactory = endpointSupplierFactoryProvider
.getIfAvailable(HttpEndpointSuppliers::constantFactory);
RestTemplateBuilder restTemplateBuilder = new RestTemplateBuilder()
.setConnectTimeout(properties.getConnectTimeout())
.setReadTimeout(properties.getReadTimeout());
restTemplateBuilder = applyCustomizers(restTemplateBuilder, customizers);
return new ZipkinRestTemplateSender(encoding, endpointSupplierFactory, connectionDetails.getSpanEndpoint(),
restTemplateBuilder.build());
}

@SuppressWarnings({ "deprecation", "removal" })
private RestTemplateBuilder applyCustomizers(RestTemplateBuilder restTemplateBuilder,
ObjectProvider<ZipkinRestTemplateBuilderCustomizer> customizers) {
Iterable<ZipkinRestTemplateBuilderCustomizer> orderedCustomizers = () -> customizers.orderedStream()
.iterator();
RestTemplateBuilder currentBuilder = restTemplateBuilder;
for (ZipkinRestTemplateBuilderCustomizer customizer : orderedCustomizers) {
currentBuilder = customizer.customize(currentBuilder);
}
return currentBuilder;
}

}

@Configuration(proxyBeanMethods = false)
@ConditionalOnClass(WebClient.class)
@EnableConfigurationProperties(ZipkinProperties.class)
static class WebClientSenderConfiguration {

@Bean
@ConditionalOnMissingBean(BytesMessageSender.class)
@SuppressWarnings({ "deprecation", "removal" })
ZipkinWebClientSender webClientSender(ZipkinProperties properties, Encoding encoding,
ObjectProvider<ZipkinWebClientBuilderCustomizer> customizers,
ObjectProvider<ZipkinConnectionDetails> connectionDetailsProvider,
ObjectProvider<HttpEndpointSupplier.Factory> endpointSupplierFactoryProvider) {
ZipkinConnectionDetails connectionDetails = connectionDetailsProvider
.getIfAvailable(() -> new PropertiesZipkinConnectionDetails(properties));
HttpEndpointSupplier.Factory endpointSupplierFactory = endpointSupplierFactoryProvider
.getIfAvailable(HttpEndpointSuppliers::constantFactory);
WebClient.Builder builder = WebClient.builder();
customizers.orderedStream().forEach((customizer) -> customizer.customize(builder));
return new ZipkinWebClientSender(encoding, endpointSupplierFactory, connectionDetails.getSpanEndpoint(),
builder.build(), properties.getConnectTimeout().plus(properties.getReadTimeout()));
}

}

@Configuration(proxyBeanMethods = false)
@ConditionalOnClass(HttpClient.class)
@EnableConfigurationProperties(ZipkinProperties.class)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,14 +16,6 @@

package org.springframework.boot.actuate.autoconfigure.tracing.zipkin;

import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.List;
import java.util.concurrent.TimeUnit;

import okhttp3.mockwebserver.MockResponse;
import okhttp3.mockwebserver.MockWebServer;
import okhttp3.mockwebserver.RecordedRequest;
import org.junit.jupiter.api.Test;
import org.mockito.ArgumentMatchers;
import zipkin2.reporter.BytesMessageSender;
Expand All @@ -36,10 +28,8 @@
import org.springframework.boot.test.context.runner.ApplicationContextRunner;
import org.springframework.boot.test.context.runner.ReactiveWebApplicationContextRunner;
import org.springframework.boot.test.context.runner.WebApplicationContextRunner;
import org.springframework.boot.web.client.RestTemplateBuilder;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.reactive.function.client.WebClient;

import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.BDDMockito.then;
Expand All @@ -64,11 +54,7 @@ class ZipkinConfigurationsSenderConfigurationTests {

@Test
void shouldSupplyBeans() {
this.contextRunner.run((context) -> {
assertThat(context).hasSingleBean(BytesMessageSender.class);
assertThat(context).hasSingleBean(URLConnectionSender.class);
assertThat(context).doesNotHaveBean(ZipkinRestTemplateSender.class);
});
this.contextRunner.run((context) -> assertThat(context).hasSingleBean(BytesMessageSender.class));
}

@Test
Expand All @@ -85,83 +71,6 @@ void shouldUseHttpClientIfUrlSenderIsNotAvailable() {
});
}

@Test
void shouldPreferWebClientSenderIfWebApplicationIsReactiveAndUrlSenderIsNotAvailable() {
this.reactiveContextRunner.withUserConfiguration(RestTemplateConfiguration.class, WebClientConfiguration.class)
.withClassLoader(new FilteredClassLoader("zipkin2.reporter.urlconnection"))
.run((context) -> {
assertThat(context).doesNotHaveBean(URLConnectionSender.class);
assertThat(context).hasSingleBean(BytesMessageSender.class);
assertThat(context).hasSingleBean(ZipkinWebClientSender.class);
then(context.getBean(ZipkinWebClientBuilderCustomizer.class)).should()
.customize(ArgumentMatchers.any());
});
}

@Test
void shouldPreferWebClientSenderIfWebApplicationIsServletAndUrlSenderIsNotAvailable() {
this.servletContextRunner.withUserConfiguration(RestTemplateConfiguration.class, WebClientConfiguration.class)
.withClassLoader(new FilteredClassLoader("zipkin2.reporter.urlconnection"))
.run((context) -> {
assertThat(context).doesNotHaveBean(URLConnectionSender.class);
assertThat(context).hasSingleBean(BytesMessageSender.class);
assertThat(context).hasSingleBean(ZipkinWebClientSender.class);
});
}

@Test
void shouldPreferWebClientInNonWebApplicationAndUrlConnectionSenderIsNotAvailable() {
this.contextRunner.withUserConfiguration(RestTemplateConfiguration.class, WebClientConfiguration.class)
.withClassLoader(new FilteredClassLoader("zipkin2.reporter.urlconnection"))
.run((context) -> {
assertThat(context).doesNotHaveBean(URLConnectionSender.class);
assertThat(context).hasSingleBean(BytesMessageSender.class);
assertThat(context).hasSingleBean(ZipkinWebClientSender.class);
});
}

@Test
void willUseRestTemplateInNonWebApplicationIfUrlConnectionSenderAndWebClientAreNotAvailable() {
this.contextRunner.withUserConfiguration(RestTemplateConfiguration.class)
.withClassLoader(new FilteredClassLoader(URLConnectionSender.class, WebClient.class))
.run((context) -> {
assertThat(context).doesNotHaveBean(URLConnectionSender.class);
assertThat(context).hasSingleBean(BytesMessageSender.class);
assertThat(context).hasSingleBean(ZipkinRestTemplateSender.class);
});
}

@Test
void willUseRestTemplateInServletWebApplicationIfUrlConnectionSenderAndWebClientNotAvailable() {
this.servletContextRunner.withUserConfiguration(RestTemplateConfiguration.class)
.withClassLoader(new FilteredClassLoader(URLConnectionSender.class, WebClient.class))
.run((context) -> {
assertThat(context).doesNotHaveBean(URLConnectionSender.class);
assertThat(context).hasSingleBean(BytesMessageSender.class);
assertThat(context).hasSingleBean(ZipkinRestTemplateSender.class);
});
}

@Test
void willUseRestTemplateInReactiveWebApplicationIfUrlConnectionSenderAndWebClientAreNotAvailable() {
this.reactiveContextRunner.withUserConfiguration(RestTemplateConfiguration.class)
.withClassLoader(new FilteredClassLoader(URLConnectionSender.class, WebClient.class))
.run((context) -> {
assertThat(context).doesNotHaveBean(URLConnectionSender.class);
assertThat(context).hasSingleBean(BytesMessageSender.class);
assertThat(context).hasSingleBean(ZipkinRestTemplateSender.class);
});
}

@Test
void shouldNotUseWebClientSenderIfNoBuilderIsAvailable() {
this.reactiveContextRunner.run((context) -> {
assertThat(context).doesNotHaveBean(ZipkinWebClientSender.class);
assertThat(context).hasSingleBean(BytesMessageSender.class);
assertThat(context).hasSingleBean(URLConnectionSender.class);
});
}

@Test
void shouldBackOffOnCustomBeans() {
this.contextRunner.withUserConfiguration(CustomConfiguration.class).run((context) -> {
Expand All @@ -170,71 +79,6 @@ void shouldBackOffOnCustomBeans() {
});
}

@Test
void shouldApplyZipkinRestTemplateBuilderCustomizers() throws IOException {
try (MockWebServer mockWebServer = new MockWebServer()) {
mockWebServer.enqueue(new MockResponse().setResponseCode(204));
this.reactiveContextRunner
.withPropertyValues("management.zipkin.tracing.endpoint=" + mockWebServer.url("/"))
.withUserConfiguration(RestTemplateConfiguration.class)
.withClassLoader(new FilteredClassLoader(URLConnectionSender.class, WebClient.class))
.run((context) -> {
assertThat(context).hasSingleBean(ZipkinRestTemplateSender.class);
ZipkinRestTemplateSender sender = context.getBean(ZipkinRestTemplateSender.class);
sender.send(List.of("spans".getBytes(StandardCharsets.UTF_8)));
RecordedRequest recordedRequest = mockWebServer.takeRequest(1, TimeUnit.SECONDS);
assertThat(recordedRequest).isNotNull();
assertThat(recordedRequest.getHeaders().get("x-dummy")).isEqualTo("dummy");
});
}
}

@Test
void shouldUseCustomHttpEndpointSupplierFactory() {
this.contextRunner.withUserConfiguration(CustomHttpEndpointSupplierFactoryConfiguration.class)
.run((context) -> assertThat(context.getBean(URLConnectionSender.class))
.extracting("delegate.endpointSupplier")
.isInstanceOf(CustomHttpEndpointSupplier.class));
}

@Test
void shouldUseCustomHttpEndpointSupplierFactoryWhenReactive() {
this.reactiveContextRunner.withUserConfiguration(WebClientConfiguration.class)
.withClassLoader(new FilteredClassLoader(URLConnectionSender.class))
.withUserConfiguration(CustomHttpEndpointSupplierFactoryConfiguration.class)
.run((context) -> assertThat(context.getBean(ZipkinWebClientSender.class)).extracting("endpointSupplier")
.isInstanceOf(CustomHttpEndpointSupplier.class));
}

@Test
void shouldUseCustomHttpEndpointSupplierFactoryWhenRestTemplate() {
this.contextRunner.withUserConfiguration(RestTemplateConfiguration.class)
.withClassLoader(new FilteredClassLoader(URLConnectionSender.class, WebClient.class))
.withUserConfiguration(CustomHttpEndpointSupplierFactoryConfiguration.class)
.run((context) -> assertThat(context.getBean(ZipkinRestTemplateSender.class)).extracting("endpointSupplier")
.isInstanceOf(CustomHttpEndpointSupplier.class));
}

@Configuration(proxyBeanMethods = false)
private static final class RestTemplateConfiguration {

@Bean
ZipkinRestTemplateBuilderCustomizer zipkinRestTemplateBuilderCustomizer() {
return new DummyZipkinRestTemplateBuilderCustomizer();
}

}

@Configuration(proxyBeanMethods = false)
private static final class WebClientConfiguration {

@Bean
ZipkinWebClientBuilderCustomizer webClientBuilder() {
return mock(ZipkinWebClientBuilderCustomizer.class);
}

}

@Configuration(proxyBeanMethods = false)
private static final class HttpClientConfiguration {

Expand All @@ -255,15 +99,6 @@ BytesMessageSender customSender() {

}

private static final class DummyZipkinRestTemplateBuilderCustomizer implements ZipkinRestTemplateBuilderCustomizer {

@Override
public RestTemplateBuilder customize(RestTemplateBuilder restTemplateBuilder) {
return restTemplateBuilder.defaultHeader("x-dummy", "dummy");
}

}

@Configuration(proxyBeanMethods = false)
private static final class CustomHttpEndpointSupplierFactoryConfiguration {

Expand Down