Polish "Add auto-configuration for OTLP span exporter"

See gh-34508
This commit is contained in:
Andy Wilkinson 2023-04-19 14:45:16 +01:00
parent ceaafeca0b
commit c543d9172c
4 changed files with 12 additions and 17 deletions

View File

@ -22,6 +22,7 @@ import io.micrometer.tracing.otel.bridge.OtelTracer;
import io.opentelemetry.api.OpenTelemetry; import io.opentelemetry.api.OpenTelemetry;
import io.opentelemetry.exporter.otlp.http.trace.OtlpHttpSpanExporter; import io.opentelemetry.exporter.otlp.http.trace.OtlpHttpSpanExporter;
import io.opentelemetry.exporter.otlp.http.trace.OtlpHttpSpanExporterBuilder; import io.opentelemetry.exporter.otlp.http.trace.OtlpHttpSpanExporterBuilder;
import io.opentelemetry.exporter.otlp.trace.OtlpGrpcSpanExporter;
import io.opentelemetry.sdk.trace.SdkTracerProvider; import io.opentelemetry.sdk.trace.SdkTracerProvider;
import org.springframework.boot.actuate.autoconfigure.tracing.ConditionalOnEnabledTracing; import org.springframework.boot.actuate.autoconfigure.tracing.ConditionalOnEnabledTracing;
@ -41,7 +42,7 @@ import org.springframework.context.annotation.Bean;
* "https://github.com/open-telemetry/opentelemetry-java/issues/3651">opentelemetry-java#3651</a>. * "https://github.com/open-telemetry/opentelemetry-java/issues/3651">opentelemetry-java#3651</a>.
* Because this class configures components from the OTel SDK, it can't support HTTP/JSON. * Because this class configures components from the OTel SDK, it can't support HTTP/JSON.
* To keep things simple, we only auto-configure HTTP/protobuf. If you want to use gRPC, * To keep things simple, we only auto-configure HTTP/protobuf. If you want to use gRPC,
* please disable this auto-configuration and create a bean. * define an {@link OtlpGrpcSpanExporter} and this auto-configuration will back off.
* *
* @author Jonatan Ivanov * @author Jonatan Ivanov
* @since 3.1.0 * @since 3.1.0
@ -53,19 +54,17 @@ import org.springframework.context.annotation.Bean;
public class OtlpAutoConfiguration { public class OtlpAutoConfiguration {
@Bean @Bean
@ConditionalOnMissingBean @ConditionalOnMissingBean(value = OtlpHttpSpanExporter.class,
type = "io.opentelemetry.exporter.otlp.trace.OtlpGrpcSpanExporter")
OtlpHttpSpanExporter otlpHttpSpanExporter(OtlpProperties properties) { OtlpHttpSpanExporter otlpHttpSpanExporter(OtlpProperties properties) {
OtlpHttpSpanExporterBuilder builder = OtlpHttpSpanExporter.builder() OtlpHttpSpanExporterBuilder builder = OtlpHttpSpanExporter.builder()
.setEndpoint(properties.getEndpoint()) .setEndpoint(properties.getEndpoint())
.setTimeout(properties.getTimeout()) .setTimeout(properties.getTimeout())
.setCompression(properties.getCompression().name().toLowerCase()); .setCompression(properties.getCompression().name().toLowerCase());
for (Entry<String, String> header : properties.getHeaders().entrySet()) { for (Entry<String, String> header : properties.getHeaders().entrySet()) {
builder.addHeader(header.getKey(), header.getValue()); builder.addHeader(header.getKey(), header.getValue());
} }
return builder.build(); return builder.build();
} }
} }

View File

@ -23,7 +23,7 @@ import java.util.Map;
import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.boot.context.properties.ConfigurationProperties;
/** /**
* Configuration properties for {@link OtlpAutoConfiguration}. * Configuration properties for exporting traces using OTLP.
* *
* @author Jonatan Ivanov * @author Jonatan Ivanov
* @since 3.1.0 * @since 3.1.0

View File

@ -54,11 +54,10 @@ class OtlpAutoConfigurationIntegrationTests {
AutoConfigurations.of(ObservationAutoConfiguration.class, MicrometerTracingAutoConfiguration.class, AutoConfigurations.of(ObservationAutoConfiguration.class, MicrometerTracingAutoConfiguration.class,
OpenTelemetryAutoConfiguration.class, OtlpAutoConfiguration.class)); OpenTelemetryAutoConfiguration.class, OtlpAutoConfiguration.class));
private MockWebServer mockWebServer; private final MockWebServer mockWebServer = new MockWebServer();
@BeforeEach @BeforeEach
void setUp() throws IOException { void setUp() throws IOException {
this.mockWebServer = new MockWebServer();
this.mockWebServer.start(); this.mockWebServer.start();
} }
@ -68,7 +67,7 @@ class OtlpAutoConfigurationIntegrationTests {
} }
@Test @Test
void httpSpanExporterShouldUseProtoBufAndNoCompression() { void httpSpanExporterShouldUseProtoBufAndNoCompressionByDefault() {
this.mockWebServer.enqueue(new MockResponse()); this.mockWebServer.enqueue(new MockResponse());
this.contextRunner this.contextRunner
.withPropertyValues("management.otlp.tracing.endpoint=http://localhost:%d/v1/traces" .withPropertyValues("management.otlp.tracing.endpoint=http://localhost:%d/v1/traces"
@ -77,7 +76,6 @@ class OtlpAutoConfigurationIntegrationTests {
context.getBean(Tracer.class).nextSpan().name("test").end(); context.getBean(Tracer.class).nextSpan().name("test").end();
assertThat(context.getBean(OtlpHttpSpanExporter.class).flush()) assertThat(context.getBean(OtlpHttpSpanExporter.class).flush())
.isSameAs(CompletableResultCode.ofSuccess()); .isSameAs(CompletableResultCode.ofSuccess());
RecordedRequest request = this.mockWebServer.takeRequest(10, TimeUnit.SECONDS); RecordedRequest request = this.mockWebServer.takeRequest(10, TimeUnit.SECONDS);
assertThat(request).isNotNull(); assertThat(request).isNotNull();
assertThat(request.getRequestLine()).contains("/v1/traces"); assertThat(request.getRequestLine()).contains("/v1/traces");
@ -91,17 +89,16 @@ class OtlpAutoConfigurationIntegrationTests {
} }
@Test @Test
void httpSpanExporterShouldUseProtoBufAndGzip() { void httpSpanExporterCanBeConfiguredToUseGzipCompression() {
this.mockWebServer.enqueue(new MockResponse()); this.mockWebServer.enqueue(new MockResponse());
this.contextRunner this.contextRunner
.withPropertyValues("management.otlp.tracing.compression=GZIP", .withPropertyValues("management.otlp.tracing.compression=gzip",
"management.otlp.tracing.endpoint=http://localhost:%d/test".formatted(this.mockWebServer.getPort())) "management.otlp.tracing.endpoint=http://localhost:%d/test".formatted(this.mockWebServer.getPort()))
.run((context) -> { .run((context) -> {
assertThat(context).hasSingleBean(OtlpHttpSpanExporter.class).hasSingleBean(SpanExporter.class); assertThat(context).hasSingleBean(OtlpHttpSpanExporter.class).hasSingleBean(SpanExporter.class);
context.getBean(Tracer.class).nextSpan().name("test").end(); context.getBean(Tracer.class).nextSpan().name("test").end();
assertThat(context.getBean(OtlpHttpSpanExporter.class).flush()) assertThat(context.getBean(OtlpHttpSpanExporter.class).flush())
.isSameAs(CompletableResultCode.ofSuccess()); .isSameAs(CompletableResultCode.ofSuccess());
RecordedRequest request = this.mockWebServer.takeRequest(10, TimeUnit.SECONDS); RecordedRequest request = this.mockWebServer.takeRequest(10, TimeUnit.SECONDS);
assertThat(request).isNotNull(); assertThat(request).isNotNull();
assertThat(request.getRequestLine()).contains("/test"); assertThat(request.getRequestLine()).contains("/test");

View File

@ -76,16 +76,15 @@ class OtlpAutoConfigurationTests {
} }
@Test @Test
void shouldSupplyCustomHttpExporter() { void shouldBackOffWhenCustomHttpExporterIsDefined() {
this.contextRunner.withUserConfiguration(CustomHttpExporterConfiguration.class) this.contextRunner.withUserConfiguration(CustomHttpExporterConfiguration.class)
.run((context) -> assertThat(context).hasBean("customOtlpHttpSpanExporter") .run((context) -> assertThat(context).hasBean("customOtlpHttpSpanExporter")
.hasSingleBean(SpanExporter.class)); .hasSingleBean(SpanExporter.class));
} }
@Test @Test
void shouldSupplyCustomGrpcExporter() { void shouldBackOffWhenCustomGrpcExporterIsDefined() {
this.contextRunner.withClassLoader(new FilteredClassLoader("io.opentelemetry.exporter")) this.contextRunner.withUserConfiguration(CustomGrpcExporterConfiguration.class)
.withUserConfiguration(CustomGrpcExporterConfiguration.class)
.run((context) -> assertThat(context).hasBean("customOtlpGrpcSpanExporter") .run((context) -> assertThat(context).hasBean("customOtlpGrpcSpanExporter")
.hasSingleBean(SpanExporter.class)); .hasSingleBean(SpanExporter.class));
} }