Skip to content

Commit ffc4265

Browse files
committed
Introduce OTLP span exporter builder customizers
This commit introduces customizers for both OtlpHttpSpanExporterBuilder and OtlpGrpcSpanExporterBuilder. Signed-off-by: Dmytro Nosan <[email protected]>
1 parent b5f7435 commit ffc4265

File tree

5 files changed

+122
-2
lines changed

5 files changed

+122
-2
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
/*
2+
* Copyright 2012-2025 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.otlp;
18+
19+
import io.opentelemetry.exporter.otlp.trace.OtlpGrpcSpanExporterBuilder;
20+
21+
/**
22+
* Callback interface that can be implemented by beans wishing to customize the
23+
* {@link OtlpGrpcSpanExporterBuilder} whilst retaining default auto-configuration.
24+
*
25+
* @author Dmytro Nosan
26+
* @since 3.5.0
27+
*/
28+
@FunctionalInterface
29+
public interface OtlpGrpcSpanExporterBuilderCustomizer {
30+
31+
/**
32+
* Customize the {@link OtlpGrpcSpanExporterBuilder}.
33+
* @param builder the builder to customize
34+
*/
35+
void customize(OtlpGrpcSpanExporterBuilder builder);
36+
37+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
/*
2+
* Copyright 2012-2025 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.otlp;
18+
19+
import io.opentelemetry.exporter.otlp.http.trace.OtlpHttpSpanExporterBuilder;
20+
21+
/**
22+
* Callback interface that can be implemented by beans wishing to customize the
23+
* {@link OtlpHttpSpanExporterBuilder} whilst retaining default auto-configuration.
24+
*
25+
* @author Dmytro Nosan
26+
* @since 3.5.0
27+
*/
28+
@FunctionalInterface
29+
public interface OtlpHttpSpanExporterBuilderCustomizer {
30+
31+
/**
32+
* Customize the {@link OtlpHttpSpanExporterBuilder}.
33+
* @param builder the builder to customize
34+
*/
35+
void customize(OtlpHttpSpanExporterBuilder builder);
36+
37+
}

spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/tracing/otlp/OtlpTracingConfigurations.java

+6-2
Original file line numberDiff line numberDiff line change
@@ -83,28 +83,32 @@ static class Exporters {
8383
@Bean
8484
@ConditionalOnProperty(name = "management.otlp.tracing.transport", havingValue = "http", matchIfMissing = true)
8585
OtlpHttpSpanExporter otlpHttpSpanExporter(OtlpTracingProperties properties,
86-
OtlpTracingConnectionDetails connectionDetails, ObjectProvider<MeterProvider> meterProvider) {
86+
OtlpTracingConnectionDetails connectionDetails, ObjectProvider<MeterProvider> meterProvider,
87+
ObjectProvider<OtlpHttpSpanExporterBuilderCustomizer> customizers) {
8788
OtlpHttpSpanExporterBuilder builder = OtlpHttpSpanExporter.builder()
8889
.setEndpoint(connectionDetails.getUrl(Transport.HTTP))
8990
.setTimeout(properties.getTimeout())
9091
.setConnectTimeout(properties.getConnectTimeout())
9192
.setCompression(properties.getCompression().name().toLowerCase(Locale.ROOT));
9293
properties.getHeaders().forEach(builder::addHeader);
9394
meterProvider.ifAvailable(builder::setMeterProvider);
95+
customizers.orderedStream().forEach((customizer) -> customizer.customize(builder));
9496
return builder.build();
9597
}
9698

9799
@Bean
98100
@ConditionalOnProperty(name = "management.otlp.tracing.transport", havingValue = "grpc")
99101
OtlpGrpcSpanExporter otlpGrpcSpanExporter(OtlpTracingProperties properties,
100-
OtlpTracingConnectionDetails connectionDetails, ObjectProvider<MeterProvider> meterProvider) {
102+
OtlpTracingConnectionDetails connectionDetails, ObjectProvider<MeterProvider> meterProvider,
103+
ObjectProvider<OtlpGrpcSpanExporterBuilderCustomizer> customizers) {
101104
OtlpGrpcSpanExporterBuilder builder = OtlpGrpcSpanExporter.builder()
102105
.setEndpoint(connectionDetails.getUrl(Transport.GRPC))
103106
.setTimeout(properties.getTimeout())
104107
.setConnectTimeout(properties.getConnectTimeout())
105108
.setCompression(properties.getCompression().name().toLowerCase(Locale.ROOT));
106109
properties.getHeaders().forEach(builder::addHeader);
107110
meterProvider.ifAvailable(builder::setMeterProvider);
111+
customizers.orderedStream().forEach((customizer) -> customizer.customize(builder));
108112
return builder.build();
109113
}
110114

spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/tracing/otlp/OtlpTracingAutoConfigurationTests.java

+40
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616

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

19+
import java.time.Duration;
1920
import java.util.function.Supplier;
2021

2122
import io.opentelemetry.api.metrics.MeterProvider;
@@ -184,6 +185,45 @@ void grpcShouldUseMeterProviderIfSet() {
184185
});
185186
}
186187

188+
@Test
189+
void shouldCustomizeHttpTransportWithOtlpHttpSpanExporterBuilderCustomizer() {
190+
Duration connectTimeout = Duration.ofMinutes(20);
191+
Duration timeout = Duration.ofMinutes(10);
192+
this.contextRunner
193+
.withBean("httpCustomizer1", OtlpHttpSpanExporterBuilderCustomizer.class,
194+
() -> (builder) -> builder.setConnectTimeout(connectTimeout))
195+
.withBean("httpCustomizer2", OtlpHttpSpanExporterBuilderCustomizer.class,
196+
() -> (builder) -> builder.setTimeout(timeout))
197+
.withPropertyValues("management.otlp.tracing.endpoint=http://localhost:4317/v1/traces")
198+
.run((context) -> {
199+
assertThat(context).hasSingleBean(OtlpHttpSpanExporter.class).hasSingleBean(SpanExporter.class);
200+
OtlpHttpSpanExporter exporter = context.getBean(OtlpHttpSpanExporter.class);
201+
assertThat(exporter).extracting("delegate.httpSender.client")
202+
.hasFieldOrPropertyWithValue("connectTimeoutMillis", (int) connectTimeout.toMillis())
203+
.hasFieldOrPropertyWithValue("callTimeoutMillis", (int) timeout.toMillis());
204+
});
205+
}
206+
207+
@Test
208+
void shouldCustomizeGrpcTransportWhenEnabledWithOtlpGrpcSpanExporterBuilderCustomizer() {
209+
Duration timeout = Duration.ofMinutes(10);
210+
Duration connectTimeout = Duration.ofMinutes(20);
211+
this.contextRunner
212+
.withBean("grpcCustomizer1", OtlpGrpcSpanExporterBuilderCustomizer.class,
213+
() -> (builder) -> builder.setConnectTimeout(connectTimeout))
214+
.withBean("grpcCustomizer2", OtlpGrpcSpanExporterBuilderCustomizer.class,
215+
() -> (builder) -> builder.setTimeout(timeout))
216+
.withPropertyValues("management.otlp.tracing.endpoint=http://localhost:4317/v1/traces",
217+
"management.otlp.tracing.transport=grpc")
218+
.run((context) -> {
219+
assertThat(context).hasSingleBean(OtlpGrpcSpanExporter.class).hasSingleBean(SpanExporter.class);
220+
OtlpGrpcSpanExporter exporter = context.getBean(OtlpGrpcSpanExporter.class);
221+
assertThat(exporter).extracting("delegate.grpcSender.client")
222+
.hasFieldOrPropertyWithValue("connectTimeoutMillis", (int) connectTimeout.toMillis())
223+
.hasFieldOrPropertyWithValue("callTimeoutMillis", (int) timeout.toMillis());
224+
});
225+
}
226+
187227
@Configuration(proxyBeanMethods = false)
188228
private static final class MeterProviderConfiguration {
189229

spring-boot-project/spring-boot-docs/src/docs/antora/modules/reference/pages/actuator/tracing.adoc

+2
Original file line numberDiff line numberDiff line change
@@ -150,6 +150,8 @@ Tracing with OpenTelemetry and reporting using OTLP requires the following depen
150150

151151
Use the `management.otlp.tracing.*` configuration properties to configure reporting using OTLP.
152152

153+
NOTE: If you need to apply advanced customizations to OTLP span exporters, consider registering javadoc:org.springframework.boot.actuate.autoconfigure.tracing.otlp.OtlpHttpSpanExporterBuilderCustomizer[] or javadoc:org.springframework.boot.actuate.autoconfigure.tracing.otlp.OtlpGrpcSpanExporterBuilderCustomizer[] beans. These will be invoked **before** the creation of the `OtlpHttpSpanExporter` or `OtlpGrpcSpanExporter`. The customizers take precedence over anything applied by the auto-configuration.
154+
153155

154156

155157
[[actuator.micrometer-tracing.tracer-implementations.brave-zipkin]]

0 commit comments

Comments
 (0)