Skip to content

Commit cfd62cb

Browse files
committed
Merge pull request #44655 from nosan
* pr/44655: Polish "Introduce properties for configuring the OpenTelemetry BatchSpanProcessor" Introduce properties for configuring the OpenTelemetry BatchSpanProcessor Closes gh-44655
2 parents a53aba6 + 79030e6 commit cfd62cb

File tree

3 files changed

+144
-4
lines changed

3 files changed

+144
-4
lines changed

Diff for: spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/tracing/OpenTelemetryTracingAutoConfiguration.java

+10-3
Original file line numberDiff line numberDiff line change
@@ -119,9 +119,16 @@ SpanProcessors spanProcessors(ObjectProvider<SpanProcessor> spanProcessors) {
119119
BatchSpanProcessor otelSpanProcessor(SpanExporters spanExporters,
120120
ObjectProvider<SpanExportingPredicate> spanExportingPredicates, ObjectProvider<SpanReporter> spanReporters,
121121
ObjectProvider<SpanFilter> spanFilters, ObjectProvider<MeterProvider> meterProvider) {
122-
BatchSpanProcessorBuilder builder = BatchSpanProcessor
123-
.builder(new CompositeSpanExporter(spanExporters.list(), spanExportingPredicates.orderedStream().toList(),
124-
spanReporters.orderedStream().toList(), spanFilters.orderedStream().toList()));
122+
TracingProperties.OpenTelemetry.Export properties = this.tracingProperties.getOpentelemetry().getExport();
123+
CompositeSpanExporter spanExporter = new CompositeSpanExporter(spanExporters.list(),
124+
spanExportingPredicates.orderedStream().toList(), spanReporters.orderedStream().toList(),
125+
spanFilters.orderedStream().toList());
126+
BatchSpanProcessorBuilder builder = BatchSpanProcessor.builder(spanExporter)
127+
.setExportUnsampledSpans(properties.isIncludeUnsampled())
128+
.setExporterTimeout(properties.getTimeout())
129+
.setMaxExportBatchSize(properties.getMaxBatchSize())
130+
.setMaxQueueSize(properties.getMaxQueueSize())
131+
.setScheduleDelay(properties.getScheduleDelay());
125132
meterProvider.ifAvailable(builder::setMeterProvider);
126133
return builder.build();
127134
}

Diff for: spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/tracing/TracingProperties.java

+95-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2012-2024 the original author or authors.
2+
* Copyright 2012-2025 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -16,6 +16,7 @@
1616

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

19+
import java.time.Duration;
1920
import java.util.ArrayList;
2021
import java.util.List;
2122

@@ -51,6 +52,11 @@ public class TracingProperties {
5152
*/
5253
private final Brave brave = new Brave();
5354

55+
/**
56+
* OpenTelemetry configuration.
57+
*/
58+
private final OpenTelemetry opentelemetry = new OpenTelemetry();
59+
5460
public Sampling getSampling() {
5561
return this.sampling;
5662
}
@@ -67,6 +73,10 @@ public Brave getBrave() {
6773
return this.brave;
6874
}
6975

76+
public OpenTelemetry getOpentelemetry() {
77+
return this.opentelemetry;
78+
}
79+
7080
public static class Sampling {
7181

7282
/**
@@ -293,4 +303,88 @@ public void setSpanJoiningSupported(boolean spanJoiningSupported) {
293303

294304
}
295305

306+
public static class OpenTelemetry {
307+
308+
/**
309+
* Span export configuration.
310+
*/
311+
private final Export export = new Export();
312+
313+
public Export getExport() {
314+
return this.export;
315+
}
316+
317+
public static class Export {
318+
319+
/**
320+
* Whether unsampled spans should be exported.
321+
*/
322+
private boolean includeUnsampled;
323+
324+
/**
325+
* Maximum time an export will be allowed to run before being cancelled.
326+
*/
327+
private Duration timeout = Duration.ofSeconds(30);
328+
329+
/**
330+
* Maximum batch size for each export. This must be less than or equal to
331+
* 'maxQueueSize'.
332+
*/
333+
private int maxBatchSize = 512;
334+
335+
/**
336+
* Maximum number of spans that are kept in the queue before they will be
337+
* dropped.
338+
*/
339+
private int maxQueueSize = 2048;
340+
341+
/**
342+
* The delay interval between two consecutive exports.
343+
*/
344+
private Duration scheduleDelay = Duration.ofSeconds(5);
345+
346+
public boolean isIncludeUnsampled() {
347+
return this.includeUnsampled;
348+
}
349+
350+
public void setIncludeUnsampled(boolean includeUnsampled) {
351+
this.includeUnsampled = includeUnsampled;
352+
}
353+
354+
public Duration getTimeout() {
355+
return this.timeout;
356+
}
357+
358+
public void setTimeout(Duration timeout) {
359+
this.timeout = timeout;
360+
}
361+
362+
public int getMaxBatchSize() {
363+
return this.maxBatchSize;
364+
}
365+
366+
public void setMaxBatchSize(int maxBatchSize) {
367+
this.maxBatchSize = maxBatchSize;
368+
}
369+
370+
public int getMaxQueueSize() {
371+
return this.maxQueueSize;
372+
}
373+
374+
public void setMaxQueueSize(int maxQueueSize) {
375+
this.maxQueueSize = maxQueueSize;
376+
}
377+
378+
public Duration getScheduleDelay() {
379+
return this.scheduleDelay;
380+
}
381+
382+
public void setScheduleDelay(Duration scheduleDelay) {
383+
this.scheduleDelay = scheduleDelay;
384+
}
385+
386+
}
387+
388+
}
389+
296390
}

Diff for: spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/tracing/OpenTelemetryTracingAutoConfigurationTests.java

+39
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,7 @@
7070
import org.springframework.context.annotation.Bean;
7171
import org.springframework.context.annotation.Configuration;
7272
import org.springframework.core.annotation.Order;
73+
import org.springframework.test.util.ReflectionTestUtils;
7374

7475
import static org.assertj.core.api.Assertions.assertThat;
7576
import static org.assertj.core.api.Assertions.fail;
@@ -324,6 +325,44 @@ void shouldDisablePropagationIfTracingIsDisabled() {
324325
});
325326
}
326327

328+
@Test
329+
void batchSpanProcessorShouldBeConfiguredWithCustomProperties() {
330+
this.contextRunner
331+
.withPropertyValues("management.tracing.opentelemetry.export.timeout=45s",
332+
"management.tracing.opentelemetry.export.include-unsampled=true",
333+
"management.tracing.opentelemetry.export.max-batch-size=256",
334+
"management.tracing.opentelemetry.export.max-queue-size=4096",
335+
"management.tracing.opentelemetry.export.schedule-delay=15s")
336+
.run((context) -> {
337+
assertThat(context).hasSingleBean(BatchSpanProcessor.class);
338+
BatchSpanProcessor batchSpanProcessor = context.getBean(BatchSpanProcessor.class);
339+
assertThat(batchSpanProcessor).hasFieldOrPropertyWithValue("exportUnsampledSpans", true)
340+
.extracting("worker")
341+
.hasFieldOrPropertyWithValue("exporterTimeoutNanos", Duration.ofSeconds(45).toNanos())
342+
.hasFieldOrPropertyWithValue("maxExportBatchSize", 256)
343+
.hasFieldOrPropertyWithValue("scheduleDelayNanos", Duration.ofSeconds(15).toNanos())
344+
.extracting("queue")
345+
.satisfies((queue) -> assertThat(ReflectionTestUtils.<Integer>invokeMethod(queue, "capacity"))
346+
.isEqualTo(4096));
347+
});
348+
}
349+
350+
@Test
351+
void batchSpanProcessorShouldBeConfiguredWithDefaultProperties() {
352+
this.contextRunner.run((context) -> {
353+
assertThat(context).hasSingleBean(BatchSpanProcessor.class);
354+
BatchSpanProcessor batchSpanProcessor = context.getBean(BatchSpanProcessor.class);
355+
assertThat(batchSpanProcessor).hasFieldOrPropertyWithValue("exportUnsampledSpans", false)
356+
.extracting("worker")
357+
.hasFieldOrPropertyWithValue("exporterTimeoutNanos", Duration.ofSeconds(30).toNanos())
358+
.hasFieldOrPropertyWithValue("maxExportBatchSize", 512)
359+
.hasFieldOrPropertyWithValue("scheduleDelayNanos", Duration.ofSeconds(5).toNanos())
360+
.extracting("queue")
361+
.satisfies((queue) -> assertThat(ReflectionTestUtils.<Integer>invokeMethod(queue, "capacity"))
362+
.isEqualTo(2048));
363+
});
364+
}
365+
327366
@Test // gh-41439
328367
@ForkedClassPath
329368
void shouldPublishEventsWhenContextStorageIsInitializedEarly() {

0 commit comments

Comments
 (0)