Skip to content

Commit 574242b

Browse files
committed
Polish "Break cycles between Zipkin senders and HTTP client observation"
See gh-32528
1 parent b41ed44 commit 574242b

File tree

4 files changed

+152
-6
lines changed

4 files changed

+152
-6
lines changed

spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/tracing/zipkin/ZipkinConfigurations.java

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,6 @@
1616

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

19-
import java.util.List;
20-
2119
import io.opentelemetry.exporter.zipkin.ZipkinSpanExporter;
2220
import zipkin2.Span;
2321
import zipkin2.codec.BytesEncoder;
@@ -27,6 +25,7 @@
2725
import zipkin2.reporter.brave.ZipkinSpanHandler;
2826
import zipkin2.reporter.urlconnection.URLConnectionSender;
2927

28+
import org.springframework.beans.factory.ObjectProvider;
3029
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
3130
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
3231
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
@@ -76,10 +75,10 @@ static class RestTemplateSenderConfiguration {
7675
@Bean
7776
@ConditionalOnMissingBean(Sender.class)
7877
ZipkinRestTemplateSender restTemplateSender(ZipkinProperties properties,
79-
List<ZipkinRestTemplateBuilderCustomizer> customizers) {
78+
ObjectProvider<ZipkinRestTemplateBuilderCustomizer> customizers) {
8079
RestTemplateBuilder restTemplateBuilder = new RestTemplateBuilder()
8180
.setConnectTimeout(properties.getConnectTimeout()).setReadTimeout(properties.getReadTimeout());
82-
customizers.forEach((c) -> c.customize(restTemplateBuilder));
81+
customizers.orderedStream().forEach((c) -> c.customize(restTemplateBuilder));
8382
return new ZipkinRestTemplateSender(properties.getEndpoint(), restTemplateBuilder.build());
8483
}
8584

@@ -93,9 +92,9 @@ static class WebClientSenderConfiguration {
9392
@Bean
9493
@ConditionalOnMissingBean(Sender.class)
9594
ZipkinWebClientSender webClientSender(ZipkinProperties properties,
96-
List<ZipkinWebClientBuilderCustomizer> customizers) {
95+
ObjectProvider<ZipkinWebClientBuilderCustomizer> customizers) {
9796
WebClient.Builder builder = WebClient.builder();
98-
customizers.forEach((c) -> c.customize(builder));
97+
customizers.orderedStream().forEach((c) -> c.customize(builder));
9998
return new ZipkinWebClientSender(properties.getEndpoint(), builder.build());
10099
}
101100

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
/*
2+
* Copyright 2012-2022 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package org.springframework.boot.actuate.autoconfigure.tracing.zipkin;
18+
19+
import org.springframework.boot.web.client.RestTemplateBuilder;
20+
21+
/**
22+
* Callback interface that can be implemented by beans wishing to customize the
23+
* {@link RestTemplateBuilder} used to send spans to Zipkin.
24+
*
25+
* @author Marcin Grzejszczak
26+
* @since 3.0.0
27+
*/
28+
@FunctionalInterface
29+
public interface ZipkinRestTemplateBuilderCustomizer {
30+
31+
/**
32+
* Customize the rest template builder.
33+
* @param restTemplateBuilder the {@code RestTemplateBuilder} to customize
34+
*/
35+
void customize(RestTemplateBuilder restTemplateBuilder);
36+
37+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
/*
2+
* Copyright 2012-2022 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package org.springframework.boot.actuate.autoconfigure.tracing.zipkin;
18+
19+
import org.springframework.web.reactive.function.client.WebClient;
20+
import org.springframework.web.reactive.function.client.WebClient.Builder;
21+
22+
/**
23+
* Callback interface that can be implemented by beans wishing to customize the
24+
* {@link Builder} used to send spans to Zipkin.
25+
*
26+
* @author Marcin Grzejszczak
27+
* @since 3.0.0
28+
*/
29+
@FunctionalInterface
30+
public interface ZipkinWebClientBuilderCustomizer {
31+
32+
/**
33+
* Customize the web client builder.
34+
* @param webClientBuilder the {@code WebClient.Builder} to customize
35+
*/
36+
void customize(WebClient.Builder webClientBuilder);
37+
38+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
/*
2+
* Copyright 2012-2022 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package org.springframework.boot.actuate.autoconfigure.tracing.zipkin;
18+
19+
import org.junit.jupiter.api.Test;
20+
import zipkin2.reporter.urlconnection.URLConnectionSender;
21+
22+
import org.springframework.boot.actuate.autoconfigure.metrics.MetricsAutoConfiguration;
23+
import org.springframework.boot.actuate.autoconfigure.metrics.export.simple.SimpleMetricsExportAutoConfiguration;
24+
import org.springframework.boot.actuate.autoconfigure.metrics.web.client.HttpClientMetricsAutoConfiguration;
25+
import org.springframework.boot.actuate.autoconfigure.observation.ObservationAutoConfiguration;
26+
import org.springframework.boot.actuate.autoconfigure.tracing.BraveAutoConfiguration;
27+
import org.springframework.boot.actuate.autoconfigure.tracing.MicrometerTracingAutoConfiguration;
28+
import org.springframework.boot.autoconfigure.AutoConfigurations;
29+
import org.springframework.boot.autoconfigure.web.client.RestTemplateAutoConfiguration;
30+
import org.springframework.boot.autoconfigure.web.reactive.function.client.WebClientAutoConfiguration;
31+
import org.springframework.boot.test.context.FilteredClassLoader;
32+
import org.springframework.boot.test.context.assertj.ApplicationContextAssertProvider;
33+
import org.springframework.boot.test.context.runner.AbstractApplicationContextRunner;
34+
import org.springframework.boot.test.context.runner.ReactiveWebApplicationContextRunner;
35+
import org.springframework.boot.test.context.runner.WebApplicationContextRunner;
36+
import org.springframework.context.ConfigurableApplicationContext;
37+
38+
import static org.assertj.core.api.Assertions.assertThat;
39+
40+
/**
41+
* Integration tests for {@link ZipkinAutoConfiguration} and other related
42+
* auto-configurations.
43+
*
44+
* @author Andy Wilkinson
45+
*/
46+
class ZipkinAutoConfigurationIntegrationTests {
47+
48+
@Test
49+
void zipkinsUseOfRestTemplateDoesNotCauseACycle() {
50+
configure(new WebApplicationContextRunner())
51+
.withConfiguration(AutoConfigurations.of(RestTemplateAutoConfiguration.class))
52+
.run((context) -> assertThat(context).hasNotFailed());
53+
}
54+
55+
@Test
56+
void zipkinsUseOfWebClientDoesNotCauseACycle() {
57+
configure(new ReactiveWebApplicationContextRunner())
58+
.withConfiguration(AutoConfigurations.of(WebClientAutoConfiguration.class))
59+
.run((context) -> assertThat(context).hasNotFailed());
60+
}
61+
62+
<SELF extends AbstractApplicationContextRunner<SELF, C, A>, C extends ConfigurableApplicationContext, A extends ApplicationContextAssertProvider<C>> AbstractApplicationContextRunner<SELF, C, A> configure(
63+
AbstractApplicationContextRunner<SELF, ?, ?> runner) {
64+
return runner
65+
.withConfiguration(AutoConfigurations.of(MicrometerTracingAutoConfiguration.class,
66+
ObservationAutoConfiguration.class, BraveAutoConfiguration.class, ZipkinAutoConfiguration.class,
67+
HttpClientMetricsAutoConfiguration.class, MetricsAutoConfiguration.class,
68+
SimpleMetricsExportAutoConfiguration.class))
69+
.withClassLoader(new FilteredClassLoader(URLConnectionSender.class));
70+
}
71+
72+
}

0 commit comments

Comments
 (0)