From 6b50d6783bb5defd1301cd0444210c2ecb1f4e30 Mon Sep 17 00:00:00 2001 From: Peeters Tim EXT Date: Mon, 24 Jun 2024 11:46:49 +0200 Subject: [PATCH 1/2] Add auto-configuration for OTLP gRPC format when using tracing See gh-41213 --- .../build.gradle | 1 + .../tracing/otlp/OtlpAutoConfiguration.java | 6 +- .../tracing/otlp/OtlpProperties.java | 27 ++++ .../otlp/OtlpTracingConfigurations.java | 24 +++- ...OtlpAutoConfigurationIntegrationTests.java | 116 +++++++++++++++++- .../otlp/OtlpAutoConfigurationTests.java | 15 +++ 6 files changed, 183 insertions(+), 6 deletions(-) diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/build.gradle b/spring-boot-project/spring-boot-actuator-autoconfigure/build.gradle index 3b4e685872..533adfbb10 100644 --- a/spring-boot-project/spring-boot-actuator-autoconfigure/build.gradle +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/build.gradle @@ -161,6 +161,7 @@ dependencies { testImplementation("org.awaitility:awaitility") testImplementation("org.cache2k:cache2k-api") testImplementation("org.eclipse.jetty.ee10:jetty-ee10-webapp") + testImplementation("org.eclipse.jetty.http2:jetty-http2-server") testImplementation("org.glassfish.jersey.ext:jersey-spring6") testImplementation("org.glassfish.jersey.media:jersey-media-json-jackson") testImplementation("org.hamcrest:hamcrest") diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/tracing/otlp/OtlpAutoConfiguration.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/tracing/otlp/OtlpAutoConfiguration.java index abb3253f2f..9d797721fb 100644 --- a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/tracing/otlp/OtlpAutoConfiguration.java +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/tracing/otlp/OtlpAutoConfiguration.java @@ -36,8 +36,10 @@ import org.springframework.context.annotation.Import; * the future, see: opentelemetry-java#3651. * 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, - * define an {@link OtlpGrpcSpanExporter} and this auto-configuration will back off. + * By default, we auto-configure HTTP/protobuf. If you want to use gRPC, you need to set + * {@code management.otlp.tracing.transport=grpc}. If you define a + * {@link OtlpHttpSpanExporter} or {@link OtlpGrpcSpanExporter}, this auto-configuration + * will back off. * * @author Jonatan Ivanov * @author Moritz Halbritter diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/tracing/otlp/OtlpProperties.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/tracing/otlp/OtlpProperties.java index 371de84911..b6bd517a5b 100644 --- a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/tracing/otlp/OtlpProperties.java +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/tracing/otlp/OtlpProperties.java @@ -44,6 +44,11 @@ public class OtlpProperties { */ private Duration timeout = Duration.ofSeconds(10); + /** + * Transport used to send the spans. Defaults to HTTP. + */ + private Transport transport = Transport.HTTP; + /** * Method used to compress the payload. */ @@ -70,6 +75,14 @@ public class OtlpProperties { this.timeout = timeout; } + public Transport getTransport() { + return this.transport; + } + + public void setTransport(Transport transport) { + this.transport = transport; + } + public Compression getCompression() { return this.compression; } @@ -86,6 +99,20 @@ public class OtlpProperties { this.headers = headers; } + enum Transport { + + /** + * HTTP exporter. + */ + HTTP, + + /** + * gRPC exporter. + */ + GRPC + + } + enum Compression { /** diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/tracing/otlp/OtlpTracingConfigurations.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/tracing/otlp/OtlpTracingConfigurations.java index 1426967171..95f0ec4a4a 100644 --- a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/tracing/otlp/OtlpTracingConfigurations.java +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/tracing/otlp/OtlpTracingConfigurations.java @@ -20,6 +20,8 @@ import java.util.Map.Entry; import io.opentelemetry.exporter.otlp.http.trace.OtlpHttpSpanExporter; import io.opentelemetry.exporter.otlp.http.trace.OtlpHttpSpanExporterBuilder; +import io.opentelemetry.exporter.otlp.trace.OtlpGrpcSpanExporter; +import io.opentelemetry.exporter.otlp.trace.OtlpGrpcSpanExporterBuilder; import org.springframework.boot.actuate.autoconfigure.tracing.ConditionalOnEnabledTracing; import org.springframework.boot.autoconfigure.condition.ConditionalOnBean; @@ -69,10 +71,11 @@ class OtlpTracingConfigurations { static class Exporters { @Bean - @ConditionalOnMissingBean(value = OtlpHttpSpanExporter.class, - type = "io.opentelemetry.exporter.otlp.trace.OtlpGrpcSpanExporter") + @ConditionalOnMissingBean({ OtlpGrpcSpanExporter.class, OtlpHttpSpanExporter.class }) @ConditionalOnBean(OtlpTracingConnectionDetails.class) @ConditionalOnEnabledTracing("otlp") + @ConditionalOnProperty(prefix = "management.otlp.tracing", name = "transport", havingValue = "http", + matchIfMissing = true) OtlpHttpSpanExporter otlpHttpSpanExporter(OtlpProperties properties, OtlpTracingConnectionDetails connectionDetails) { OtlpHttpSpanExporterBuilder builder = OtlpHttpSpanExporter.builder() @@ -85,6 +88,23 @@ class OtlpTracingConfigurations { return builder.build(); } + @Bean + @ConditionalOnMissingBean({ OtlpGrpcSpanExporter.class, OtlpHttpSpanExporter.class }) + @ConditionalOnBean(OtlpTracingConnectionDetails.class) + @ConditionalOnEnabledTracing("otlp") + @ConditionalOnProperty(prefix = "management.otlp.tracing", name = "transport", havingValue = "grpc") + OtlpGrpcSpanExporter otlpGrpcSpanExporter(OtlpProperties properties, + OtlpTracingConnectionDetails connectionDetails) { + OtlpGrpcSpanExporterBuilder builder = OtlpGrpcSpanExporter.builder() + .setEndpoint(connectionDetails.getUrl()) + .setTimeout(properties.getTimeout()) + .setCompression(properties.getCompression().name().toLowerCase()); + for (Entry header : properties.getHeaders().entrySet()) { + builder.addHeader(header.getKey(), header.getValue()); + } + return builder.build(); + } + } } diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/tracing/otlp/OtlpAutoConfigurationIntegrationTests.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/tracing/otlp/OtlpAutoConfigurationIntegrationTests.java index 0fcc77811f..4f001a4993 100644 --- a/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/tracing/otlp/OtlpAutoConfigurationIntegrationTests.java +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/tracing/otlp/OtlpAutoConfigurationIntegrationTests.java @@ -17,11 +17,15 @@ package org.springframework.boot.actuate.autoconfigure.tracing.otlp; import java.io.IOException; +import java.io.InputStream; import java.nio.charset.StandardCharsets; +import java.util.concurrent.BlockingQueue; +import java.util.concurrent.LinkedBlockingQueue; import java.util.concurrent.TimeUnit; import io.micrometer.tracing.Tracer; import io.opentelemetry.exporter.otlp.http.trace.OtlpHttpSpanExporter; +import io.opentelemetry.exporter.otlp.trace.OtlpGrpcSpanExporter; import io.opentelemetry.sdk.common.CompletableResultCode; import io.opentelemetry.sdk.trace.export.SpanExporter; import okhttp3.mockwebserver.MockResponse; @@ -29,6 +33,16 @@ import okhttp3.mockwebserver.MockWebServer; import okhttp3.mockwebserver.RecordedRequest; import okio.Buffer; import okio.GzipSource; +import org.eclipse.jetty.http.HttpFields; +import org.eclipse.jetty.http2.server.HTTP2CServerConnectionFactory; +import org.eclipse.jetty.io.Content; +import org.eclipse.jetty.server.Handler; +import org.eclipse.jetty.server.HttpConfiguration; +import org.eclipse.jetty.server.Request; +import org.eclipse.jetty.server.Response; +import org.eclipse.jetty.server.Server; +import org.eclipse.jetty.server.ServerConnector; +import org.eclipse.jetty.util.Callback; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; @@ -36,8 +50,10 @@ import org.junit.jupiter.api.Test; import org.springframework.boot.actuate.autoconfigure.observation.ObservationAutoConfiguration; import org.springframework.boot.actuate.autoconfigure.opentelemetry.OpenTelemetryAutoConfiguration; import org.springframework.boot.actuate.autoconfigure.tracing.MicrometerTracingAutoConfiguration; +import org.springframework.boot.actuate.autoconfigure.tracing.otlp.OtlpAutoConfigurationIntegrationTests.MockGrpcServer.RecordedGrpcRequest; import org.springframework.boot.autoconfigure.AutoConfigurations; import org.springframework.boot.test.context.runner.ApplicationContextRunner; +import org.springframework.util.StreamUtils; import static org.assertj.core.api.Assertions.assertThat; @@ -57,16 +73,28 @@ class OtlpAutoConfigurationIntegrationTests { private final MockWebServer mockWebServer = new MockWebServer(); + private final MockGrpcServer mockGrpcServer = new MockGrpcServer(); + @BeforeEach - void setUp() throws IOException { + void startMockWebServer() throws IOException { this.mockWebServer.start(); } + @BeforeEach + void startMockGrpcServer() throws Exception { + this.mockGrpcServer.start(); + } + @AfterEach - void tearDown() throws IOException { + void stopMockWebServer() throws IOException { this.mockWebServer.close(); } + @AfterEach + void stopMockGrpcServer() throws Exception { + this.mockGrpcServer.stop(); + } + @Test void httpSpanExporterShouldUseProtobufAndNoCompressionByDefault() { this.mockWebServer.enqueue(new MockResponse()); @@ -113,4 +141,88 @@ class OtlpAutoConfigurationIntegrationTests { }); } + @Test + void grpcSpanExporter() { + this.contextRunner + .withPropertyValues( + "management.otlp.tracing.endpoint=http://localhost:%d".formatted(this.mockGrpcServer.getPort()), + "management.otlp.tracing.headers.custom=42", "management.otlp.tracing.transport=grpc") + .run((context) -> { + context.getBean(Tracer.class).nextSpan().name("test").end(); + assertThat(context.getBean(OtlpGrpcSpanExporter.class).flush()) + .isSameAs(CompletableResultCode.ofSuccess()); + RecordedGrpcRequest request = this.mockGrpcServer.takeRequest(10, TimeUnit.SECONDS); + assertThat(request).isNotNull(); + assertThat(request.headers().get("Content-Type")).isEqualTo("application/grpc"); + assertThat(request.headers().get("custom")).isEqualTo("42"); + assertThat(request.body()).contains("org.springframework.boot"); + }); + } + + static class MockGrpcServer { + + private final Server server = createServer(); + + private final BlockingQueue recordedRequests = new LinkedBlockingQueue<>(); + + void start() throws Exception { + this.server.start(); + } + + void stop() throws Exception { + this.server.stop(); + } + + int getPort() { + return this.server.getURI().getPort(); + } + + RecordedGrpcRequest takeRequest(int timeout, TimeUnit unit) throws InterruptedException { + return this.recordedRequests.poll(timeout, unit); + } + + void recordRequest(RecordedGrpcRequest request) { + this.recordedRequests.add(request); + } + + private Server createServer() { + Server server = new Server(); + server.addConnector(createConnector(server)); + server.setHandler(new GrpcHandler()); + + return server; + } + + private ServerConnector createConnector(Server server) { + ServerConnector connector = new ServerConnector(server, + new HTTP2CServerConnectionFactory(new HttpConfiguration())); + connector.setPort(0); + + return connector; + } + + class GrpcHandler extends Handler.Abstract { + + @Override + public boolean handle(Request request, Response response, Callback callback) throws Exception { + try (InputStream in = Content.Source.asInputStream(request)) { + recordRequest(new RecordedGrpcRequest(request.getHeaders(), + StreamUtils.copyToString(in, StandardCharsets.UTF_8))); + } + + response.getHeaders().add("Content-Type", "application/grpc"); + response.getHeaders().add("Grpc-Status", "0"); + + callback.succeeded(); + + return true; + } + + } + + record RecordedGrpcRequest(HttpFields headers, String body) { + } + + } + } diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/tracing/otlp/OtlpAutoConfigurationTests.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/tracing/otlp/OtlpAutoConfigurationTests.java index eba8fe1125..2f9259c6db 100644 --- a/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/tracing/otlp/OtlpAutoConfigurationTests.java +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/tracing/otlp/OtlpAutoConfigurationTests.java @@ -51,6 +51,12 @@ class OtlpAutoConfigurationTests { this.contextRunner.run((context) -> assertThat(context).doesNotHaveBean(OtlpHttpSpanExporter.class)); } + @Test + void shouldNotSupplyBeansIfGrpcTransportIsEnabledButPropertyIsNotSet() { + this.contextRunner.withPropertyValues("management.otlp.tracing.transport=grpc") + .run((context) -> assertThat(context).doesNotHaveBean(OtlpGrpcSpanExporter.class)); + } + @Test void shouldSupplyBeans() { this.contextRunner.withPropertyValues("management.otlp.tracing.endpoint=http://localhost:4318/v1/traces") @@ -58,6 +64,15 @@ class OtlpAutoConfigurationTests { .hasSingleBean(SpanExporter.class)); } + @Test + void shouldSupplyBeansIfGrpcTransportIsEnabled() { + this.contextRunner + .withPropertyValues("management.otlp.tracing.endpoint=http://localhost:4317/v1/traces", + "management.otlp.tracing.transport=grpc") + .run((context) -> assertThat(context).hasSingleBean(OtlpGrpcSpanExporter.class) + .hasSingleBean(SpanExporter.class)); + } + @Test void shouldNotSupplyBeansIfGlobalTracingIsDisabled() { this.contextRunner.withPropertyValues("management.tracing.enabled=false") From abf923ee9aba478a9a0165e2db8961ae1edb1add Mon Sep 17 00:00:00 2001 From: Moritz Halbritter Date: Thu, 4 Jul 2024 09:53:30 +0200 Subject: [PATCH 2/2] Polish "Add auto-configuration for OTLP gRPC format when using tracing" See gh-41213 --- .../tracing/otlp/OtlpProperties.java | 10 +++--- .../otlp/OtlpTracingConfigurations.java | 9 ++--- ...itional-spring-configuration-metadata.json | 4 +++ ...OtlpAutoConfigurationIntegrationTests.java | 35 ++++++------------- 4 files changed, 23 insertions(+), 35 deletions(-) diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/tracing/otlp/OtlpProperties.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/tracing/otlp/OtlpProperties.java index b6bd517a5b..bf93d58dd1 100644 --- a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/tracing/otlp/OtlpProperties.java +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/tracing/otlp/OtlpProperties.java @@ -45,7 +45,7 @@ public class OtlpProperties { private Duration timeout = Duration.ofSeconds(10); /** - * Transport used to send the spans. Defaults to HTTP. + * Transport used to send the spans. */ private Transport transport = Transport.HTTP; @@ -99,21 +99,21 @@ public class OtlpProperties { this.headers = headers; } - enum Transport { + public enum Transport { /** - * HTTP exporter. + * HTTP transport. */ HTTP, /** - * gRPC exporter. + * gRPC transport. */ GRPC } - enum Compression { + public enum Compression { /** * Gzip compression. diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/tracing/otlp/OtlpTracingConfigurations.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/tracing/otlp/OtlpTracingConfigurations.java index 95f0ec4a4a..f222fb249d 100644 --- a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/tracing/otlp/OtlpTracingConfigurations.java +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/tracing/otlp/OtlpTracingConfigurations.java @@ -68,12 +68,12 @@ class OtlpTracingConfigurations { } @Configuration(proxyBeanMethods = false) + @ConditionalOnMissingBean({ OtlpGrpcSpanExporter.class, OtlpHttpSpanExporter.class }) + @ConditionalOnBean(OtlpTracingConnectionDetails.class) + @ConditionalOnEnabledTracing("otlp") static class Exporters { @Bean - @ConditionalOnMissingBean({ OtlpGrpcSpanExporter.class, OtlpHttpSpanExporter.class }) - @ConditionalOnBean(OtlpTracingConnectionDetails.class) - @ConditionalOnEnabledTracing("otlp") @ConditionalOnProperty(prefix = "management.otlp.tracing", name = "transport", havingValue = "http", matchIfMissing = true) OtlpHttpSpanExporter otlpHttpSpanExporter(OtlpProperties properties, @@ -89,9 +89,6 @@ class OtlpTracingConfigurations { } @Bean - @ConditionalOnMissingBean({ OtlpGrpcSpanExporter.class, OtlpHttpSpanExporter.class }) - @ConditionalOnBean(OtlpTracingConnectionDetails.class) - @ConditionalOnEnabledTracing("otlp") @ConditionalOnProperty(prefix = "management.otlp.tracing", name = "transport", havingValue = "grpc") OtlpGrpcSpanExporter otlpGrpcSpanExporter(OtlpProperties properties, OtlpTracingConnectionDetails connectionDetails) { diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/resources/META-INF/additional-spring-configuration-metadata.json b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/resources/META-INF/additional-spring-configuration-metadata.json index c69880ebfd..fb5bf2716d 100644 --- a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/resources/META-INF/additional-spring-configuration-metadata.json +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/resources/META-INF/additional-spring-configuration-metadata.json @@ -2102,6 +2102,10 @@ "type": "java.lang.Boolean", "description": "Whether auto-configuration of tracing is enabled to export OTLP traces." }, + { + "name": "management.otlp.tracing.transport", + "defaultValue": "http" + }, { "name": "management.prometheus.metrics.export.histogram-flavor", "defaultValue": "prometheus" diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/tracing/otlp/OtlpAutoConfigurationIntegrationTests.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/tracing/otlp/OtlpAutoConfigurationIntegrationTests.java index 4f001a4993..9882e837ef 100644 --- a/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/tracing/otlp/OtlpAutoConfigurationIntegrationTests.java +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/tracing/otlp/OtlpAutoConfigurationIntegrationTests.java @@ -16,7 +16,6 @@ package org.springframework.boot.actuate.autoconfigure.tracing.otlp; -import java.io.IOException; import java.io.InputStream; import java.nio.charset.StandardCharsets; import java.util.concurrent.BlockingQueue; @@ -53,7 +52,6 @@ import org.springframework.boot.actuate.autoconfigure.tracing.MicrometerTracingA import org.springframework.boot.actuate.autoconfigure.tracing.otlp.OtlpAutoConfigurationIntegrationTests.MockGrpcServer.RecordedGrpcRequest; import org.springframework.boot.autoconfigure.AutoConfigurations; import org.springframework.boot.test.context.runner.ApplicationContextRunner; -import org.springframework.util.StreamUtils; import static org.assertj.core.api.Assertions.assertThat; @@ -76,23 +74,15 @@ class OtlpAutoConfigurationIntegrationTests { private final MockGrpcServer mockGrpcServer = new MockGrpcServer(); @BeforeEach - void startMockWebServer() throws IOException { + void startServers() throws Exception { this.mockWebServer.start(); - } - - @BeforeEach - void startMockGrpcServer() throws Exception { this.mockGrpcServer.start(); } @AfterEach - void stopMockWebServer() throws IOException { + void stopServers() throws Exception { this.mockWebServer.close(); - } - - @AfterEach - void stopMockGrpcServer() throws Exception { - this.mockGrpcServer.stop(); + this.mockGrpcServer.close(); } @Test @@ -142,7 +132,7 @@ class OtlpAutoConfigurationIntegrationTests { } @Test - void grpcSpanExporter() { + void grpcSpanExporterShouldExportSpans() { this.contextRunner .withPropertyValues( "management.otlp.tracing.endpoint=http://localhost:%d".formatted(this.mockGrpcServer.getPort()), @@ -155,7 +145,7 @@ class OtlpAutoConfigurationIntegrationTests { assertThat(request).isNotNull(); assertThat(request.headers().get("Content-Type")).isEqualTo("application/grpc"); assertThat(request.headers().get("custom")).isEqualTo("42"); - assertThat(request.body()).contains("org.springframework.boot"); + assertThat(request.bodyAsString()).contains("org.springframework.boot"); }); } @@ -169,7 +159,7 @@ class OtlpAutoConfigurationIntegrationTests { this.server.start(); } - void stop() throws Exception { + void close() throws Exception { this.server.stop(); } @@ -189,7 +179,6 @@ class OtlpAutoConfigurationIntegrationTests { Server server = new Server(); server.addConnector(createConnector(server)); server.setHandler(new GrpcHandler()); - return server; } @@ -197,7 +186,6 @@ class OtlpAutoConfigurationIntegrationTests { ServerConnector connector = new ServerConnector(server, new HTTP2CServerConnectionFactory(new HttpConfiguration())); connector.setPort(0); - return connector; } @@ -206,21 +194,20 @@ class OtlpAutoConfigurationIntegrationTests { @Override public boolean handle(Request request, Response response, Callback callback) throws Exception { try (InputStream in = Content.Source.asInputStream(request)) { - recordRequest(new RecordedGrpcRequest(request.getHeaders(), - StreamUtils.copyToString(in, StandardCharsets.UTF_8))); + recordRequest(new RecordedGrpcRequest(request.getHeaders(), in.readAllBytes())); } - response.getHeaders().add("Content-Type", "application/grpc"); response.getHeaders().add("Grpc-Status", "0"); - callback.succeeded(); - return true; } } - record RecordedGrpcRequest(HttpFields headers, String body) { + record RecordedGrpcRequest(HttpFields headers, byte[] body) { + String bodyAsString() { + return new String(this.body, StandardCharsets.UTF_8); + } } }