Add transport and connect timeout properties for OTLP logging

Closes gh-42528
Closes gh-42527
This commit is contained in:
Moritz Halbritter 2024-10-08 15:59:49 +02:00
parent b997c0c53a
commit e6165b0311
20 changed files with 134 additions and 83 deletions

View File

@ -14,7 +14,7 @@
* limitations under the License.
*/
package org.springframework.boot.actuate.autoconfigure.logging.opentelemetry;
package org.springframework.boot.actuate.autoconfigure.logging;
import io.opentelemetry.api.OpenTelemetry;
import io.opentelemetry.sdk.logs.LogRecordProcessor;

View File

@ -14,7 +14,7 @@
* limitations under the License.
*/
package org.springframework.boot.actuate.autoconfigure.logging.opentelemetry;
package org.springframework.boot.actuate.autoconfigure.logging;
import io.opentelemetry.sdk.logs.SdkLoggerProvider;
import io.opentelemetry.sdk.logs.SdkLoggerProviderBuilder;

View File

@ -1,20 +0,0 @@
/*
* Copyright 2012-2024 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/**
* Auto-configuration for OpenTelemetry logging with OTLP.
*/
package org.springframework.boot.actuate.autoconfigure.logging.opentelemetry.otlp;

View File

@ -14,7 +14,7 @@
* limitations under the License.
*/
package org.springframework.boot.actuate.autoconfigure.logging.opentelemetry.otlp;
package org.springframework.boot.actuate.autoconfigure.logging.otlp;
import io.opentelemetry.api.OpenTelemetry;
import io.opentelemetry.exporter.otlp.http.logs.OtlpHttpLogRecordExporter;

View File

@ -14,19 +14,21 @@
* limitations under the License.
*/
package org.springframework.boot.actuate.autoconfigure.logging.opentelemetry.otlp;
package org.springframework.boot.actuate.autoconfigure.logging.otlp;
import java.util.Locale;
import io.opentelemetry.exporter.otlp.http.logs.OtlpHttpLogRecordExporter;
import io.opentelemetry.exporter.otlp.http.logs.OtlpHttpLogRecordExporterBuilder;
import io.opentelemetry.exporter.otlp.logs.OtlpGrpcLogRecordExporter;
import io.opentelemetry.exporter.otlp.logs.OtlpGrpcLogRecordExporterBuilder;
import org.springframework.boot.actuate.autoconfigure.opentelemetry.otlp.Transport;
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.util.Assert;
/**
* Configurations imported by {@link OtlpLoggingAutoConfiguration}.
@ -61,6 +63,9 @@ final class OtlpLoggingConfigurations {
@Override
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()));
return this.properties.getEndpoint();
}
@ -69,18 +74,33 @@ final class OtlpLoggingConfigurations {
}
@Configuration(proxyBeanMethods = false)
@ConditionalOnMissingBean({ OtlpGrpcLogRecordExporter.class, OtlpHttpLogRecordExporter.class })
@ConditionalOnBean(OtlpLoggingConnectionDetails.class)
static class Exporters {
@ConditionalOnMissingBean(value = OtlpHttpLogRecordExporter.class,
type = "io.opentelemetry.exporter.otlp.logs.OtlpGrpcLogRecordExporter")
@ConditionalOnBean(OtlpLoggingConnectionDetails.class)
@Bean
@ConditionalOnProperty(prefix = "management.otlp.logging", name = "transport", havingValue = "http",
matchIfMissing = true)
OtlpHttpLogRecordExporter otlpHttpLogRecordExporter(OtlpLoggingProperties properties,
OtlpLoggingConnectionDetails connectionDetails) {
OtlpHttpLogRecordExporterBuilder builder = OtlpHttpLogRecordExporter.builder()
.setEndpoint(connectionDetails.getUrl(Transport.HTTP))
.setCompression(properties.getCompression().name().toLowerCase(Locale.US))
.setTimeout(properties.getTimeout());
.setTimeout(properties.getTimeout())
.setConnectTimeout(properties.getConnectTimeout())
.setCompression(properties.getCompression().name().toLowerCase(Locale.US));
properties.getHeaders().forEach(builder::addHeader);
return builder.build();
}
@Bean
@ConditionalOnProperty(prefix = "management.otlp.logging", name = "transport", havingValue = "grpc")
OtlpGrpcLogRecordExporter otlpGrpcLogRecordExporter(OtlpLoggingProperties properties,
OtlpLoggingConnectionDetails connectionDetails) {
OtlpGrpcLogRecordExporterBuilder builder = OtlpGrpcLogRecordExporter.builder()
.setEndpoint(connectionDetails.getUrl(Transport.GRPC))
.setTimeout(properties.getTimeout())
.setConnectTimeout(properties.getConnectTimeout())
.setCompression(properties.getCompression().name().toLowerCase(Locale.US));
properties.getHeaders().forEach(builder::addHeader);
return builder.build();
}

View File

@ -14,9 +14,8 @@
* limitations under the License.
*/
package org.springframework.boot.actuate.autoconfigure.logging.opentelemetry.otlp;
package org.springframework.boot.actuate.autoconfigure.logging.otlp;
import org.springframework.boot.actuate.autoconfigure.opentelemetry.otlp.Transport;
import org.springframework.boot.autoconfigure.service.connection.ConnectionDetails;
/**

View File

@ -14,13 +14,12 @@
* limitations under the License.
*/
package org.springframework.boot.actuate.autoconfigure.logging.opentelemetry.otlp;
package org.springframework.boot.actuate.autoconfigure.logging.otlp;
import java.time.Duration;
import java.util.HashMap;
import java.util.Map;
import org.springframework.boot.actuate.autoconfigure.opentelemetry.otlp.Compression;
import org.springframework.boot.context.properties.ConfigurationProperties;
/**
@ -45,6 +44,16 @@ public class OtlpLoggingProperties {
*/
private Duration timeout = Duration.ofSeconds(10);
/**
* Connect timeout for the OTel collector connection.
*/
private Duration connectTimeout = Duration.ofSeconds(10);
/**
* Transport used to send the spans.
*/
private Transport transport = Transport.HTTP;
/**
* Method used to compress the payload.
*/
@ -71,6 +80,22 @@ public class OtlpLoggingProperties {
this.timeout = timeout;
}
public Duration getConnectTimeout() {
return this.connectTimeout;
}
public void setConnectTimeout(Duration connectTimeout) {
this.connectTimeout = connectTimeout;
}
public Transport getTransport() {
return this.transport;
}
public void setTransport(Transport transport) {
this.transport = transport;
}
public Compression getCompression() {
return this.compression;
}
@ -83,4 +108,18 @@ public class OtlpLoggingProperties {
return this.headers;
}
public enum Compression {
/**
* Gzip compression.
*/
GZIP,
/**
* No compression.
*/
NONE
}
}

View File

@ -14,7 +14,7 @@
* limitations under the License.
*/
package org.springframework.boot.actuate.autoconfigure.opentelemetry.otlp;
package org.springframework.boot.actuate.autoconfigure.logging.otlp;
/**
* Transport used to send OTLP data.

View File

@ -15,6 +15,6 @@
*/
/**
* Auto-configuration for OpenTelemetry logging.
* Auto-configuration for exporting logs with OTLP.
*/
package org.springframework.boot.actuate.autoconfigure.logging.opentelemetry;
package org.springframework.boot.actuate.autoconfigure.logging.otlp;

View File

@ -1,20 +0,0 @@
/*
* Copyright 2012-2024 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/**
* Classes for OpenTelemetry's OTLP.
*/
package org.springframework.boot.actuate.autoconfigure.opentelemetry.otlp;

View File

@ -14,7 +14,7 @@
* limitations under the License.
*/
package org.springframework.boot.actuate.autoconfigure.logging.opentelemetry;
package org.springframework.boot.actuate.autoconfigure.logging;
import java.util.Collection;
import java.util.concurrent.atomic.AtomicInteger;

View File

@ -14,7 +14,7 @@
* limitations under the License.
*/
package org.springframework.boot.actuate.autoconfigure.logging.opentelemetry.otlp;
package org.springframework.boot.actuate.autoconfigure.logging.otlp;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
@ -32,7 +32,7 @@ import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.springframework.boot.actuate.autoconfigure.logging.opentelemetry.OpenTelemetryLoggingAutoConfiguration;
import org.springframework.boot.actuate.autoconfigure.logging.OpenTelemetryLoggingAutoConfiguration;
import org.springframework.boot.actuate.autoconfigure.opentelemetry.OpenTelemetryAutoConfiguration;
import org.springframework.boot.autoconfigure.AutoConfigurations;
import org.springframework.boot.test.context.runner.ApplicationContextRunner;

View File

@ -14,7 +14,7 @@
* limitations under the License.
*/
package org.springframework.boot.actuate.autoconfigure.logging.opentelemetry.otlp;
package org.springframework.boot.actuate.autoconfigure.logging.otlp;
import io.opentelemetry.exporter.otlp.http.logs.OtlpHttpLogRecordExporter;
import io.opentelemetry.exporter.otlp.logs.OtlpGrpcLogRecordExporter;
@ -24,8 +24,7 @@ import org.junit.jupiter.api.Test;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.ValueSource;
import org.springframework.boot.actuate.autoconfigure.logging.opentelemetry.otlp.OtlpLoggingConfigurations.ConnectionDetails.PropertiesOtlpLoggingConnectionDetails;
import org.springframework.boot.actuate.autoconfigure.opentelemetry.otlp.Transport;
import org.springframework.boot.actuate.autoconfigure.logging.otlp.OtlpLoggingConfigurations.ConnectionDetails.PropertiesOtlpLoggingConnectionDetails;
import org.springframework.boot.autoconfigure.AutoConfigurations;
import org.springframework.boot.test.context.FilteredClassLoader;
import org.springframework.boot.test.context.runner.ApplicationContextRunner;
@ -100,6 +99,40 @@ class OtlpLoggingAutoConfigurationTests {
}
@Test
void shouldUseHttpExporterIfTransportIsNotSet() {
this.contextRunner.withPropertyValues("management.otlp.logging.endpoint=http://localhost:4318/v1/logs")
.run((context) -> {
assertThat(context).hasSingleBean(OtlpHttpLogRecordExporter.class)
.hasSingleBean(LogRecordExporter.class);
assertThat(context).doesNotHaveBean(OtlpGrpcLogRecordExporter.class);
});
}
@Test
void shouldUseHttpExporterIfTransportIsSetToHttp() {
this.contextRunner
.withPropertyValues("management.otlp.logging.endpoint=http://localhost:4318/v1/logs",
"management.otlp.logging.transport=http")
.run((context) -> {
assertThat(context).hasSingleBean(OtlpHttpLogRecordExporter.class)
.hasSingleBean(LogRecordExporter.class);
assertThat(context).doesNotHaveBean(OtlpGrpcLogRecordExporter.class);
});
}
@Test
void shouldUseGrpcExporterIfTransportIsSetToGrpc() {
this.contextRunner
.withPropertyValues("management.otlp.logging.endpoint=http://localhost:4318/v1/logs",
"management.otlp.logging.transport=grpc")
.run((context) -> {
assertThat(context).hasSingleBean(OtlpGrpcLogRecordExporter.class)
.hasSingleBean(LogRecordExporter.class);
assertThat(context).doesNotHaveBean(OtlpHttpLogRecordExporter.class);
});
}
@Configuration(proxyBeanMethods = false)
public static class CustomHttpExporterConfiguration {

View File

@ -16,8 +16,8 @@
package org.springframework.boot.docker.compose.service.connection.otlp;
import org.springframework.boot.actuate.autoconfigure.logging.opentelemetry.otlp.OtlpLoggingConnectionDetails;
import org.springframework.boot.actuate.autoconfigure.opentelemetry.otlp.Transport;
import org.springframework.boot.actuate.autoconfigure.logging.otlp.OtlpLoggingConnectionDetails;
import org.springframework.boot.actuate.autoconfigure.logging.otlp.Transport;
import org.springframework.boot.docker.compose.service.connection.test.DockerComposeTest;
import org.springframework.boot.testsupport.container.TestImage;

View File

@ -16,8 +16,8 @@
package org.springframework.boot.docker.compose.service.connection.otlp;
import org.springframework.boot.actuate.autoconfigure.logging.opentelemetry.otlp.OtlpLoggingConnectionDetails;
import org.springframework.boot.actuate.autoconfigure.opentelemetry.otlp.Transport;
import org.springframework.boot.actuate.autoconfigure.logging.otlp.OtlpLoggingConnectionDetails;
import org.springframework.boot.actuate.autoconfigure.logging.otlp.Transport;
import org.springframework.boot.docker.compose.service.connection.test.DockerComposeTest;
import org.springframework.boot.testsupport.container.TestImage;

View File

@ -16,8 +16,8 @@
package org.springframework.boot.docker.compose.service.connection.otlp;
import org.springframework.boot.actuate.autoconfigure.logging.opentelemetry.otlp.OtlpLoggingConnectionDetails;
import org.springframework.boot.actuate.autoconfigure.opentelemetry.otlp.Transport;
import org.springframework.boot.actuate.autoconfigure.logging.otlp.OtlpLoggingConnectionDetails;
import org.springframework.boot.actuate.autoconfigure.logging.otlp.Transport;
import org.springframework.boot.docker.compose.core.RunningService;
import org.springframework.boot.docker.compose.service.connection.DockerComposeConnectionDetailsFactory;
import org.springframework.boot.docker.compose.service.connection.DockerComposeConnectionSource;
@ -40,7 +40,7 @@ class OpenTelemetryLoggingDockerComposeConnectionDetailsFactory
OpenTelemetryLoggingDockerComposeConnectionDetailsFactory() {
super(OPENTELEMETRY_IMAGE_NAMES,
"org.springframework.boot.actuate.autoconfigure.logging.opentelemetry.otlp.OtlpLoggingAutoConfiguration");
"org.springframework.boot.actuate.autoconfigure.logging.otlp.OtlpLoggingAutoConfiguration");
}
@Override

View File

@ -22,9 +22,9 @@ import org.testcontainers.junit.jupiter.Container;
import org.testcontainers.junit.jupiter.Testcontainers;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.actuate.autoconfigure.logging.opentelemetry.otlp.OtlpLoggingAutoConfiguration;
import org.springframework.boot.actuate.autoconfigure.logging.opentelemetry.otlp.OtlpLoggingConnectionDetails;
import org.springframework.boot.actuate.autoconfigure.opentelemetry.otlp.Transport;
import org.springframework.boot.actuate.autoconfigure.logging.otlp.OtlpLoggingAutoConfiguration;
import org.springframework.boot.actuate.autoconfigure.logging.otlp.OtlpLoggingConnectionDetails;
import org.springframework.boot.actuate.autoconfigure.logging.otlp.Transport;
import org.springframework.boot.autoconfigure.ImportAutoConfiguration;
import org.springframework.boot.testcontainers.service.connection.ServiceConnection;
import org.springframework.boot.testsupport.container.TestImage;

View File

@ -22,9 +22,9 @@ import org.testcontainers.junit.jupiter.Container;
import org.testcontainers.junit.jupiter.Testcontainers;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.actuate.autoconfigure.logging.opentelemetry.otlp.OtlpLoggingConnectionDetails;
import org.springframework.boot.actuate.autoconfigure.opentelemetry.otlp.Transport;
import org.springframework.boot.actuate.autoconfigure.tracing.otlp.OtlpAutoConfiguration;
import org.springframework.boot.actuate.autoconfigure.logging.otlp.OtlpLoggingConnectionDetails;
import org.springframework.boot.actuate.autoconfigure.logging.otlp.Transport;
import org.springframework.boot.actuate.autoconfigure.tracing.otlp.OtlpTracingAutoConfiguration;
import org.springframework.boot.autoconfigure.ImportAutoConfiguration;
import org.springframework.boot.testcontainers.service.connection.ServiceConnection;
import org.springframework.boot.testsupport.container.TestImage;
@ -59,7 +59,7 @@ class OpenTelemetryLoggingContainerConnectionDetailsFactoryIntegrationTests {
}
@Configuration(proxyBeanMethods = false)
@ImportAutoConfiguration(OtlpAutoConfiguration.class)
@ImportAutoConfiguration(OtlpTracingAutoConfiguration.class)
static class TestConfiguration {
}

View File

@ -18,8 +18,8 @@ package org.springframework.boot.testcontainers.service.connection.otlp;
import org.testcontainers.grafana.LgtmStackContainer;
import org.springframework.boot.actuate.autoconfigure.logging.opentelemetry.otlp.OtlpLoggingConnectionDetails;
import org.springframework.boot.actuate.autoconfigure.opentelemetry.otlp.Transport;
import org.springframework.boot.actuate.autoconfigure.logging.otlp.OtlpLoggingConnectionDetails;
import org.springframework.boot.actuate.autoconfigure.logging.otlp.Transport;
import org.springframework.boot.testcontainers.service.connection.ContainerConnectionDetailsFactory;
import org.springframework.boot.testcontainers.service.connection.ContainerConnectionSource;
import org.springframework.boot.testcontainers.service.connection.ServiceConnection;
@ -37,7 +37,7 @@ class GrafanaOpenTelemetryLoggingContainerConnectionDetailsFactory
GrafanaOpenTelemetryLoggingContainerConnectionDetailsFactory() {
super(ANY_CONNECTION_NAME,
"org.springframework.boot.actuate.autoconfigure.logging.opentelemetry.otlp.OtlpLoggingAutoConfiguration");
"org.springframework.boot.actuate.autoconfigure.logging.otlp.OtlpLoggingAutoConfiguration");
}
@Override

View File

@ -19,8 +19,8 @@ package org.springframework.boot.testcontainers.service.connection.otlp;
import org.testcontainers.containers.Container;
import org.testcontainers.containers.GenericContainer;
import org.springframework.boot.actuate.autoconfigure.logging.opentelemetry.otlp.OtlpLoggingConnectionDetails;
import org.springframework.boot.actuate.autoconfigure.opentelemetry.otlp.Transport;
import org.springframework.boot.actuate.autoconfigure.logging.otlp.OtlpLoggingConnectionDetails;
import org.springframework.boot.actuate.autoconfigure.logging.otlp.Transport;
import org.springframework.boot.testcontainers.service.connection.ContainerConnectionDetailsFactory;
import org.springframework.boot.testcontainers.service.connection.ContainerConnectionSource;
import org.springframework.boot.testcontainers.service.connection.ServiceConnection;
@ -43,7 +43,7 @@ class OpenTelemetryLoggingContainerConnectionDetailsFactory
OpenTelemetryLoggingContainerConnectionDetailsFactory() {
super("otel/opentelemetry-collector-contrib",
"org.springframework.boot.actuate.autoconfigure.logging.opentelemetry.otlp.OtlpLoggingAutoConfiguration");
"org.springframework.boot.actuate.autoconfigure.logging.otlp.OtlpLoggingAutoConfiguration");
}
@Override