From 2d6f2488b7a8b861837499e2b17ce06efb831582 Mon Sep 17 00:00:00 2001 From: Toshiaki Maki Date: Fri, 31 May 2024 15:41:39 +0900 Subject: [PATCH 1/2] Provide auto configuration for OpenTelemetry Logs See gh-40961 --- .../logs/OpenTelemetryAutoConfiguration.java | 62 +++++ .../SdkLoggerProviderBuilderCustomizer.java | 38 +++ .../logs/otlp/OtlpLogsAutoConfiguration.java | 41 ++++ .../logs/otlp/OtlpLogsConfigurations.java | 87 +++++++ .../logs/otlp/OtlpLogsConnectionDetails.java | 35 +++ .../logs/otlp/OtlpProperties.java | 103 ++++++++ .../autoconfigure/logs/otlp/package-info.java | 20 ++ .../autoconfigure/logs/package-info.java | 20 ++ ...ot.autoconfigure.AutoConfiguration.imports | 2 + .../OpenTelemetryAutoConfigurationTests.java | 226 ++++++++++++++++++ ...LogsAutoConfigurationIntegrationTests.java | 132 ++++++++++ .../otlp/OtlpLogsAutoConfigurationTests.java | 130 ++++++++++ 12 files changed, 896 insertions(+) create mode 100644 spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/logs/OpenTelemetryAutoConfiguration.java create mode 100644 spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/logs/SdkLoggerProviderBuilderCustomizer.java create mode 100644 spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/logs/otlp/OtlpLogsAutoConfiguration.java create mode 100644 spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/logs/otlp/OtlpLogsConfigurations.java create mode 100644 spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/logs/otlp/OtlpLogsConnectionDetails.java create mode 100644 spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/logs/otlp/OtlpProperties.java create mode 100644 spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/logs/otlp/package-info.java create mode 100644 spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/logs/package-info.java create mode 100644 spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/logs/OpenTelemetryAutoConfigurationTests.java create mode 100644 spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/logs/otlp/OtlpLogsAutoConfigurationIntegrationTests.java create mode 100644 spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/logs/otlp/OtlpLogsAutoConfigurationTests.java diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/logs/OpenTelemetryAutoConfiguration.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/logs/OpenTelemetryAutoConfiguration.java new file mode 100644 index 00000000000..9e41b658923 --- /dev/null +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/logs/OpenTelemetryAutoConfiguration.java @@ -0,0 +1,62 @@ +/* + * 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. + */ + +package org.springframework.boot.actuate.autoconfigure.logs; + +import io.opentelemetry.api.OpenTelemetry; +import io.opentelemetry.sdk.logs.LogRecordProcessor; +import io.opentelemetry.sdk.logs.SdkLoggerProvider; +import io.opentelemetry.sdk.logs.SdkLoggerProviderBuilder; +import io.opentelemetry.sdk.logs.export.BatchLogRecordProcessor; +import io.opentelemetry.sdk.logs.export.LogRecordExporter; +import io.opentelemetry.sdk.resources.Resource; + +import org.springframework.beans.factory.ObjectProvider; +import org.springframework.boot.autoconfigure.AutoConfiguration; +import org.springframework.boot.autoconfigure.EnableAutoConfiguration; +import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; +import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; +import org.springframework.context.annotation.Bean; + +/** + * {@link EnableAutoConfiguration Auto-configuration} for OpenTelemetry Logs. + * + * @author Toshiaki Maki + * @since 3.4.0 + */ +@AutoConfiguration("openTelemetryLogsAutoConfiguration") +@ConditionalOnClass({ SdkLoggerProvider.class, OpenTelemetry.class }) +public class OpenTelemetryAutoConfiguration { + + @Bean + @ConditionalOnMissingBean + public BatchLogRecordProcessor batchLogRecordProcessor(ObjectProvider logRecordExporters) { + return BatchLogRecordProcessor.builder(LogRecordExporter.composite(logRecordExporters.orderedStream().toList())) + .build(); + } + + @Bean + @ConditionalOnMissingBean + public SdkLoggerProvider otelSdkLoggerProvider(Resource resource, + ObjectProvider logRecordProcessors, + ObjectProvider customizers) { + SdkLoggerProviderBuilder builder = SdkLoggerProvider.builder().setResource(resource); + logRecordProcessors.orderedStream().forEach(builder::addLogRecordProcessor); + customizers.orderedStream().forEach((customizer) -> customizer.customize(builder)); + return builder.build(); + } + +} diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/logs/SdkLoggerProviderBuilderCustomizer.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/logs/SdkLoggerProviderBuilderCustomizer.java new file mode 100644 index 00000000000..47d9ac382a3 --- /dev/null +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/logs/SdkLoggerProviderBuilderCustomizer.java @@ -0,0 +1,38 @@ +/* + * 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. + */ + +package org.springframework.boot.actuate.autoconfigure.logs; + +import io.opentelemetry.sdk.logs.SdkLoggerProvider; +import io.opentelemetry.sdk.logs.SdkLoggerProviderBuilder; + +/** + * Callback interface that can be used to customize the {@link SdkLoggerProviderBuilder} + * that is used to create the auto-configured {@link SdkLoggerProvider}. + * + * @author Toshiaki Maki + * @since 3.4.0 + */ +@FunctionalInterface +public interface SdkLoggerProviderBuilderCustomizer { + + /** + * Customize the given {@code builder}. + * @param builder the builder to customize + */ + void customize(SdkLoggerProviderBuilder builder); + +} diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/logs/otlp/OtlpLogsAutoConfiguration.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/logs/otlp/OtlpLogsAutoConfiguration.java new file mode 100644 index 00000000000..3bf302a9d16 --- /dev/null +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/logs/otlp/OtlpLogsAutoConfiguration.java @@ -0,0 +1,41 @@ +/* + * 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. + */ + +package org.springframework.boot.actuate.autoconfigure.logs.otlp; + +import io.opentelemetry.api.OpenTelemetry; +import io.opentelemetry.exporter.otlp.http.logs.OtlpHttpLogRecordExporter; +import io.opentelemetry.sdk.logs.SdkLoggerProvider; + +import org.springframework.boot.autoconfigure.AutoConfiguration; +import org.springframework.boot.autoconfigure.EnableAutoConfiguration; +import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; +import org.springframework.boot.context.properties.EnableConfigurationProperties; +import org.springframework.context.annotation.Import; + +/** + * {@link EnableAutoConfiguration Auto-configuration} for OTLP Logs. + * + * @author Toshiaki Maki + * @since 3.4.0 + */ +@AutoConfiguration +@ConditionalOnClass({ SdkLoggerProvider.class, OpenTelemetry.class, OtlpHttpLogRecordExporter.class }) +@EnableConfigurationProperties(OtlpProperties.class) +@Import({ OtlpLogsConfigurations.ConnectionDetails.class, OtlpLogsConfigurations.Exporters.class }) +public class OtlpLogsAutoConfiguration { + +} diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/logs/otlp/OtlpLogsConfigurations.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/logs/otlp/OtlpLogsConfigurations.java new file mode 100644 index 00000000000..f739549a4b8 --- /dev/null +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/logs/otlp/OtlpLogsConfigurations.java @@ -0,0 +1,87 @@ +/* + * 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. + */ + +package org.springframework.boot.actuate.autoconfigure.logs.otlp; + +import java.util.Locale; + +import io.opentelemetry.exporter.otlp.http.logs.OtlpHttpLogRecordExporter; +import io.opentelemetry.exporter.otlp.http.logs.OtlpHttpLogRecordExporterBuilder; + +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; + +/** + * Configurations imported by {@link OtlpLogsAutoConfiguration}. + * + * @author Toshiaki Maki + * @since 3.4.0 + */ +public class OtlpLogsConfigurations { + + @Configuration(proxyBeanMethods = false) + static class ConnectionDetails { + + @Bean + @ConditionalOnMissingBean + @ConditionalOnProperty(prefix = "management.otlp.logs", name = "endpoint") + OtlpLogsConnectionDetails otlpLogsConnectionDetails(OtlpProperties properties) { + return new PropertiesOtlpLogsConnectionDetails(properties); + } + + /** + * Adapts {@link OtlpProperties} to {@link OtlpLogsConnectionDetails}. + */ + static class PropertiesOtlpLogsConnectionDetails implements OtlpLogsConnectionDetails { + + private final OtlpProperties properties; + + PropertiesOtlpLogsConnectionDetails(OtlpProperties properties) { + this.properties = properties; + } + + @Override + public String getUrl() { + return this.properties.getEndpoint(); + } + + } + + } + + @Configuration(proxyBeanMethods = false) + static class Exporters { + + @ConditionalOnMissingBean(value = OtlpHttpLogRecordExporter.class, + type = "io.opentelemetry.exporter.otlp.logs.OtlpGrpcLogRecordExporter") + @ConditionalOnBean(OtlpLogsConnectionDetails.class) + @Bean + OtlpHttpLogRecordExporter otlpHttpLogRecordExporter(OtlpProperties properties, + OtlpLogsConnectionDetails connectionDetails) { + OtlpHttpLogRecordExporterBuilder builder = OtlpHttpLogRecordExporter.builder() + .setEndpoint(connectionDetails.getUrl()) + .setCompression(properties.getCompression().name().toLowerCase(Locale.US)) + .setTimeout(properties.getTimeout()); + properties.getHeaders().forEach(builder::addHeader); + return builder.build(); + } + + } + +} diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/logs/otlp/OtlpLogsConnectionDetails.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/logs/otlp/OtlpLogsConnectionDetails.java new file mode 100644 index 00000000000..83ee7d1648e --- /dev/null +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/logs/otlp/OtlpLogsConnectionDetails.java @@ -0,0 +1,35 @@ +/* + * 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. + */ + +package org.springframework.boot.actuate.autoconfigure.logs.otlp; + +import org.springframework.boot.autoconfigure.service.connection.ConnectionDetails; + +/** + * Details required to establish a connection to an OpenTelemetry logs service. + * + * @author Toshiaki Maki + * @since 3.4.0 + */ +public interface OtlpLogsConnectionDetails extends ConnectionDetails { + + /** + * Address to where logs will be published. + * @return the address to where logs will be published + */ + String getUrl(); + +} diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/logs/otlp/OtlpProperties.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/logs/otlp/OtlpProperties.java new file mode 100644 index 00000000000..e520ccf2dce --- /dev/null +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/logs/otlp/OtlpProperties.java @@ -0,0 +1,103 @@ +/* + * 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. + */ + +package org.springframework.boot.actuate.autoconfigure.logs.otlp; + +import java.time.Duration; +import java.util.HashMap; +import java.util.Map; + +import org.springframework.boot.context.properties.ConfigurationProperties; + +/** + * Configuration properties for exporting logs using OTLP. + * + * @author Jonatan Ivanov + * @since 3.4.0 + */ +@ConfigurationProperties("management.otlp.logs") +public class OtlpProperties { + + /** + * URL to the OTel collector's HTTP API. + */ + private String endpoint; + + /** + * Call timeout for the OTel Collector to process an exported batch of data. This + * timeout spans the entire call: resolving DNS, connecting, writing the request body, + * server processing, and reading the response body. If the call requires redirects or + * retries all must complete within one timeout period. + */ + private Duration timeout = Duration.ofSeconds(10); + + /** + * Method used to compress the payload. + */ + private Compression compression = Compression.NONE; + + /** + * Custom HTTP headers you want to pass to the collector, for example auth headers. + */ + private Map headers = new HashMap<>(); + + public String getEndpoint() { + return this.endpoint; + } + + public void setEndpoint(String endpoint) { + this.endpoint = endpoint; + } + + public Duration getTimeout() { + return this.timeout; + } + + public void setTimeout(Duration timeout) { + this.timeout = timeout; + } + + public Compression getCompression() { + return this.compression; + } + + public void setCompression(Compression compression) { + this.compression = compression; + } + + public Map getHeaders() { + return this.headers; + } + + public void setHeaders(Map headers) { + this.headers = headers; + } + + public enum Compression { + + /** + * Gzip compression. + */ + GZIP, + + /** + * No compression. + */ + NONE + + } + +} diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/logs/otlp/package-info.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/logs/otlp/package-info.java new file mode 100644 index 00000000000..5c5a7d42cb9 --- /dev/null +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/logs/otlp/package-info.java @@ -0,0 +1,20 @@ +/* + * Copyright 2012-2023 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 logs with OTLP. + */ +package org.springframework.boot.actuate.autoconfigure.logs.otlp; diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/logs/package-info.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/logs/package-info.java new file mode 100644 index 00000000000..6db2a10b3e3 --- /dev/null +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/logs/package-info.java @@ -0,0 +1,20 @@ +/* + * Copyright 2012-2019 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 Logs. + */ +package org.springframework.boot.actuate.autoconfigure.logs; diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports index d3a6fc7ead5..77b1d8aa837 100644 --- a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports @@ -35,6 +35,8 @@ org.springframework.boot.actuate.autoconfigure.ldap.LdapHealthContributorAutoCon org.springframework.boot.actuate.autoconfigure.liquibase.LiquibaseEndpointAutoConfiguration org.springframework.boot.actuate.autoconfigure.logging.LogFileWebEndpointAutoConfiguration org.springframework.boot.actuate.autoconfigure.logging.LoggersEndpointAutoConfiguration +org.springframework.boot.actuate.autoconfigure.logs.OpenTelemetryAutoConfiguration +org.springframework.boot.actuate.autoconfigure.logs.otlp.OtlpLogsAutoConfiguration org.springframework.boot.actuate.autoconfigure.mail.MailHealthContributorAutoConfiguration org.springframework.boot.actuate.autoconfigure.management.HeapDumpWebEndpointAutoConfiguration org.springframework.boot.actuate.autoconfigure.management.ThreadDumpEndpointAutoConfiguration diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/logs/OpenTelemetryAutoConfigurationTests.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/logs/OpenTelemetryAutoConfigurationTests.java new file mode 100644 index 00000000000..08415d359b0 --- /dev/null +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/logs/OpenTelemetryAutoConfigurationTests.java @@ -0,0 +1,226 @@ +/* + * 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. + */ + +package org.springframework.boot.actuate.autoconfigure.logs; + +import java.util.Collection; +import java.util.concurrent.atomic.AtomicInteger; + +import io.opentelemetry.context.Context; +import io.opentelemetry.sdk.common.CompletableResultCode; +import io.opentelemetry.sdk.logs.LogRecordProcessor; +import io.opentelemetry.sdk.logs.ReadWriteLogRecord; +import io.opentelemetry.sdk.logs.SdkLoggerProvider; +import io.opentelemetry.sdk.logs.SdkLoggerProviderBuilder; +import io.opentelemetry.sdk.logs.data.LogRecordData; +import io.opentelemetry.sdk.logs.export.BatchLogRecordProcessor; +import io.opentelemetry.sdk.logs.export.LogRecordExporter; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.ValueSource; + +import org.springframework.boot.autoconfigure.AutoConfigurations; +import org.springframework.boot.test.context.FilteredClassLoader; +import org.springframework.boot.test.context.runner.ApplicationContextRunner; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +import static org.assertj.core.api.Assertions.assertThat; + +/** + * Tests for {@link OpenTelemetryAutoConfiguration}. + * + * @author Toshiaki Maki + */ +class OpenTelemetryAutoConfigurationTests { + + private final ApplicationContextRunner contextRunner; + + OpenTelemetryAutoConfigurationTests() { + this.contextRunner = new ApplicationContextRunner().withConfiguration(AutoConfigurations.of( + org.springframework.boot.actuate.autoconfigure.opentelemetry.OpenTelemetryAutoConfiguration.class, + OpenTelemetryAutoConfiguration.class)); + } + + @Test + void shouldSupplyBeans() { + this.contextRunner.run((context) -> { + assertThat(context).hasSingleBean(BatchLogRecordProcessor.class); + assertThat(context).hasSingleBean(SdkLoggerProvider.class); + }); + } + + @ParameterizedTest + @ValueSource(strings = { "io.opentelemetry.sdk.logs", "io.opentelemetry.api" }) + void shouldNotSupplyBeansIfDependencyIsMissing(String packageName) { + this.contextRunner.withClassLoader(new FilteredClassLoader(packageName)).run((context) -> { + assertThat(context).doesNotHaveBean(BatchLogRecordProcessor.class); + assertThat(context).doesNotHaveBean(SdkLoggerProvider.class); + }); + } + + @Test + void shouldBackOffOnCustomBeans() { + this.contextRunner.withUserConfiguration(CustomConfig.class).run((context) -> { + assertThat(context).hasBean("customBatchLogRecordProcessor").hasSingleBean(BatchLogRecordProcessor.class); + assertThat(context.getBeansOfType(LogRecordProcessor.class)).hasSize(1); + assertThat(context).hasBean("customSdkLoggerProvider").hasSingleBean(SdkLoggerProvider.class); + }); + } + + @Test + void shouldAllowMultipleLogRecordExporter() { + this.contextRunner.withUserConfiguration(MultipleLogRecordExporterConfig.class).run((context) -> { + assertThat(context).hasSingleBean(BatchLogRecordProcessor.class); + assertThat(context.getBeansOfType(LogRecordExporter.class)).hasSize(2); + assertThat(context).hasBean("customLogRecordExporter1"); + assertThat(context).hasBean("customLogRecordExporter2"); + }); + } + + @Test + void shouldAllowMultipleLogRecordProcessorInAdditionToBatchLogRecordProcessor() { + this.contextRunner.withUserConfiguration(MultipleLogRecordProcessorConfig.class).run((context) -> { + assertThat(context).hasSingleBean(BatchLogRecordProcessor.class); + assertThat(context).hasSingleBean(SdkLoggerProvider.class); + assertThat(context.getBeansOfType(LogRecordProcessor.class)).hasSize(3); + assertThat(context).hasBean("batchLogRecordProcessor"); + assertThat(context).hasBean("customLogRecordProcessor1"); + assertThat(context).hasBean("customLogRecordProcessor2"); + }); + } + + @Test + void shouldAllowMultipleSdkLoggerProviderBuilderCustomizer() { + this.contextRunner.withUserConfiguration(MultipleSdkLoggerProviderBuilderCustomizerConfig.class) + .run((context) -> { + assertThat(context).hasSingleBean(SdkLoggerProvider.class); + assertThat(context.getBeansOfType(NoopSdkLoggerProviderBuilderCustomizer.class)).hasSize(2); + assertThat(context).hasBean("customSdkLoggerProviderBuilderCustomizer1"); + assertThat(context).hasBean("customSdkLoggerProviderBuilderCustomizer2"); + assertThat(context + .getBean("customSdkLoggerProviderBuilderCustomizer1", NoopSdkLoggerProviderBuilderCustomizer.class) + .called()).isEqualTo(1); + assertThat(context + .getBean("customSdkLoggerProviderBuilderCustomizer2", NoopSdkLoggerProviderBuilderCustomizer.class) + .called()).isEqualTo(1); + }); + } + + @Configuration(proxyBeanMethods = false) + public static class CustomConfig { + + @Bean + public BatchLogRecordProcessor customBatchLogRecordProcessor() { + return BatchLogRecordProcessor.builder(new NoopLogRecordExporter()).build(); + } + + @Bean + public SdkLoggerProvider customSdkLoggerProvider() { + return SdkLoggerProvider.builder().build(); + } + + } + + @Configuration(proxyBeanMethods = false) + public static class MultipleLogRecordExporterConfig { + + @Bean + public LogRecordExporter customLogRecordExporter1() { + return new NoopLogRecordExporter(); + } + + @Bean + public LogRecordExporter customLogRecordExporter2() { + return new NoopLogRecordExporter(); + } + + } + + @Configuration(proxyBeanMethods = false) + public static class MultipleLogRecordProcessorConfig { + + @Bean + public LogRecordProcessor customLogRecordProcessor1() { + return new NoopLogRecordProcessor(); + } + + @Bean + public LogRecordProcessor customLogRecordProcessor2() { + return new NoopLogRecordProcessor(); + } + + } + + @Configuration(proxyBeanMethods = false) + public static class MultipleSdkLoggerProviderBuilderCustomizerConfig { + + @Bean + public SdkLoggerProviderBuilderCustomizer customSdkLoggerProviderBuilderCustomizer1() { + return new NoopSdkLoggerProviderBuilderCustomizer(); + } + + @Bean + public SdkLoggerProviderBuilderCustomizer customSdkLoggerProviderBuilderCustomizer2() { + return new NoopSdkLoggerProviderBuilderCustomizer(); + } + + } + + static class NoopLogRecordExporter implements LogRecordExporter { + + @Override + public CompletableResultCode export(Collection logs) { + return CompletableResultCode.ofSuccess(); + } + + @Override + public CompletableResultCode flush() { + return CompletableResultCode.ofSuccess(); + } + + @Override + public CompletableResultCode shutdown() { + return CompletableResultCode.ofSuccess(); + } + + } + + static class NoopLogRecordProcessor implements LogRecordProcessor { + + @Override + public void onEmit(Context context, ReadWriteLogRecord logRecord) { + + } + + } + + static class NoopSdkLoggerProviderBuilderCustomizer implements SdkLoggerProviderBuilderCustomizer { + + final AtomicInteger called = new AtomicInteger(0); + + @Override + public void customize(SdkLoggerProviderBuilder builder) { + this.called.incrementAndGet(); + } + + int called() { + return this.called.get(); + } + + } + +} diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/logs/otlp/OtlpLogsAutoConfigurationIntegrationTests.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/logs/otlp/OtlpLogsAutoConfigurationIntegrationTests.java new file mode 100644 index 00000000000..933076186a1 --- /dev/null +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/logs/otlp/OtlpLogsAutoConfigurationIntegrationTests.java @@ -0,0 +1,132 @@ +/* + * 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. + */ + +package org.springframework.boot.actuate.autoconfigure.logs.otlp; + +import java.io.IOException; +import java.nio.charset.StandardCharsets; +import java.time.Instant; +import java.util.concurrent.TimeUnit; + +import io.opentelemetry.api.logs.Severity; +import io.opentelemetry.sdk.logs.SdkLoggerProvider; +import okhttp3.mockwebserver.MockResponse; +import okhttp3.mockwebserver.MockWebServer; +import okhttp3.mockwebserver.RecordedRequest; +import okio.Buffer; +import okio.GzipSource; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import org.springframework.boot.actuate.autoconfigure.logs.OpenTelemetryAutoConfiguration; +import org.springframework.boot.autoconfigure.AutoConfigurations; +import org.springframework.boot.test.context.runner.ApplicationContextRunner; + +import static org.assertj.core.api.Assertions.assertThat; + +/** + * Integration tests for {@link OtlpLogsAutoConfiguration}. + * + * @author Toshiaki Maki + */ +public class OtlpLogsAutoConfigurationIntegrationTests { + + private final ApplicationContextRunner contextRunner = new ApplicationContextRunner() + .withPropertyValues("spring.application.name=otlp-logs-test", + "management.otlp.logs.headers.Authorization=Bearer my-token") + .withConfiguration(AutoConfigurations.of( + org.springframework.boot.actuate.autoconfigure.opentelemetry.OpenTelemetryAutoConfiguration.class, + OpenTelemetryAutoConfiguration.class, OtlpLogsAutoConfiguration.class)); + + private final MockWebServer mockWebServer = new MockWebServer(); + + @BeforeEach + void setUp() throws IOException { + this.mockWebServer.start(); + } + + @AfterEach + void tearDown() throws IOException { + this.mockWebServer.close(); + } + + @Test + void httpLogRecordExporterShouldUseProtobufAndNoCompressionByDefault() { + this.mockWebServer.enqueue(new MockResponse()); + this.contextRunner + .withPropertyValues( + "management.otlp.logs.endpoint=http://localhost:%d/v1/logs".formatted(this.mockWebServer.getPort())) + .run((context) -> { + SdkLoggerProvider loggerProvider = context.getBean(SdkLoggerProvider.class); + loggerProvider.get("test") + .logRecordBuilder() + .setSeverity(Severity.INFO) + .setSeverityText("INFO") + .setBody("Hello") + .setTimestamp(Instant.now()) + .emit(); + RecordedRequest request = this.mockWebServer.takeRequest(10, TimeUnit.SECONDS); + assertThat(request).isNotNull(); + assertThat(request.getRequestLine()).contains("/v1/logs"); + assertThat(request.getHeader("Content-Type")).isEqualTo("application/x-protobuf"); + assertThat(request.getHeader("Content-Encoding")).isNull(); + assertThat(request.getBodySize()).isPositive(); + try (Buffer body = request.getBody()) { + String bodyString = body.readString(StandardCharsets.UTF_8); + assertThat(bodyString).contains("otlp-logs-test"); + assertThat(bodyString).contains("test"); + assertThat(bodyString).contains("INFO"); + + assertThat(bodyString).contains("Hello"); + } + }); + } + + @Test + void httpLogRecordExporterCanBeConfiguredToUseGzipCompression() { + this.mockWebServer.enqueue(new MockResponse()); + this.contextRunner + .withPropertyValues( + "management.otlp.logs.endpoint=http://localhost:%d/v1/logs".formatted(this.mockWebServer.getPort()), + "management.otlp.logs.compression=gzip") + .run((context) -> { + SdkLoggerProvider loggerProvider = context.getBean(SdkLoggerProvider.class); + loggerProvider.get("test") + .logRecordBuilder() + .setBody("Hello") + .setSeverity(Severity.INFO) + .setSeverityText("INFO") + .setTimestamp(Instant.now()) + .emit(); + RecordedRequest request = this.mockWebServer.takeRequest(10, TimeUnit.SECONDS); + assertThat(request).isNotNull(); + assertThat(request.getRequestLine()).contains("/v1/logs"); + assertThat(request.getHeader("Content-Type")).isEqualTo("application/x-protobuf"); + assertThat(request.getHeader("Content-Encoding")).isEqualTo("gzip"); + assertThat(request.getBodySize()).isPositive(); + try (Buffer uncompressed = new Buffer(); Buffer body = request.getBody()) { + uncompressed.writeAll(new GzipSource(body)); + String bodyString = uncompressed.readString(StandardCharsets.UTF_8); + assertThat(bodyString).contains("otlp-logs-test"); + assertThat(bodyString).contains("test"); + assertThat(bodyString).contains("INFO"); + assertThat(bodyString).contains("Hello"); + } + }); + } + +} diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/logs/otlp/OtlpLogsAutoConfigurationTests.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/logs/otlp/OtlpLogsAutoConfigurationTests.java new file mode 100644 index 00000000000..ac5d4bd62fa --- /dev/null +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/logs/otlp/OtlpLogsAutoConfigurationTests.java @@ -0,0 +1,130 @@ +/* + * 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. + */ + +package org.springframework.boot.actuate.autoconfigure.logs.otlp; + +import io.opentelemetry.exporter.otlp.http.logs.OtlpHttpLogRecordExporter; +import io.opentelemetry.exporter.otlp.logs.OtlpGrpcLogRecordExporter; +import io.opentelemetry.sdk.logs.export.LogRecordExporter; +import okhttp3.HttpUrl; +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.logs.otlp.OtlpLogsConfigurations.ConnectionDetails.PropertiesOtlpLogsConnectionDetails; +import org.springframework.boot.autoconfigure.AutoConfigurations; +import org.springframework.boot.test.context.FilteredClassLoader; +import org.springframework.boot.test.context.runner.ApplicationContextRunner; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +import static org.assertj.core.api.Assertions.assertThat; + +/** + * Tests for {@link OtlpLogsAutoConfiguration}. + * + * @author Toshiaki Maki + */ +class OtlpLogsAutoConfigurationTests { + + private final ApplicationContextRunner contextRunner = new ApplicationContextRunner() + .withConfiguration(AutoConfigurations.of(OtlpLogsAutoConfiguration.class)); + + @Test + void shouldNotSupplyBeansIfPropertyIsNotSet() { + this.contextRunner.run((context) -> { + assertThat(context).doesNotHaveBean(OtlpLogsConnectionDetails.class); + assertThat(context).doesNotHaveBean(OtlpHttpLogRecordExporter.class); + }); + } + + @Test + void shouldSupplyBeans() { + this.contextRunner.withPropertyValues("management.otlp.logs.endpoint=http://localhost:4318/v1/logs") + .run((context) -> { + assertThat(context).hasSingleBean(OtlpLogsConnectionDetails.class); + assertThat(context).hasSingleBean(OtlpHttpLogRecordExporter.class) + .hasSingleBean(LogRecordExporter.class); + }); + } + + @ParameterizedTest + @ValueSource(strings = { "io.opentelemetry.sdk.logs", "io.opentelemetry.api", + "io.opentelemetry.exporter.otlp.http.logs" }) + void shouldNotSupplyBeansIfDependencyIsMissing(String packageName) { + this.contextRunner.withClassLoader(new FilteredClassLoader(packageName)).run((context) -> { + assertThat(context).doesNotHaveBean(OtlpLogsConnectionDetails.class); + assertThat(context).doesNotHaveBean(OtlpHttpLogRecordExporter.class); + }); + } + + @Test + void shouldBackOffWhenCustomHttpExporterIsDefined() { + this.contextRunner.withUserConfiguration(CustomHttpExporterConfiguration.class) + .run((context) -> assertThat(context).hasBean("customOtlpHttpLogRecordExporter") + .hasSingleBean(LogRecordExporter.class)); + } + + @Test + void shouldBackOffWhenCustomGrpcExporterIsDefined() { + this.contextRunner.withUserConfiguration(CustomGrpcExporterConfiguration.class) + .run((context) -> assertThat(context).hasBean("customOtlpGrpcLogRecordExporter") + .hasSingleBean(LogRecordExporter.class)); + } + + @Test + void shouldBackOffWhenCustomOtlpLogsConnectionDetailsIsDefined() { + this.contextRunner.withUserConfiguration(CustomOtlpLogsConnectionDetails.class).run((context) -> { + assertThat(context).hasSingleBean(OtlpLogsConnectionDetails.class) + .doesNotHaveBean(PropertiesOtlpLogsConnectionDetails.class); + OtlpHttpLogRecordExporter otlpHttpLogRecordExporter = context.getBean(OtlpHttpLogRecordExporter.class); + assertThat(otlpHttpLogRecordExporter).extracting("delegate.httpSender.url") + .isEqualTo(HttpUrl.get("https://otel.example.com/v1/logs")); + }); + + } + + @Configuration(proxyBeanMethods = false) + public static class CustomHttpExporterConfiguration { + + @Bean + public OtlpHttpLogRecordExporter customOtlpHttpLogRecordExporter() { + return OtlpHttpLogRecordExporter.builder().build(); + } + + } + + @Configuration(proxyBeanMethods = false) + public static class CustomGrpcExporterConfiguration { + + @Bean + public OtlpGrpcLogRecordExporter customOtlpGrpcLogRecordExporter() { + return OtlpGrpcLogRecordExporter.builder().build(); + } + + } + + @Configuration(proxyBeanMethods = false) + public static class CustomOtlpLogsConnectionDetails { + + @Bean + public OtlpLogsConnectionDetails customOtlpLogsConnectionDetails() { + return () -> "https://otel.example.com/v1/logs"; + } + + } + +} From cfa05716ef71c9f1923b215f7899a0751000a059 Mon Sep 17 00:00:00 2001 From: Moritz Halbritter Date: Thu, 27 Jun 2024 10:18:01 +0200 Subject: [PATCH 2/2] Polish "Provide auto configuration for OpenTelemetry Logs" See gh-40961 --- ...penTelemetryLoggingAutoConfiguration.java} | 13 ++-- .../SdkLoggerProviderBuilderCustomizer.java | 2 +- .../otlp/OtlpLoggingAutoConfiguration.java} | 10 +-- .../otlp/OtlpLoggingConfigurations.java} | 34 +++++---- .../otlp/OtlpLoggingConnectionDetails.java} | 8 +- .../otlp/OtlpLoggingProperties.java} | 12 +-- .../opentelemetry}/otlp/package-info.java | 4 +- .../opentelemetry}/package-info.java | 4 +- ...ot.autoconfigure.AutoConfiguration.imports | 4 +- ...lemetryLoggingAutoConfigurationTests.java} | 10 +-- ...ingAutoConfigurationIntegrationTests.java} | 76 +++++++++---------- .../OtlpLoggingAutoConfigurationTests.java} | 26 ++++--- 12 files changed, 99 insertions(+), 104 deletions(-) rename spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/{logs/OpenTelemetryAutoConfiguration.java => logging/opentelemetry/OpenTelemetryLoggingAutoConfiguration.java} (83%) rename spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/{logs => logging/opentelemetry}/SdkLoggerProviderBuilderCustomizer.java (93%) rename spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/{logs/otlp/OtlpLogsAutoConfiguration.java => logging/opentelemetry/otlp/OtlpLoggingAutoConfiguration.java} (78%) rename spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/{logs/otlp/OtlpLogsConfigurations.java => logging/opentelemetry/otlp/OtlpLoggingConfigurations.java} (64%) rename spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/{logs/otlp/OtlpLogsConnectionDetails.java => logging/opentelemetry/otlp/OtlpLoggingConnectionDetails.java} (82%) rename spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/{logs/otlp/OtlpProperties.java => logging/opentelemetry/otlp/OtlpLoggingProperties.java} (88%) rename spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/{logs => logging/opentelemetry}/otlp/package-info.java (81%) rename spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/{logs => logging/opentelemetry}/package-info.java (83%) rename spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/{logs/OpenTelemetryAutoConfigurationTests.java => logging/opentelemetry/OpenTelemetryLoggingAutoConfigurationTests.java} (96%) rename spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/{logs/otlp/OtlpLogsAutoConfigurationIntegrationTests.java => logging/opentelemetry/otlp/OtlpLoggingAutoConfigurationIntegrationTests.java} (61%) rename spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/{logs/otlp/OtlpLogsAutoConfigurationTests.java => logging/opentelemetry/otlp/OtlpLoggingAutoConfigurationTests.java} (76%) diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/logs/OpenTelemetryAutoConfiguration.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/logging/opentelemetry/OpenTelemetryLoggingAutoConfiguration.java similarity index 83% rename from spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/logs/OpenTelemetryAutoConfiguration.java rename to spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/logging/opentelemetry/OpenTelemetryLoggingAutoConfiguration.java index 9e41b658923..934be85562a 100644 --- a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/logs/OpenTelemetryAutoConfiguration.java +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/logging/opentelemetry/OpenTelemetryLoggingAutoConfiguration.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package org.springframework.boot.actuate.autoconfigure.logs; +package org.springframework.boot.actuate.autoconfigure.logging.opentelemetry; import io.opentelemetry.api.OpenTelemetry; import io.opentelemetry.sdk.logs.LogRecordProcessor; @@ -32,26 +32,25 @@ import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean import org.springframework.context.annotation.Bean; /** - * {@link EnableAutoConfiguration Auto-configuration} for OpenTelemetry Logs. + * {@link EnableAutoConfiguration Auto-configuration} for OpenTelemetry logging. * * @author Toshiaki Maki * @since 3.4.0 */ -@AutoConfiguration("openTelemetryLogsAutoConfiguration") +@AutoConfiguration @ConditionalOnClass({ SdkLoggerProvider.class, OpenTelemetry.class }) -public class OpenTelemetryAutoConfiguration { +public class OpenTelemetryLoggingAutoConfiguration { @Bean @ConditionalOnMissingBean - public BatchLogRecordProcessor batchLogRecordProcessor(ObjectProvider logRecordExporters) { + BatchLogRecordProcessor batchLogRecordProcessor(ObjectProvider logRecordExporters) { return BatchLogRecordProcessor.builder(LogRecordExporter.composite(logRecordExporters.orderedStream().toList())) .build(); } @Bean @ConditionalOnMissingBean - public SdkLoggerProvider otelSdkLoggerProvider(Resource resource, - ObjectProvider logRecordProcessors, + SdkLoggerProvider otelSdkLoggerProvider(Resource resource, ObjectProvider logRecordProcessors, ObjectProvider customizers) { SdkLoggerProviderBuilder builder = SdkLoggerProvider.builder().setResource(resource); logRecordProcessors.orderedStream().forEach(builder::addLogRecordProcessor); diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/logs/SdkLoggerProviderBuilderCustomizer.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/logging/opentelemetry/SdkLoggerProviderBuilderCustomizer.java similarity index 93% rename from spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/logs/SdkLoggerProviderBuilderCustomizer.java rename to spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/logging/opentelemetry/SdkLoggerProviderBuilderCustomizer.java index 47d9ac382a3..d58daf3ca3a 100644 --- a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/logs/SdkLoggerProviderBuilderCustomizer.java +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/logging/opentelemetry/SdkLoggerProviderBuilderCustomizer.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package org.springframework.boot.actuate.autoconfigure.logs; +package org.springframework.boot.actuate.autoconfigure.logging.opentelemetry; import io.opentelemetry.sdk.logs.SdkLoggerProvider; import io.opentelemetry.sdk.logs.SdkLoggerProviderBuilder; diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/logs/otlp/OtlpLogsAutoConfiguration.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/logging/opentelemetry/otlp/OtlpLoggingAutoConfiguration.java similarity index 78% rename from spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/logs/otlp/OtlpLogsAutoConfiguration.java rename to spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/logging/opentelemetry/otlp/OtlpLoggingAutoConfiguration.java index 3bf302a9d16..d398d6766d8 100644 --- a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/logs/otlp/OtlpLogsAutoConfiguration.java +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/logging/opentelemetry/otlp/OtlpLoggingAutoConfiguration.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package org.springframework.boot.actuate.autoconfigure.logs.otlp; +package org.springframework.boot.actuate.autoconfigure.logging.opentelemetry.otlp; import io.opentelemetry.api.OpenTelemetry; import io.opentelemetry.exporter.otlp.http.logs.OtlpHttpLogRecordExporter; @@ -27,15 +27,15 @@ import org.springframework.boot.context.properties.EnableConfigurationProperties import org.springframework.context.annotation.Import; /** - * {@link EnableAutoConfiguration Auto-configuration} for OTLP Logs. + * {@link EnableAutoConfiguration Auto-configuration} for OTLP logging. * * @author Toshiaki Maki * @since 3.4.0 */ @AutoConfiguration @ConditionalOnClass({ SdkLoggerProvider.class, OpenTelemetry.class, OtlpHttpLogRecordExporter.class }) -@EnableConfigurationProperties(OtlpProperties.class) -@Import({ OtlpLogsConfigurations.ConnectionDetails.class, OtlpLogsConfigurations.Exporters.class }) -public class OtlpLogsAutoConfiguration { +@EnableConfigurationProperties(OtlpLoggingProperties.class) +@Import({ OtlpLoggingConfigurations.ConnectionDetails.class, OtlpLoggingConfigurations.Exporters.class }) +public class OtlpLoggingAutoConfiguration { } diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/logs/otlp/OtlpLogsConfigurations.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/logging/opentelemetry/otlp/OtlpLoggingConfigurations.java similarity index 64% rename from spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/logs/otlp/OtlpLogsConfigurations.java rename to spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/logging/opentelemetry/otlp/OtlpLoggingConfigurations.java index f739549a4b8..7558efc6446 100644 --- a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/logs/otlp/OtlpLogsConfigurations.java +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/logging/opentelemetry/otlp/OtlpLoggingConfigurations.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package org.springframework.boot.actuate.autoconfigure.logs.otlp; +package org.springframework.boot.actuate.autoconfigure.logging.opentelemetry.otlp; import java.util.Locale; @@ -28,36 +28,38 @@ import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; /** - * Configurations imported by {@link OtlpLogsAutoConfiguration}. + * Configurations imported by {@link OtlpLoggingAutoConfiguration}. * * @author Toshiaki Maki - * @since 3.4.0 */ -public class OtlpLogsConfigurations { +final class OtlpLoggingConfigurations { + + private OtlpLoggingConfigurations() { + } @Configuration(proxyBeanMethods = false) static class ConnectionDetails { @Bean @ConditionalOnMissingBean - @ConditionalOnProperty(prefix = "management.otlp.logs", name = "endpoint") - OtlpLogsConnectionDetails otlpLogsConnectionDetails(OtlpProperties properties) { - return new PropertiesOtlpLogsConnectionDetails(properties); + @ConditionalOnProperty(prefix = "management.otlp.logging", name = "endpoint") + OtlpLoggingConnectionDetails otlpLogsConnectionDetails(OtlpLoggingProperties properties) { + return new PropertiesOtlpLoggingConnectionDetails(properties); } /** - * Adapts {@link OtlpProperties} to {@link OtlpLogsConnectionDetails}. + * Adapts {@link OtlpLoggingProperties} to {@link OtlpLoggingConnectionDetails}. */ - static class PropertiesOtlpLogsConnectionDetails implements OtlpLogsConnectionDetails { + static class PropertiesOtlpLoggingConnectionDetails implements OtlpLoggingConnectionDetails { - private final OtlpProperties properties; + private final OtlpLoggingProperties properties; - PropertiesOtlpLogsConnectionDetails(OtlpProperties properties) { + PropertiesOtlpLoggingConnectionDetails(OtlpLoggingProperties properties) { this.properties = properties; } @Override - public String getUrl() { + public String getEndpoint() { return this.properties.getEndpoint(); } @@ -70,12 +72,12 @@ public class OtlpLogsConfigurations { @ConditionalOnMissingBean(value = OtlpHttpLogRecordExporter.class, type = "io.opentelemetry.exporter.otlp.logs.OtlpGrpcLogRecordExporter") - @ConditionalOnBean(OtlpLogsConnectionDetails.class) + @ConditionalOnBean(OtlpLoggingConnectionDetails.class) @Bean - OtlpHttpLogRecordExporter otlpHttpLogRecordExporter(OtlpProperties properties, - OtlpLogsConnectionDetails connectionDetails) { + OtlpHttpLogRecordExporter otlpHttpLogRecordExporter(OtlpLoggingProperties properties, + OtlpLoggingConnectionDetails connectionDetails) { OtlpHttpLogRecordExporterBuilder builder = OtlpHttpLogRecordExporter.builder() - .setEndpoint(connectionDetails.getUrl()) + .setEndpoint(connectionDetails.getEndpoint()) .setCompression(properties.getCompression().name().toLowerCase(Locale.US)) .setTimeout(properties.getTimeout()); properties.getHeaders().forEach(builder::addHeader); diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/logs/otlp/OtlpLogsConnectionDetails.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/logging/opentelemetry/otlp/OtlpLoggingConnectionDetails.java similarity index 82% rename from spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/logs/otlp/OtlpLogsConnectionDetails.java rename to spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/logging/opentelemetry/otlp/OtlpLoggingConnectionDetails.java index 83ee7d1648e..f4d1dfb35a5 100644 --- a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/logs/otlp/OtlpLogsConnectionDetails.java +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/logging/opentelemetry/otlp/OtlpLoggingConnectionDetails.java @@ -14,22 +14,22 @@ * limitations under the License. */ -package org.springframework.boot.actuate.autoconfigure.logs.otlp; +package org.springframework.boot.actuate.autoconfigure.logging.opentelemetry.otlp; import org.springframework.boot.autoconfigure.service.connection.ConnectionDetails; /** - * Details required to establish a connection to an OpenTelemetry logs service. + * Details required to establish a connection to an OpenTelemetry logging service. * * @author Toshiaki Maki * @since 3.4.0 */ -public interface OtlpLogsConnectionDetails extends ConnectionDetails { +public interface OtlpLoggingConnectionDetails extends ConnectionDetails { /** * Address to where logs will be published. * @return the address to where logs will be published */ - String getUrl(); + String getEndpoint(); } diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/logs/otlp/OtlpProperties.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/logging/opentelemetry/otlp/OtlpLoggingProperties.java similarity index 88% rename from spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/logs/otlp/OtlpProperties.java rename to spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/logging/opentelemetry/otlp/OtlpLoggingProperties.java index e520ccf2dce..b7d484a9466 100644 --- a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/logs/otlp/OtlpProperties.java +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/logging/opentelemetry/otlp/OtlpLoggingProperties.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package org.springframework.boot.actuate.autoconfigure.logs.otlp; +package org.springframework.boot.actuate.autoconfigure.logging.opentelemetry.otlp; import java.time.Duration; import java.util.HashMap; @@ -28,8 +28,8 @@ import org.springframework.boot.context.properties.ConfigurationProperties; * @author Jonatan Ivanov * @since 3.4.0 */ -@ConfigurationProperties("management.otlp.logs") -public class OtlpProperties { +@ConfigurationProperties("management.otlp.logging") +public class OtlpLoggingProperties { /** * URL to the OTel collector's HTTP API. @@ -52,7 +52,7 @@ public class OtlpProperties { /** * Custom HTTP headers you want to pass to the collector, for example auth headers. */ - private Map headers = new HashMap<>(); + private final Map headers = new HashMap<>(); public String getEndpoint() { return this.endpoint; @@ -82,10 +82,6 @@ public class OtlpProperties { return this.headers; } - public void setHeaders(Map headers) { - this.headers = headers; - } - public enum Compression { /** diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/logs/otlp/package-info.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/logging/opentelemetry/otlp/package-info.java similarity index 81% rename from spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/logs/otlp/package-info.java rename to spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/logging/opentelemetry/otlp/package-info.java index 5c5a7d42cb9..167fb211c09 100644 --- a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/logs/otlp/package-info.java +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/logging/opentelemetry/otlp/package-info.java @@ -15,6 +15,6 @@ */ /** - * Auto-configuration for OpenTelemetry logs with OTLP. + * Auto-configuration for OpenTelemetry logging with OTLP. */ -package org.springframework.boot.actuate.autoconfigure.logs.otlp; +package org.springframework.boot.actuate.autoconfigure.logging.opentelemetry.otlp; diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/logs/package-info.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/logging/opentelemetry/package-info.java similarity index 83% rename from spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/logs/package-info.java rename to spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/logging/opentelemetry/package-info.java index 6db2a10b3e3..63ec3087114 100644 --- a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/logs/package-info.java +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/logging/opentelemetry/package-info.java @@ -15,6 +15,6 @@ */ /** - * Auto-configuration for OpenTelemetry Logs. + * Auto-configuration for OpenTelemetry logging. */ -package org.springframework.boot.actuate.autoconfigure.logs; +package org.springframework.boot.actuate.autoconfigure.logging.opentelemetry; diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports index 77b1d8aa837..3fcc8bf0204 100644 --- a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports @@ -35,8 +35,8 @@ org.springframework.boot.actuate.autoconfigure.ldap.LdapHealthContributorAutoCon org.springframework.boot.actuate.autoconfigure.liquibase.LiquibaseEndpointAutoConfiguration org.springframework.boot.actuate.autoconfigure.logging.LogFileWebEndpointAutoConfiguration org.springframework.boot.actuate.autoconfigure.logging.LoggersEndpointAutoConfiguration -org.springframework.boot.actuate.autoconfigure.logs.OpenTelemetryAutoConfiguration -org.springframework.boot.actuate.autoconfigure.logs.otlp.OtlpLogsAutoConfiguration +org.springframework.boot.actuate.autoconfigure.logging.opentelemetry.OpenTelemetryLoggingAutoConfiguration +org.springframework.boot.actuate.autoconfigure.logging.opentelemetry.otlp.OtlpLoggingAutoConfiguration org.springframework.boot.actuate.autoconfigure.mail.MailHealthContributorAutoConfiguration org.springframework.boot.actuate.autoconfigure.management.HeapDumpWebEndpointAutoConfiguration org.springframework.boot.actuate.autoconfigure.management.ThreadDumpEndpointAutoConfiguration diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/logs/OpenTelemetryAutoConfigurationTests.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/logging/opentelemetry/OpenTelemetryLoggingAutoConfigurationTests.java similarity index 96% rename from spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/logs/OpenTelemetryAutoConfigurationTests.java rename to spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/logging/opentelemetry/OpenTelemetryLoggingAutoConfigurationTests.java index 08415d359b0..00ddf95e3f5 100644 --- a/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/logs/OpenTelemetryAutoConfigurationTests.java +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/logging/opentelemetry/OpenTelemetryLoggingAutoConfigurationTests.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package org.springframework.boot.actuate.autoconfigure.logs; +package org.springframework.boot.actuate.autoconfigure.logging.opentelemetry; import java.util.Collection; import java.util.concurrent.atomic.AtomicInteger; @@ -41,18 +41,18 @@ import org.springframework.context.annotation.Configuration; import static org.assertj.core.api.Assertions.assertThat; /** - * Tests for {@link OpenTelemetryAutoConfiguration}. + * Tests for {@link OpenTelemetryLoggingAutoConfiguration}. * * @author Toshiaki Maki */ -class OpenTelemetryAutoConfigurationTests { +class OpenTelemetryLoggingAutoConfigurationTests { private final ApplicationContextRunner contextRunner; - OpenTelemetryAutoConfigurationTests() { + OpenTelemetryLoggingAutoConfigurationTests() { this.contextRunner = new ApplicationContextRunner().withConfiguration(AutoConfigurations.of( org.springframework.boot.actuate.autoconfigure.opentelemetry.OpenTelemetryAutoConfiguration.class, - OpenTelemetryAutoConfiguration.class)); + OpenTelemetryLoggingAutoConfiguration.class)); } @Test diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/logs/otlp/OtlpLogsAutoConfigurationIntegrationTests.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/logging/opentelemetry/otlp/OtlpLoggingAutoConfigurationIntegrationTests.java similarity index 61% rename from spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/logs/otlp/OtlpLogsAutoConfigurationIntegrationTests.java rename to spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/logging/opentelemetry/otlp/OtlpLoggingAutoConfigurationIntegrationTests.java index 933076186a1..71b4b55c9dd 100644 --- a/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/logs/otlp/OtlpLogsAutoConfigurationIntegrationTests.java +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/logging/opentelemetry/otlp/OtlpLoggingAutoConfigurationIntegrationTests.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package org.springframework.boot.actuate.autoconfigure.logs.otlp; +package org.springframework.boot.actuate.autoconfigure.logging.opentelemetry.otlp; import java.io.IOException; import java.nio.charset.StandardCharsets; @@ -32,25 +32,26 @@ import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; -import org.springframework.boot.actuate.autoconfigure.logs.OpenTelemetryAutoConfiguration; +import org.springframework.boot.actuate.autoconfigure.logging.opentelemetry.OpenTelemetryLoggingAutoConfiguration; +import org.springframework.boot.actuate.autoconfigure.opentelemetry.OpenTelemetryAutoConfiguration; import org.springframework.boot.autoconfigure.AutoConfigurations; import org.springframework.boot.test.context.runner.ApplicationContextRunner; +import org.springframework.context.ApplicationContext; import static org.assertj.core.api.Assertions.assertThat; /** - * Integration tests for {@link OtlpLogsAutoConfiguration}. + * Integration tests for {@link OtlpLoggingAutoConfiguration}. * * @author Toshiaki Maki */ -public class OtlpLogsAutoConfigurationIntegrationTests { +public class OtlpLoggingAutoConfigurationIntegrationTests { private final ApplicationContextRunner contextRunner = new ApplicationContextRunner() .withPropertyValues("spring.application.name=otlp-logs-test", - "management.otlp.logs.headers.Authorization=Bearer my-token") - .withConfiguration(AutoConfigurations.of( - org.springframework.boot.actuate.autoconfigure.opentelemetry.OpenTelemetryAutoConfiguration.class, - OpenTelemetryAutoConfiguration.class, OtlpLogsAutoConfiguration.class)); + "management.otlp.logging.headers.Authorization=Bearer my-token") + .withConfiguration(AutoConfigurations.of(OpenTelemetryAutoConfiguration.class, + OpenTelemetryLoggingAutoConfiguration.class, OtlpLoggingAutoConfiguration.class)); private final MockWebServer mockWebServer = new MockWebServer(); @@ -68,17 +69,10 @@ public class OtlpLogsAutoConfigurationIntegrationTests { void httpLogRecordExporterShouldUseProtobufAndNoCompressionByDefault() { this.mockWebServer.enqueue(new MockResponse()); this.contextRunner - .withPropertyValues( - "management.otlp.logs.endpoint=http://localhost:%d/v1/logs".formatted(this.mockWebServer.getPort())) + .withPropertyValues("management.otlp.logging.endpoint=http://localhost:%d/v1/logs" + .formatted(this.mockWebServer.getPort())) .run((context) -> { - SdkLoggerProvider loggerProvider = context.getBean(SdkLoggerProvider.class); - loggerProvider.get("test") - .logRecordBuilder() - .setSeverity(Severity.INFO) - .setSeverityText("INFO") - .setBody("Hello") - .setTimestamp(Instant.now()) - .emit(); + logMessage(context); RecordedRequest request = this.mockWebServer.takeRequest(10, TimeUnit.SECONDS); assertThat(request).isNotNull(); assertThat(request.getRequestLine()).contains("/v1/logs"); @@ -86,12 +80,7 @@ public class OtlpLogsAutoConfigurationIntegrationTests { assertThat(request.getHeader("Content-Encoding")).isNull(); assertThat(request.getBodySize()).isPositive(); try (Buffer body = request.getBody()) { - String bodyString = body.readString(StandardCharsets.UTF_8); - assertThat(bodyString).contains("otlp-logs-test"); - assertThat(bodyString).contains("test"); - assertThat(bodyString).contains("INFO"); - - assertThat(bodyString).contains("Hello"); + assertLogMessage(body); } }); } @@ -100,18 +89,10 @@ public class OtlpLogsAutoConfigurationIntegrationTests { void httpLogRecordExporterCanBeConfiguredToUseGzipCompression() { this.mockWebServer.enqueue(new MockResponse()); this.contextRunner - .withPropertyValues( - "management.otlp.logs.endpoint=http://localhost:%d/v1/logs".formatted(this.mockWebServer.getPort()), - "management.otlp.logs.compression=gzip") + .withPropertyValues("management.otlp.logging.endpoint=http://localhost:%d/v1/logs" + .formatted(this.mockWebServer.getPort()), "management.otlp.logging.compression=gzip") .run((context) -> { - SdkLoggerProvider loggerProvider = context.getBean(SdkLoggerProvider.class); - loggerProvider.get("test") - .logRecordBuilder() - .setBody("Hello") - .setSeverity(Severity.INFO) - .setSeverityText("INFO") - .setTimestamp(Instant.now()) - .emit(); + logMessage(context); RecordedRequest request = this.mockWebServer.takeRequest(10, TimeUnit.SECONDS); assertThat(request).isNotNull(); assertThat(request.getRequestLine()).contains("/v1/logs"); @@ -120,13 +101,28 @@ public class OtlpLogsAutoConfigurationIntegrationTests { assertThat(request.getBodySize()).isPositive(); try (Buffer uncompressed = new Buffer(); Buffer body = request.getBody()) { uncompressed.writeAll(new GzipSource(body)); - String bodyString = uncompressed.readString(StandardCharsets.UTF_8); - assertThat(bodyString).contains("otlp-logs-test"); - assertThat(bodyString).contains("test"); - assertThat(bodyString).contains("INFO"); - assertThat(bodyString).contains("Hello"); + assertLogMessage(uncompressed); } }); } + private static void logMessage(ApplicationContext context) { + SdkLoggerProvider loggerProvider = context.getBean(SdkLoggerProvider.class); + loggerProvider.get("test") + .logRecordBuilder() + .setSeverity(Severity.INFO) + .setSeverityText("INFO") + .setBody("Hello") + .setTimestamp(Instant.now()) + .emit(); + } + + private static void assertLogMessage(Buffer body) { + String string = body.readString(StandardCharsets.UTF_8); + assertThat(string).contains("otlp-logs-test"); + assertThat(string).contains("test"); + assertThat(string).contains("INFO"); + assertThat(string).contains("Hello"); + } + } diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/logs/otlp/OtlpLogsAutoConfigurationTests.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/logging/opentelemetry/otlp/OtlpLoggingAutoConfigurationTests.java similarity index 76% rename from spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/logs/otlp/OtlpLogsAutoConfigurationTests.java rename to spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/logging/opentelemetry/otlp/OtlpLoggingAutoConfigurationTests.java index ac5d4bd62fa..afe42035c0c 100644 --- a/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/logs/otlp/OtlpLogsAutoConfigurationTests.java +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/logging/opentelemetry/otlp/OtlpLoggingAutoConfigurationTests.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package org.springframework.boot.actuate.autoconfigure.logs.otlp; +package org.springframework.boot.actuate.autoconfigure.logging.opentelemetry.otlp; import io.opentelemetry.exporter.otlp.http.logs.OtlpHttpLogRecordExporter; import io.opentelemetry.exporter.otlp.logs.OtlpGrpcLogRecordExporter; @@ -24,7 +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.logs.otlp.OtlpLogsConfigurations.ConnectionDetails.PropertiesOtlpLogsConnectionDetails; +import org.springframework.boot.actuate.autoconfigure.logging.opentelemetry.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; @@ -34,28 +34,30 @@ import org.springframework.context.annotation.Configuration; import static org.assertj.core.api.Assertions.assertThat; /** - * Tests for {@link OtlpLogsAutoConfiguration}. + * Tests for {@link OtlpLoggingAutoConfiguration}. * * @author Toshiaki Maki */ -class OtlpLogsAutoConfigurationTests { +class OtlpLoggingAutoConfigurationTests { private final ApplicationContextRunner contextRunner = new ApplicationContextRunner() - .withConfiguration(AutoConfigurations.of(OtlpLogsAutoConfiguration.class)); + .withConfiguration(AutoConfigurations.of(OtlpLoggingAutoConfiguration.class)); @Test void shouldNotSupplyBeansIfPropertyIsNotSet() { this.contextRunner.run((context) -> { - assertThat(context).doesNotHaveBean(OtlpLogsConnectionDetails.class); + assertThat(context).doesNotHaveBean(OtlpLoggingConnectionDetails.class); assertThat(context).doesNotHaveBean(OtlpHttpLogRecordExporter.class); }); } @Test void shouldSupplyBeans() { - this.contextRunner.withPropertyValues("management.otlp.logs.endpoint=http://localhost:4318/v1/logs") + this.contextRunner.withPropertyValues("management.otlp.logging.endpoint=http://localhost:4318/v1/logs") .run((context) -> { - assertThat(context).hasSingleBean(OtlpLogsConnectionDetails.class); + assertThat(context).hasSingleBean(OtlpLoggingConnectionDetails.class); + OtlpLoggingConnectionDetails connectionDetails = context.getBean(OtlpLoggingConnectionDetails.class); + assertThat(connectionDetails.getEndpoint()).isEqualTo("http://localhost:4318/v1/logs"); assertThat(context).hasSingleBean(OtlpHttpLogRecordExporter.class) .hasSingleBean(LogRecordExporter.class); }); @@ -66,7 +68,7 @@ class OtlpLogsAutoConfigurationTests { "io.opentelemetry.exporter.otlp.http.logs" }) void shouldNotSupplyBeansIfDependencyIsMissing(String packageName) { this.contextRunner.withClassLoader(new FilteredClassLoader(packageName)).run((context) -> { - assertThat(context).doesNotHaveBean(OtlpLogsConnectionDetails.class); + assertThat(context).doesNotHaveBean(OtlpLoggingConnectionDetails.class); assertThat(context).doesNotHaveBean(OtlpHttpLogRecordExporter.class); }); } @@ -88,8 +90,8 @@ class OtlpLogsAutoConfigurationTests { @Test void shouldBackOffWhenCustomOtlpLogsConnectionDetailsIsDefined() { this.contextRunner.withUserConfiguration(CustomOtlpLogsConnectionDetails.class).run((context) -> { - assertThat(context).hasSingleBean(OtlpLogsConnectionDetails.class) - .doesNotHaveBean(PropertiesOtlpLogsConnectionDetails.class); + assertThat(context).hasSingleBean(OtlpLoggingConnectionDetails.class) + .doesNotHaveBean(PropertiesOtlpLoggingConnectionDetails.class); OtlpHttpLogRecordExporter otlpHttpLogRecordExporter = context.getBean(OtlpHttpLogRecordExporter.class); assertThat(otlpHttpLogRecordExporter).extracting("delegate.httpSender.url") .isEqualTo(HttpUrl.get("https://otel.example.com/v1/logs")); @@ -121,7 +123,7 @@ class OtlpLogsAutoConfigurationTests { public static class CustomOtlpLogsConnectionDetails { @Bean - public OtlpLogsConnectionDetails customOtlpLogsConnectionDetails() { + public OtlpLoggingConnectionDetails customOtlpLogsConnectionDetails() { return () -> "https://otel.example.com/v1/logs"; }