mirror of
https://github.com/spring-projects/spring-boot.git
synced 2026-09-17 12:09:16 +00:00
Polish "Align OTLP signal-specific properties with common fallback configuration"
Allow `management.opentelemetry.otlp.compression` to act as a common default for OTLP compression, mirroring the existing endpoint/headers fallback. Tracing, logging and metrics exporters now fall back to it when their own signal-specific compression property is unset. See gh-50461
This commit is contained in:
-10
@@ -151,16 +151,6 @@
|
|||||||
"description": "Whether auto-configuration of logging is enabled to export logs.",
|
"description": "Whether auto-configuration of logging is enabled to export logs.",
|
||||||
"defaultValue": true
|
"defaultValue": true
|
||||||
},
|
},
|
||||||
{
|
|
||||||
"name": "management.opentelemetry.otlp.endpoint",
|
|
||||||
"type": "java.lang.String",
|
|
||||||
"description": "OTLP target endpoint URL."
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "management.opentelemetry.otlp.headers",
|
|
||||||
"type": "java.util.Map<java.lang.String,java.lang.String>",
|
|
||||||
"description": "Custom headers to be appended to OTLP requests."
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"name": "management.server.add-application-context-header",
|
"name": "management.server.add-application-context-header",
|
||||||
"type": "java.lang.Boolean",
|
"type": "java.lang.Boolean",
|
||||||
|
|||||||
+3
-3
@@ -53,7 +53,7 @@ public class OtlpMetricsProperties extends StepRegistryProperties {
|
|||||||
/**
|
/**
|
||||||
* Compression mode to use when exporting metrics.
|
* Compression mode to use when exporting metrics.
|
||||||
*/
|
*/
|
||||||
private CompressionMode compressionMode = CompressionMode.NONE;
|
private @Nullable CompressionMode compressionMode;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Headers for the exported metrics.
|
* Headers for the exported metrics.
|
||||||
@@ -109,11 +109,11 @@ public class OtlpMetricsProperties extends StepRegistryProperties {
|
|||||||
this.aggregationTemporality = aggregationTemporality;
|
this.aggregationTemporality = aggregationTemporality;
|
||||||
}
|
}
|
||||||
|
|
||||||
public CompressionMode getCompressionMode() {
|
public @Nullable CompressionMode getCompressionMode() {
|
||||||
return this.compressionMode;
|
return this.compressionMode;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setCompressionMode(CompressionMode compressionMode) {
|
public void setCompressionMode(@Nullable CompressionMode compressionMode) {
|
||||||
this.compressionMode = compressionMode;
|
this.compressionMode = compressionMode;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+12
-1
@@ -79,7 +79,18 @@ class OtlpMetricsPropertiesConfigAdapter extends StepRegistryPropertiesConfigAda
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public CompressionMode compressionMode() {
|
public CompressionMode compressionMode() {
|
||||||
return obtain(OtlpMetricsProperties::getCompressionMode, OtlpConfig.super::compressionMode);
|
CompressionMode compressionMode = this.properties.getCompressionMode();
|
||||||
|
if (compressionMode != null) {
|
||||||
|
return compressionMode;
|
||||||
|
}
|
||||||
|
OtlpProperties.Compression commonCompression = this.otlpProperties.getCompression();
|
||||||
|
if (commonCompression != null) {
|
||||||
|
return switch (commonCompression) {
|
||||||
|
case GZIP -> CompressionMode.GZIP;
|
||||||
|
case NONE -> CompressionMode.NONE;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
return OtlpConfig.super.compressionMode();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
+13
@@ -279,4 +279,17 @@ class OtlpMetricsPropertiesConfigAdapterTests {
|
|||||||
assertThat(createAdapter().url()).isEqualTo("http://signal-endpoint:4318/custom/metrics");
|
assertThat(createAdapter().url()).isEqualTo("http://signal-endpoint:4318/custom/metrics");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void whenPropertiesCompressionModeIsNotSetThenUseOtlpPropertiesCompressionAsFallback() {
|
||||||
|
this.otlpProperties.setCompression(OtlpProperties.Compression.GZIP);
|
||||||
|
assertThat(createAdapter().compressionMode()).isSameAs(CompressionMode.GZIP);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void whenPropertiesCompressionModeIsSetThenItOverridesOtlpPropertiesCompression() {
|
||||||
|
this.otlpProperties.setCompression(OtlpProperties.Compression.GZIP);
|
||||||
|
this.properties.setCompressionMode(CompressionMode.NONE);
|
||||||
|
assertThat(createAdapter().compressionMode()).isSameAs(CompressionMode.NONE);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
+1
-1
@@ -36,7 +36,7 @@ class OtlpMetricsPropertiesTests extends StepRegistryPropertiesTests {
|
|||||||
OtlpConfig config = OtlpConfig.DEFAULT;
|
OtlpConfig config = OtlpConfig.DEFAULT;
|
||||||
assertStepRegistryDefaultValues(properties, config);
|
assertStepRegistryDefaultValues(properties, config);
|
||||||
assertThat(properties.getAggregationTemporality()).isSameAs(config.aggregationTemporality());
|
assertThat(properties.getAggregationTemporality()).isSameAs(config.aggregationTemporality());
|
||||||
assertThat(properties.getCompressionMode()).isSameAs(config.compressionMode());
|
assertThat(properties.getCompressionMode()).isNull();
|
||||||
assertThat(properties.getHistogramFlavor()).isSameAs(config.histogramFlavor());
|
assertThat(properties.getHistogramFlavor()).isSameAs(config.histogramFlavor());
|
||||||
assertThat(properties.getMaxScale()).isEqualTo(config.maxScale());
|
assertThat(properties.getMaxScale()).isEqualTo(config.maxScale());
|
||||||
assertThat(properties.getMaxBucketCount()).isEqualTo(config.maxBucketCount());
|
assertThat(properties.getMaxBucketCount()).isEqualTo(config.maxBucketCount());
|
||||||
|
|||||||
+27
-61
@@ -16,7 +16,6 @@
|
|||||||
|
|
||||||
package org.springframework.boot.micrometer.tracing.opentelemetry.autoconfigure.otlp;
|
package org.springframework.boot.micrometer.tracing.opentelemetry.autoconfigure.otlp;
|
||||||
|
|
||||||
import java.time.Duration;
|
|
||||||
import java.util.LinkedHashMap;
|
import java.util.LinkedHashMap;
|
||||||
import java.util.Locale;
|
import java.util.Locale;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
@@ -34,20 +33,16 @@ import org.jspecify.annotations.Nullable;
|
|||||||
|
|
||||||
import org.springframework.beans.factory.ObjectProvider;
|
import org.springframework.beans.factory.ObjectProvider;
|
||||||
import org.springframework.boot.autoconfigure.condition.AnyNestedCondition;
|
import org.springframework.boot.autoconfigure.condition.AnyNestedCondition;
|
||||||
import org.springframework.boot.autoconfigure.condition.ConditionOutcome;
|
|
||||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
|
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
|
||||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
|
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
|
||||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
|
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
|
||||||
import org.springframework.boot.autoconfigure.condition.SpringBootCondition;
|
|
||||||
import org.springframework.boot.micrometer.tracing.autoconfigure.ConditionalOnEnabledTracingExport;
|
import org.springframework.boot.micrometer.tracing.autoconfigure.ConditionalOnEnabledTracingExport;
|
||||||
import org.springframework.boot.opentelemetry.autoconfigure.OtlpProperties;
|
import org.springframework.boot.opentelemetry.autoconfigure.OtlpProperties;
|
||||||
import org.springframework.boot.ssl.SslBundle;
|
import org.springframework.boot.ssl.SslBundle;
|
||||||
import org.springframework.boot.ssl.SslBundles;
|
import org.springframework.boot.ssl.SslBundles;
|
||||||
import org.springframework.context.annotation.Bean;
|
import org.springframework.context.annotation.Bean;
|
||||||
import org.springframework.context.annotation.ConditionContext;
|
|
||||||
import org.springframework.context.annotation.Conditional;
|
import org.springframework.context.annotation.Conditional;
|
||||||
import org.springframework.context.annotation.Configuration;
|
import org.springframework.context.annotation.Configuration;
|
||||||
import org.springframework.core.type.AnnotatedTypeMetadata;
|
|
||||||
import org.springframework.util.Assert;
|
import org.springframework.util.Assert;
|
||||||
import org.springframework.util.StringUtils;
|
import org.springframework.util.StringUtils;
|
||||||
|
|
||||||
@@ -81,13 +76,11 @@ final class OtlpTracingConfigurations {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@ConditionalOnProperty("management.opentelemetry.tracing.export.otlp.endpoint")
|
@ConditionalOnProperty("management.opentelemetry.tracing.export.otlp.endpoint")
|
||||||
@SuppressWarnings("unused")
|
|
||||||
static class TracingEndpoint {
|
static class TracingEndpoint {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@ConditionalOnProperty("management.opentelemetry.otlp.endpoint")
|
@ConditionalOnProperty("management.opentelemetry.otlp.endpoint")
|
||||||
@SuppressWarnings("unused")
|
|
||||||
static class CommonEndpoint {
|
static class CommonEndpoint {
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -115,6 +108,9 @@ final class OtlpTracingConfigurations {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getUrl(Transport transport) {
|
public String getUrl(Transport transport) {
|
||||||
|
Assert.state(transport == this.properties.getTransport(),
|
||||||
|
"Requested transport %s doesn't match configured transport %s".formatted(transport,
|
||||||
|
this.properties.getTransport()));
|
||||||
String endpoint = this.properties.getEndpoint();
|
String endpoint = this.properties.getEndpoint();
|
||||||
if (!StringUtils.hasLength(endpoint)) {
|
if (!StringUtils.hasLength(endpoint)) {
|
||||||
endpoint = this.otlpProperties.getEndpoint();
|
endpoint = this.otlpProperties.getEndpoint();
|
||||||
@@ -153,23 +149,13 @@ final class OtlpTracingConfigurations {
|
|||||||
OtlpTracingConnectionDetails connectionDetails, ObjectProvider<MeterProvider> meterProvider,
|
OtlpTracingConnectionDetails connectionDetails, ObjectProvider<MeterProvider> meterProvider,
|
||||||
ObjectProvider<OtlpHttpSpanExporterBuilderCustomizer> customizers) {
|
ObjectProvider<OtlpHttpSpanExporterBuilderCustomizer> customizers) {
|
||||||
OtlpHttpSpanExporterBuilder builder = OtlpHttpSpanExporter.builder()
|
OtlpHttpSpanExporterBuilder builder = OtlpHttpSpanExporter.builder()
|
||||||
.setEndpoint(connectionDetails.getUrl(Transport.HTTP));
|
.setEndpoint(connectionDetails.getUrl(Transport.HTTP))
|
||||||
|
.setTimeout(properties.getTimeout())
|
||||||
Duration timeout = properties.getTimeout();
|
.setConnectTimeout(properties.getConnectTimeout())
|
||||||
builder.setTimeout(timeout);
|
.setCompression(resolveCompression(properties, otlpProperties).name().toLowerCase(Locale.ROOT));
|
||||||
|
|
||||||
Duration connectTimeout = properties.getConnectTimeout();
|
|
||||||
builder.setConnectTimeout(connectTimeout);
|
|
||||||
|
|
||||||
String compression = properties.getCompression().name().toLowerCase(Locale.ROOT);
|
|
||||||
if (StringUtils.hasLength(compression)) {
|
|
||||||
builder.setCompression(compression);
|
|
||||||
}
|
|
||||||
|
|
||||||
Map<String, String> headers = new LinkedHashMap<>(otlpProperties.getHeaders());
|
Map<String, String> headers = new LinkedHashMap<>(otlpProperties.getHeaders());
|
||||||
headers.putAll(properties.getHeaders());
|
headers.putAll(properties.getHeaders());
|
||||||
headers.forEach(builder::addHeader);
|
headers.forEach(builder::addHeader);
|
||||||
|
|
||||||
meterProvider.ifAvailable(builder::setMeterProvider);
|
meterProvider.ifAvailable(builder::setMeterProvider);
|
||||||
configureSsl(connectionDetails, builder::setSslContext);
|
configureSsl(connectionDetails, builder::setSslContext);
|
||||||
customizers.orderedStream().forEach((customizer) -> customizer.customize(builder));
|
customizers.orderedStream().forEach((customizer) -> customizer.customize(builder));
|
||||||
@@ -182,29 +168,35 @@ final class OtlpTracingConfigurations {
|
|||||||
OtlpTracingConnectionDetails connectionDetails, ObjectProvider<MeterProvider> meterProvider,
|
OtlpTracingConnectionDetails connectionDetails, ObjectProvider<MeterProvider> meterProvider,
|
||||||
ObjectProvider<OtlpGrpcSpanExporterBuilderCustomizer> customizers) {
|
ObjectProvider<OtlpGrpcSpanExporterBuilderCustomizer> customizers) {
|
||||||
OtlpGrpcSpanExporterBuilder builder = OtlpGrpcSpanExporter.builder()
|
OtlpGrpcSpanExporterBuilder builder = OtlpGrpcSpanExporter.builder()
|
||||||
.setEndpoint(connectionDetails.getUrl(Transport.GRPC));
|
.setEndpoint(connectionDetails.getUrl(Transport.GRPC))
|
||||||
|
.setTimeout(properties.getTimeout())
|
||||||
Duration timeout = properties.getTimeout();
|
.setConnectTimeout(properties.getConnectTimeout())
|
||||||
builder.setTimeout(timeout);
|
.setCompression(resolveCompression(properties, otlpProperties).name().toLowerCase(Locale.ROOT));
|
||||||
|
|
||||||
Duration connectTimeout = properties.getConnectTimeout();
|
|
||||||
builder.setConnectTimeout(connectTimeout);
|
|
||||||
|
|
||||||
String compression = properties.getCompression().name().toLowerCase(Locale.ROOT);
|
|
||||||
if (StringUtils.hasLength(compression)) {
|
|
||||||
builder.setCompression(compression);
|
|
||||||
}
|
|
||||||
|
|
||||||
Map<String, String> headers = new LinkedHashMap<>(otlpProperties.getHeaders());
|
Map<String, String> headers = new LinkedHashMap<>(otlpProperties.getHeaders());
|
||||||
headers.putAll(properties.getHeaders());
|
headers.putAll(properties.getHeaders());
|
||||||
headers.forEach(builder::addHeader);
|
headers.forEach(builder::addHeader);
|
||||||
|
|
||||||
meterProvider.ifAvailable(builder::setMeterProvider);
|
meterProvider.ifAvailable(builder::setMeterProvider);
|
||||||
configureSsl(connectionDetails, builder::setSslContext);
|
configureSsl(connectionDetails, builder::setSslContext);
|
||||||
customizers.orderedStream().forEach((customizer) -> customizer.customize(builder));
|
customizers.orderedStream().forEach((customizer) -> customizer.customize(builder));
|
||||||
return builder.build();
|
return builder.build();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private OtlpTracingProperties.Compression resolveCompression(OtlpTracingProperties properties,
|
||||||
|
OtlpProperties otlpProperties) {
|
||||||
|
OtlpTracingProperties.Compression compression = properties.getCompression();
|
||||||
|
if (compression != null) {
|
||||||
|
return compression;
|
||||||
|
}
|
||||||
|
OtlpProperties.Compression commonCompression = otlpProperties.getCompression();
|
||||||
|
if (commonCompression != null) {
|
||||||
|
return switch (commonCompression) {
|
||||||
|
case GZIP -> OtlpTracingProperties.Compression.GZIP;
|
||||||
|
case NONE -> OtlpTracingProperties.Compression.NONE;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
return OtlpTracingProperties.Compression.NONE;
|
||||||
|
}
|
||||||
|
|
||||||
private void configureSsl(OtlpTracingConnectionDetails connectionDetails,
|
private void configureSsl(OtlpTracingConnectionDetails connectionDetails,
|
||||||
SslContextConfigurer sslContextConfigurer) {
|
SslContextConfigurer sslContextConfigurer) {
|
||||||
SslBundle sslBundle = connectionDetails.getSslBundle();
|
SslBundle sslBundle = connectionDetails.getSslBundle();
|
||||||
@@ -230,32 +222,6 @@ final class OtlpTracingConfigurations {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static class HttpTransportCondition extends SpringBootCondition {
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public ConditionOutcome getMatchOutcome(ConditionContext context, AnnotatedTypeMetadata metadata) {
|
|
||||||
String tracingTransport = context.getEnvironment()
|
|
||||||
.getProperty("management.opentelemetry.tracing.export.otlp.transport");
|
|
||||||
String activeTransport = (tracingTransport != null) ? tracingTransport : "http";
|
|
||||||
return new ConditionOutcome("http".equalsIgnoreCase(activeTransport),
|
|
||||||
"Transport is " + activeTransport);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
static class GrpcTransportCondition extends SpringBootCondition {
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public ConditionOutcome getMatchOutcome(ConditionContext context, AnnotatedTypeMetadata metadata) {
|
|
||||||
String tracingTransport = context.getEnvironment()
|
|
||||||
.getProperty("management.opentelemetry.tracing.export.otlp.transport");
|
|
||||||
String activeTransport = (tracingTransport != null) ? tracingTransport : "http";
|
|
||||||
return new ConditionOutcome("grpc".equalsIgnoreCase(activeTransport),
|
|
||||||
"Transport is " + activeTransport);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
+3
-3
@@ -59,7 +59,7 @@ public class OtlpTracingProperties {
|
|||||||
/**
|
/**
|
||||||
* Method used to compress the payload.
|
* Method used to compress the payload.
|
||||||
*/
|
*/
|
||||||
private Compression compression = Compression.NONE;
|
private @Nullable Compression compression;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Custom HTTP headers you want to pass to the collector, for example auth headers.
|
* Custom HTTP headers you want to pass to the collector, for example auth headers.
|
||||||
@@ -100,11 +100,11 @@ public class OtlpTracingProperties {
|
|||||||
this.transport = transport;
|
this.transport = transport;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Compression getCompression() {
|
public @Nullable Compression getCompression() {
|
||||||
return this.compression;
|
return this.compression;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setCompression(Compression compression) {
|
public void setCompression(@Nullable Compression compression) {
|
||||||
this.compression = compression;
|
this.compression = compression;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+35
@@ -134,6 +134,41 @@ class OtlpTracingAutoConfigurationIntegrationTests {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void httpSpanExporterFallsBackToCommonCompressionWhenSignalSpecificCompressionIsNotSet() {
|
||||||
|
this.mockWebServer.enqueue(new MockResponse());
|
||||||
|
this.contextRunner
|
||||||
|
.withPropertyValues("management.opentelemetry.otlp.compression=gzip",
|
||||||
|
"management.opentelemetry.tracing.export.otlp.endpoint=http://localhost:%d/test"
|
||||||
|
.formatted(this.mockWebServer.getPort()))
|
||||||
|
.run((context) -> {
|
||||||
|
context.getBean(Tracer.class).nextSpan().name("test").end();
|
||||||
|
assertThat(context.getBean(OtlpHttpSpanExporter.class).flush())
|
||||||
|
.isSameAs(CompletableResultCode.ofSuccess());
|
||||||
|
RecordedRequest request = this.mockWebServer.takeRequest(10, TimeUnit.SECONDS);
|
||||||
|
assertThat(request).isNotNull();
|
||||||
|
assertThat(request.getHeader("Content-Encoding")).isEqualTo("gzip");
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void httpSpanExporterSignalSpecificCompressionWinsOverCommonCompression() {
|
||||||
|
this.mockWebServer.enqueue(new MockResponse());
|
||||||
|
this.contextRunner
|
||||||
|
.withPropertyValues("management.opentelemetry.otlp.compression=gzip",
|
||||||
|
"management.opentelemetry.tracing.export.otlp.compression=none",
|
||||||
|
"management.opentelemetry.tracing.export.otlp.endpoint=http://localhost:%d/test"
|
||||||
|
.formatted(this.mockWebServer.getPort()))
|
||||||
|
.run((context) -> {
|
||||||
|
context.getBean(Tracer.class).nextSpan().name("test").end();
|
||||||
|
assertThat(context.getBean(OtlpHttpSpanExporter.class).flush())
|
||||||
|
.isSameAs(CompletableResultCode.ofSuccess());
|
||||||
|
RecordedRequest request = this.mockWebServer.takeRequest(10, TimeUnit.SECONDS);
|
||||||
|
assertThat(request).isNotNull();
|
||||||
|
assertThat(request.getHeader("Content-Encoding")).isNull();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void grpcSpanExporterShouldExportSpans() {
|
void grpcSpanExporterShouldExportSpans() {
|
||||||
this.contextRunner
|
this.contextRunner
|
||||||
|
|||||||
+30
@@ -42,6 +42,11 @@ public class OtlpProperties {
|
|||||||
*/
|
*/
|
||||||
private final Map<String, String> headers = new LinkedHashMap<>();
|
private final Map<String, String> headers = new LinkedHashMap<>();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Method used to compress the payload.
|
||||||
|
*/
|
||||||
|
private @Nullable Compression compression;
|
||||||
|
|
||||||
public @Nullable String getEndpoint() {
|
public @Nullable String getEndpoint() {
|
||||||
return this.endpoint;
|
return this.endpoint;
|
||||||
}
|
}
|
||||||
@@ -54,4 +59,29 @@ public class OtlpProperties {
|
|||||||
return this.headers;
|
return this.headers;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public @Nullable Compression getCompression() {
|
||||||
|
return this.compression;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setCompression(@Nullable Compression compression) {
|
||||||
|
this.compression = compression;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Compression methods.
|
||||||
|
*/
|
||||||
|
public enum Compression {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gzip compression.
|
||||||
|
*/
|
||||||
|
GZIP,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* No compression.
|
||||||
|
*/
|
||||||
|
NONE
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
+27
-25
@@ -16,7 +16,6 @@
|
|||||||
|
|
||||||
package org.springframework.boot.opentelemetry.autoconfigure.logging.otlp;
|
package org.springframework.boot.opentelemetry.autoconfigure.logging.otlp;
|
||||||
|
|
||||||
import java.time.Duration;
|
|
||||||
import java.util.LinkedHashMap;
|
import java.util.LinkedHashMap;
|
||||||
import java.util.Locale;
|
import java.util.Locale;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
@@ -78,13 +77,11 @@ final class OtlpLoggingConfigurations {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@ConditionalOnProperty("management.opentelemetry.logging.export.otlp.endpoint")
|
@ConditionalOnProperty("management.opentelemetry.logging.export.otlp.endpoint")
|
||||||
@SuppressWarnings("unused")
|
|
||||||
static class LoggingEndpoint {
|
static class LoggingEndpoint {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@ConditionalOnProperty("management.opentelemetry.otlp.endpoint")
|
@ConditionalOnProperty("management.opentelemetry.otlp.endpoint")
|
||||||
@SuppressWarnings("unused")
|
|
||||||
static class CommonEndpoint {
|
static class CommonEndpoint {
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -112,6 +109,9 @@ final class OtlpLoggingConfigurations {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getUrl(Transport transport) {
|
public String getUrl(Transport transport) {
|
||||||
|
Assert.state(transport == this.properties.getTransport(),
|
||||||
|
"Requested transport %s doesn't match configured transport %s".formatted(transport,
|
||||||
|
this.properties.getTransport()));
|
||||||
String endpoint = this.properties.getEndpoint();
|
String endpoint = this.properties.getEndpoint();
|
||||||
if (!StringUtils.hasLength(endpoint)) {
|
if (!StringUtils.hasLength(endpoint)) {
|
||||||
endpoint = this.otlpProperties.getEndpoint();
|
endpoint = this.otlpProperties.getEndpoint();
|
||||||
@@ -152,20 +152,13 @@ final class OtlpLoggingConfigurations {
|
|||||||
ObjectProvider<MeterProvider> meterProvider,
|
ObjectProvider<MeterProvider> meterProvider,
|
||||||
ObjectProvider<OtlpHttpLogRecordExporterBuilderCustomizer> customizers) {
|
ObjectProvider<OtlpHttpLogRecordExporterBuilderCustomizer> customizers) {
|
||||||
OtlpHttpLogRecordExporterBuilder builder = OtlpHttpLogRecordExporter.builder()
|
OtlpHttpLogRecordExporterBuilder builder = OtlpHttpLogRecordExporter.builder()
|
||||||
.setEndpoint(connectionDetails.getUrl(Transport.HTTP));
|
.setEndpoint(connectionDetails.getUrl(Transport.HTTP))
|
||||||
|
.setTimeout(properties.getTimeout())
|
||||||
Duration timeout = properties.getTimeout();
|
.setConnectTimeout(properties.getConnectTimeout())
|
||||||
builder.setTimeout(timeout);
|
.setCompression(resolveCompression(properties, otlpProperties).name().toLowerCase(Locale.US));
|
||||||
|
|
||||||
String compression = properties.getCompression().name().toLowerCase(Locale.ROOT);
|
|
||||||
if (StringUtils.hasLength(compression)) {
|
|
||||||
builder.setCompression(compression);
|
|
||||||
}
|
|
||||||
|
|
||||||
Map<String, String> headers = new LinkedHashMap<>(otlpProperties.getHeaders());
|
Map<String, String> headers = new LinkedHashMap<>(otlpProperties.getHeaders());
|
||||||
headers.putAll(properties.getHeaders());
|
headers.putAll(properties.getHeaders());
|
||||||
headers.forEach(builder::addHeader);
|
headers.forEach(builder::addHeader);
|
||||||
|
|
||||||
meterProvider.ifAvailable(builder::setMeterProvider);
|
meterProvider.ifAvailable(builder::setMeterProvider);
|
||||||
configureSsl(connectionDetails, builder::setSslContext);
|
configureSsl(connectionDetails, builder::setSslContext);
|
||||||
customizers.orderedStream().forEach((customizer) -> customizer.customize(builder));
|
customizers.orderedStream().forEach((customizer) -> customizer.customize(builder));
|
||||||
@@ -179,26 +172,35 @@ final class OtlpLoggingConfigurations {
|
|||||||
ObjectProvider<MeterProvider> meterProvider,
|
ObjectProvider<MeterProvider> meterProvider,
|
||||||
ObjectProvider<OtlpGrpcLogRecordExporterBuilderCustomizer> customizers) {
|
ObjectProvider<OtlpGrpcLogRecordExporterBuilderCustomizer> customizers) {
|
||||||
OtlpGrpcLogRecordExporterBuilder builder = OtlpGrpcLogRecordExporter.builder()
|
OtlpGrpcLogRecordExporterBuilder builder = OtlpGrpcLogRecordExporter.builder()
|
||||||
.setEndpoint(connectionDetails.getUrl(Transport.GRPC));
|
.setEndpoint(connectionDetails.getUrl(Transport.GRPC))
|
||||||
|
.setTimeout(properties.getTimeout())
|
||||||
Duration timeout = properties.getTimeout();
|
.setConnectTimeout(properties.getConnectTimeout())
|
||||||
builder.setTimeout(timeout);
|
.setCompression(resolveCompression(properties, otlpProperties).name().toLowerCase(Locale.US));
|
||||||
|
|
||||||
String compression = properties.getCompression().name().toLowerCase(Locale.ROOT);
|
|
||||||
if (StringUtils.hasLength(compression)) {
|
|
||||||
builder.setCompression(compression);
|
|
||||||
}
|
|
||||||
|
|
||||||
Map<String, String> headers = new LinkedHashMap<>(otlpProperties.getHeaders());
|
Map<String, String> headers = new LinkedHashMap<>(otlpProperties.getHeaders());
|
||||||
headers.putAll(properties.getHeaders());
|
headers.putAll(properties.getHeaders());
|
||||||
headers.forEach(builder::addHeader);
|
headers.forEach(builder::addHeader);
|
||||||
|
|
||||||
meterProvider.ifAvailable(builder::setMeterProvider);
|
meterProvider.ifAvailable(builder::setMeterProvider);
|
||||||
configureSsl(connectionDetails, builder::setSslContext);
|
configureSsl(connectionDetails, builder::setSslContext);
|
||||||
customizers.orderedStream().forEach((customizer) -> customizer.customize(builder));
|
customizers.orderedStream().forEach((customizer) -> customizer.customize(builder));
|
||||||
return builder.build();
|
return builder.build();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private OtlpLoggingProperties.Compression resolveCompression(OtlpLoggingProperties properties,
|
||||||
|
OtlpProperties otlpProperties) {
|
||||||
|
OtlpLoggingProperties.Compression compression = properties.getCompression();
|
||||||
|
if (compression != null) {
|
||||||
|
return compression;
|
||||||
|
}
|
||||||
|
OtlpProperties.Compression commonCompression = otlpProperties.getCompression();
|
||||||
|
if (commonCompression != null) {
|
||||||
|
return switch (commonCompression) {
|
||||||
|
case GZIP -> OtlpLoggingProperties.Compression.GZIP;
|
||||||
|
case NONE -> OtlpLoggingProperties.Compression.NONE;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
return OtlpLoggingProperties.Compression.NONE;
|
||||||
|
}
|
||||||
|
|
||||||
private void configureSsl(OtlpLoggingConnectionDetails connectionDetails,
|
private void configureSsl(OtlpLoggingConnectionDetails connectionDetails,
|
||||||
SslContextConfigurer sslContextConfigurer) {
|
SslContextConfigurer sslContextConfigurer) {
|
||||||
SslBundle sslBundle = connectionDetails.getSslBundle();
|
SslBundle sslBundle = connectionDetails.getSslBundle();
|
||||||
|
|||||||
+3
-3
@@ -59,7 +59,7 @@ public class OtlpLoggingProperties {
|
|||||||
/**
|
/**
|
||||||
* Method used to compress the payload.
|
* Method used to compress the payload.
|
||||||
*/
|
*/
|
||||||
private Compression compression = Compression.NONE;
|
private @Nullable Compression compression;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Custom HTTP headers you want to pass to the collector, for example auth headers.
|
* Custom HTTP headers you want to pass to the collector, for example auth headers.
|
||||||
@@ -100,11 +100,11 @@ public class OtlpLoggingProperties {
|
|||||||
this.transport = transport;
|
this.transport = transport;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Compression getCompression() {
|
public @Nullable Compression getCompression() {
|
||||||
return this.compression;
|
return this.compression;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setCompression(Compression compression) {
|
public void setCompression(@Nullable Compression compression) {
|
||||||
this.compression = compression;
|
this.compression = compression;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+31
@@ -108,6 +108,37 @@ class OtlpLoggingAutoConfigurationIntegrationTests {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void httpLogRecordExporterFallsBackToCommonCompressionWhenSignalSpecificCompressionIsNotSet() {
|
||||||
|
this.mockWebServer.enqueue(new MockResponse());
|
||||||
|
this.contextRunner
|
||||||
|
.withPropertyValues("management.opentelemetry.logging.export.otlp.endpoint=http://localhost:%d/v1/logs"
|
||||||
|
.formatted(this.mockWebServer.getPort()), "management.opentelemetry.otlp.compression=gzip")
|
||||||
|
.run((context) -> {
|
||||||
|
logMessage(context);
|
||||||
|
RecordedRequest request = this.mockWebServer.takeRequest(10, TimeUnit.SECONDS);
|
||||||
|
assertThat(request).isNotNull();
|
||||||
|
assertThat(request.getHeader("Content-Encoding")).isEqualTo("gzip");
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void httpLogRecordExporterSignalSpecificCompressionWinsOverCommonCompression() {
|
||||||
|
this.mockWebServer.enqueue(new MockResponse());
|
||||||
|
this.contextRunner
|
||||||
|
.withPropertyValues(
|
||||||
|
"management.opentelemetry.logging.export.otlp.endpoint=http://localhost:%d/v1/logs"
|
||||||
|
.formatted(this.mockWebServer.getPort()),
|
||||||
|
"management.opentelemetry.logging.export.otlp.compression=none",
|
||||||
|
"management.opentelemetry.otlp.compression=gzip")
|
||||||
|
.run((context) -> {
|
||||||
|
logMessage(context);
|
||||||
|
RecordedRequest request = this.mockWebServer.takeRequest(10, TimeUnit.SECONDS);
|
||||||
|
assertThat(request).isNotNull();
|
||||||
|
assertThat(request.getHeader("Content-Encoding")).isNull();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
private static void logMessage(ApplicationContext context) {
|
private static void logMessage(ApplicationContext context) {
|
||||||
SdkLoggerProvider loggerProvider = context.getBean(SdkLoggerProvider.class);
|
SdkLoggerProvider loggerProvider = context.getBean(SdkLoggerProvider.class);
|
||||||
loggerProvider.get("test")
|
loggerProvider.get("test")
|
||||||
|
|||||||
+13
-1
@@ -323,14 +323,26 @@ class OtlpLoggingAutoConfigurationTests {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void shouldAppendLogsPathToCommonEndpoint() {
|
void shouldAppendLogsPathToCommonEndpointForHttpTransport() {
|
||||||
OtlpLoggingProperties properties = new OtlpLoggingProperties();
|
OtlpLoggingProperties properties = new OtlpLoggingProperties();
|
||||||
|
properties.setTransport(Transport.HTTP);
|
||||||
OtlpProperties otlpProperties = new OtlpProperties();
|
OtlpProperties otlpProperties = new OtlpProperties();
|
||||||
otlpProperties.setEndpoint("http://localhost:4318");
|
otlpProperties.setEndpoint("http://localhost:4318");
|
||||||
PropertiesOtlpLoggingConnectionDetails connectionDetails = new PropertiesOtlpLoggingConnectionDetails(
|
PropertiesOtlpLoggingConnectionDetails connectionDetails = new PropertiesOtlpLoggingConnectionDetails(
|
||||||
properties, otlpProperties, null);
|
properties, otlpProperties, null);
|
||||||
|
|
||||||
assertThat(connectionDetails.getUrl(Transport.HTTP)).isEqualTo("http://localhost:4318/v1/logs");
|
assertThat(connectionDetails.getUrl(Transport.HTTP)).isEqualTo("http://localhost:4318/v1/logs");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void shouldNotAppendLogsPathToCommonEndpointForGrpcTransport() {
|
||||||
|
OtlpLoggingProperties properties = new OtlpLoggingProperties();
|
||||||
|
properties.setTransport(Transport.GRPC);
|
||||||
|
OtlpProperties otlpProperties = new OtlpProperties();
|
||||||
|
otlpProperties.setEndpoint("http://localhost:4318");
|
||||||
|
PropertiesOtlpLoggingConnectionDetails connectionDetails = new PropertiesOtlpLoggingConnectionDetails(
|
||||||
|
properties, otlpProperties, null);
|
||||||
|
|
||||||
assertThat(connectionDetails.getUrl(Transport.GRPC)).isEqualTo("http://localhost:4318");
|
assertThat(connectionDetails.getUrl(Transport.GRPC)).isEqualTo("http://localhost:4318");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user