Create spring-boot-opentelemetry module
Renames `management.otlp.logging` properties to `management.opentelemetry.logging`. Issue: 46149
This commit is contained in:
parent
3909b9d483
commit
ded9701db5
|
@ -119,6 +119,7 @@ include "spring-boot-project:spring-boot-metrics"
|
||||||
include "spring-boot-project:spring-boot-mongodb"
|
include "spring-boot-project:spring-boot-mongodb"
|
||||||
include "spring-boot-project:spring-boot-mustache"
|
include "spring-boot-project:spring-boot-mustache"
|
||||||
include "spring-boot-project:spring-boot-netty"
|
include "spring-boot-project:spring-boot-netty"
|
||||||
|
include "spring-boot-project:spring-boot-opentelemetry"
|
||||||
include "spring-boot-project:spring-boot-parent"
|
include "spring-boot-project:spring-boot-parent"
|
||||||
include "spring-boot-project:spring-boot-pulsar"
|
include "spring-boot-project:spring-boot-pulsar"
|
||||||
include "spring-boot-project:spring-boot-quartz"
|
include "spring-boot-project:spring-boot-quartz"
|
||||||
|
|
|
@ -56,6 +56,7 @@ dependencies {
|
||||||
optional(project(":spring-boot-project:spring-boot-jsonb"))
|
optional(project(":spring-boot-project:spring-boot-jsonb"))
|
||||||
optional(project(":spring-boot-project:spring-boot-kafka"))
|
optional(project(":spring-boot-project:spring-boot-kafka"))
|
||||||
optional(project(":spring-boot-project:spring-boot-metrics"))
|
optional(project(":spring-boot-project:spring-boot-metrics"))
|
||||||
|
optional(project(":spring-boot-project:spring-boot-opentelemetry"))
|
||||||
optional(project(":spring-boot-project:spring-boot-r2dbc"))
|
optional(project(":spring-boot-project:spring-boot-r2dbc"))
|
||||||
optional(project(":spring-boot-project:spring-boot-restclient"))
|
optional(project(":spring-boot-project:spring-boot-restclient"))
|
||||||
optional(project(":spring-boot-project:spring-boot-security-oauth2-client"))
|
optional(project(":spring-boot-project:spring-boot-security-oauth2-client"))
|
||||||
|
|
|
@ -1,61 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright 2012-present 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.logging;
|
|
||||||
|
|
||||||
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 logging.
|
|
||||||
*
|
|
||||||
* @author Toshiaki Maki
|
|
||||||
* @since 3.4.0
|
|
||||||
*/
|
|
||||||
@AutoConfiguration
|
|
||||||
@ConditionalOnClass({ SdkLoggerProvider.class, OpenTelemetry.class })
|
|
||||||
public class OpenTelemetryLoggingAutoConfiguration {
|
|
||||||
|
|
||||||
@Bean
|
|
||||||
@ConditionalOnMissingBean
|
|
||||||
BatchLogRecordProcessor batchLogRecordProcessor(ObjectProvider<LogRecordExporter> logRecordExporters) {
|
|
||||||
return BatchLogRecordProcessor.builder(LogRecordExporter.composite(logRecordExporters.orderedStream().toList()))
|
|
||||||
.build();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Bean
|
|
||||||
@ConditionalOnMissingBean
|
|
||||||
SdkLoggerProvider otelSdkLoggerProvider(Resource resource, ObjectProvider<LogRecordProcessor> logRecordProcessors,
|
|
||||||
ObjectProvider<SdkLoggerProviderBuilderCustomizer> customizers) {
|
|
||||||
SdkLoggerProviderBuilder builder = SdkLoggerProvider.builder().setResource(resource);
|
|
||||||
logRecordProcessors.orderedStream().forEach(builder::addLogRecordProcessor);
|
|
||||||
customizers.orderedStream().forEach((customizer) -> customizer.customize(builder));
|
|
||||||
return builder.build();
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,112 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright 2012-present 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.logging.otlp;
|
|
||||||
|
|
||||||
import java.util.Locale;
|
|
||||||
|
|
||||||
import io.opentelemetry.api.metrics.MeterProvider;
|
|
||||||
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.beans.factory.ObjectProvider;
|
|
||||||
import org.springframework.boot.actuate.autoconfigure.logging.ConditionalOnEnabledLoggingExport;
|
|
||||||
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}.
|
|
||||||
*
|
|
||||||
* @author Toshiaki Maki
|
|
||||||
*/
|
|
||||||
final class OtlpLoggingConfigurations {
|
|
||||||
|
|
||||||
@Configuration(proxyBeanMethods = false)
|
|
||||||
static class ConnectionDetails {
|
|
||||||
|
|
||||||
@Bean
|
|
||||||
@ConditionalOnMissingBean
|
|
||||||
@ConditionalOnProperty("management.otlp.logging.endpoint")
|
|
||||||
OtlpLoggingConnectionDetails otlpLoggingConnectionDetails(OtlpLoggingProperties properties) {
|
|
||||||
return new PropertiesOtlpLoggingConnectionDetails(properties);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Adapts {@link OtlpLoggingProperties} to {@link OtlpLoggingConnectionDetails}.
|
|
||||||
*/
|
|
||||||
static class PropertiesOtlpLoggingConnectionDetails implements OtlpLoggingConnectionDetails {
|
|
||||||
|
|
||||||
private final OtlpLoggingProperties properties;
|
|
||||||
|
|
||||||
PropertiesOtlpLoggingConnectionDetails(OtlpLoggingProperties properties) {
|
|
||||||
this.properties = properties;
|
|
||||||
}
|
|
||||||
|
|
||||||
@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();
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
@Configuration(proxyBeanMethods = false)
|
|
||||||
@ConditionalOnMissingBean({ OtlpGrpcLogRecordExporter.class, OtlpHttpLogRecordExporter.class })
|
|
||||||
@ConditionalOnBean(OtlpLoggingConnectionDetails.class)
|
|
||||||
@ConditionalOnEnabledLoggingExport("otlp")
|
|
||||||
static class Exporters {
|
|
||||||
|
|
||||||
@Bean
|
|
||||||
@ConditionalOnProperty(name = "management.otlp.logging.transport", havingValue = "http", matchIfMissing = true)
|
|
||||||
OtlpHttpLogRecordExporter otlpHttpLogRecordExporter(OtlpLoggingProperties properties,
|
|
||||||
OtlpLoggingConnectionDetails connectionDetails, ObjectProvider<MeterProvider> meterProvider) {
|
|
||||||
OtlpHttpLogRecordExporterBuilder builder = OtlpHttpLogRecordExporter.builder()
|
|
||||||
.setEndpoint(connectionDetails.getUrl(Transport.HTTP))
|
|
||||||
.setTimeout(properties.getTimeout())
|
|
||||||
.setConnectTimeout(properties.getConnectTimeout())
|
|
||||||
.setCompression(properties.getCompression().name().toLowerCase(Locale.US));
|
|
||||||
properties.getHeaders().forEach(builder::addHeader);
|
|
||||||
meterProvider.ifAvailable(builder::setMeterProvider);
|
|
||||||
return builder.build();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Bean
|
|
||||||
@ConditionalOnProperty(name = "management.otlp.logging.transport", havingValue = "grpc")
|
|
||||||
OtlpGrpcLogRecordExporter otlpGrpcLogRecordExporter(OtlpLoggingProperties properties,
|
|
||||||
OtlpLoggingConnectionDetails connectionDetails, ObjectProvider<MeterProvider> meterProvider) {
|
|
||||||
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);
|
|
||||||
meterProvider.ifAvailable(builder::setMeterProvider);
|
|
||||||
return builder.build();
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -24,7 +24,6 @@ import io.micrometer.registry.otlp.OtlpMetricsSender;
|
||||||
import org.springframework.beans.factory.ObjectProvider;
|
import org.springframework.beans.factory.ObjectProvider;
|
||||||
import org.springframework.boot.actuate.autoconfigure.metrics.export.ConditionalOnEnabledMetricsExport;
|
import org.springframework.boot.actuate.autoconfigure.metrics.export.ConditionalOnEnabledMetricsExport;
|
||||||
import org.springframework.boot.actuate.autoconfigure.metrics.export.simple.SimpleMetricsExportAutoConfiguration;
|
import org.springframework.boot.actuate.autoconfigure.metrics.export.simple.SimpleMetricsExportAutoConfiguration;
|
||||||
import org.springframework.boot.actuate.autoconfigure.opentelemetry.OpenTelemetryProperties;
|
|
||||||
import org.springframework.boot.autoconfigure.AutoConfiguration;
|
import org.springframework.boot.autoconfigure.AutoConfiguration;
|
||||||
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
|
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
|
||||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
|
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
|
||||||
|
@ -35,6 +34,7 @@ import org.springframework.boot.autoconfigure.thread.Threading;
|
||||||
import org.springframework.boot.context.properties.EnableConfigurationProperties;
|
import org.springframework.boot.context.properties.EnableConfigurationProperties;
|
||||||
import org.springframework.boot.metrics.autoconfigure.CompositeMeterRegistryAutoConfiguration;
|
import org.springframework.boot.metrics.autoconfigure.CompositeMeterRegistryAutoConfiguration;
|
||||||
import org.springframework.boot.metrics.autoconfigure.MetricsAutoConfiguration;
|
import org.springframework.boot.metrics.autoconfigure.MetricsAutoConfiguration;
|
||||||
|
import org.springframework.boot.opentelemetry.autoconfigure.OpenTelemetryProperties;
|
||||||
import org.springframework.context.annotation.Bean;
|
import org.springframework.context.annotation.Bean;
|
||||||
import org.springframework.core.env.Environment;
|
import org.springframework.core.env.Environment;
|
||||||
import org.springframework.core.task.VirtualThreadTaskExecutor;
|
import org.springframework.core.task.VirtualThreadTaskExecutor;
|
||||||
|
|
|
@ -28,8 +28,8 @@ import io.micrometer.registry.otlp.OtlpConfig;
|
||||||
|
|
||||||
import org.springframework.boot.actuate.autoconfigure.metrics.export.otlp.OtlpMetricsProperties.Meter;
|
import org.springframework.boot.actuate.autoconfigure.metrics.export.otlp.OtlpMetricsProperties.Meter;
|
||||||
import org.springframework.boot.actuate.autoconfigure.metrics.export.properties.StepRegistryPropertiesConfigAdapter;
|
import org.springframework.boot.actuate.autoconfigure.metrics.export.properties.StepRegistryPropertiesConfigAdapter;
|
||||||
import org.springframework.boot.actuate.autoconfigure.opentelemetry.OpenTelemetryProperties;
|
import org.springframework.boot.opentelemetry.autoconfigure.OpenTelemetryProperties;
|
||||||
import org.springframework.boot.actuate.autoconfigure.opentelemetry.OpenTelemetryResourceAttributes;
|
import org.springframework.boot.opentelemetry.autoconfigure.OpenTelemetryResourceAttributes;
|
||||||
import org.springframework.core.env.Environment;
|
import org.springframework.core.env.Environment;
|
||||||
import org.springframework.util.CollectionUtils;
|
import org.springframework.util.CollectionUtils;
|
||||||
|
|
||||||
|
|
|
@ -11,10 +11,6 @@ org.springframework.boot.actuate.autoconfigure.context.ShutdownEndpointAutoConfi
|
||||||
org.springframework.boot.actuate.autoconfigure.endpoint.jackson.JacksonEndpointAutoConfiguration
|
org.springframework.boot.actuate.autoconfigure.endpoint.jackson.JacksonEndpointAutoConfiguration
|
||||||
org.springframework.boot.actuate.autoconfigure.endpoint.jmx.JmxEndpointAutoConfiguration
|
org.springframework.boot.actuate.autoconfigure.endpoint.jmx.JmxEndpointAutoConfiguration
|
||||||
org.springframework.boot.actuate.autoconfigure.env.EnvironmentEndpointAutoConfiguration
|
org.springframework.boot.actuate.autoconfigure.env.EnvironmentEndpointAutoConfiguration
|
||||||
org.springframework.boot.actuate.autoconfigure.logging.LogFileWebEndpointAutoConfiguration
|
|
||||||
org.springframework.boot.actuate.autoconfigure.logging.LoggersEndpointAutoConfiguration
|
|
||||||
org.springframework.boot.actuate.autoconfigure.logging.OpenTelemetryLoggingAutoConfiguration
|
|
||||||
org.springframework.boot.actuate.autoconfigure.logging.otlp.OtlpLoggingAutoConfiguration
|
|
||||||
org.springframework.boot.actuate.autoconfigure.management.HeapDumpWebEndpointAutoConfiguration
|
org.springframework.boot.actuate.autoconfigure.management.HeapDumpWebEndpointAutoConfiguration
|
||||||
org.springframework.boot.actuate.autoconfigure.management.ThreadDumpEndpointAutoConfiguration
|
org.springframework.boot.actuate.autoconfigure.management.ThreadDumpEndpointAutoConfiguration
|
||||||
org.springframework.boot.actuate.autoconfigure.metrics.data.RepositoryMetricsAutoConfiguration
|
org.springframework.boot.actuate.autoconfigure.metrics.data.RepositoryMetricsAutoConfiguration
|
||||||
|
@ -44,7 +40,6 @@ org.springframework.boot.actuate.autoconfigure.observation.ObservationAutoConfig
|
||||||
org.springframework.boot.actuate.autoconfigure.observation.web.client.HttpClientObservationsAutoConfiguration
|
org.springframework.boot.actuate.autoconfigure.observation.web.client.HttpClientObservationsAutoConfiguration
|
||||||
org.springframework.boot.actuate.autoconfigure.observation.web.reactive.WebFluxObservationAutoConfiguration
|
org.springframework.boot.actuate.autoconfigure.observation.web.reactive.WebFluxObservationAutoConfiguration
|
||||||
org.springframework.boot.actuate.autoconfigure.observation.web.servlet.WebMvcObservationAutoConfiguration
|
org.springframework.boot.actuate.autoconfigure.observation.web.servlet.WebMvcObservationAutoConfiguration
|
||||||
org.springframework.boot.actuate.autoconfigure.opentelemetry.OpenTelemetryAutoConfiguration
|
|
||||||
org.springframework.boot.actuate.autoconfigure.r2dbc.ConnectionFactoryHealthContributorAutoConfiguration
|
org.springframework.boot.actuate.autoconfigure.r2dbc.ConnectionFactoryHealthContributorAutoConfiguration
|
||||||
org.springframework.boot.actuate.autoconfigure.r2dbc.R2dbcObservationAutoConfiguration
|
org.springframework.boot.actuate.autoconfigure.r2dbc.R2dbcObservationAutoConfiguration
|
||||||
org.springframework.boot.actuate.autoconfigure.sbom.SbomEndpointAutoConfiguration
|
org.springframework.boot.actuate.autoconfigure.sbom.SbomEndpointAutoConfiguration
|
||||||
|
|
|
@ -1,226 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright 2012-present 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.logging;
|
|
||||||
|
|
||||||
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.actuate.autoconfigure.opentelemetry.OpenTelemetryAutoConfiguration;
|
|
||||||
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 OpenTelemetryLoggingAutoConfiguration}.
|
|
||||||
*
|
|
||||||
* @author Toshiaki Maki
|
|
||||||
*/
|
|
||||||
class OpenTelemetryLoggingAutoConfigurationTests {
|
|
||||||
|
|
||||||
private final ApplicationContextRunner contextRunner;
|
|
||||||
|
|
||||||
OpenTelemetryLoggingAutoConfigurationTests() {
|
|
||||||
this.contextRunner = new ApplicationContextRunner().withConfiguration(AutoConfigurations
|
|
||||||
.of(OpenTelemetryAutoConfiguration.class, OpenTelemetryLoggingAutoConfiguration.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 shouldAllowMultipleLogRecordExporters() {
|
|
||||||
this.contextRunner.withUserConfiguration(MultipleLogRecordExportersConfig.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 shouldAllowMultipleLogRecordProcessorsInAdditionToBatchLogRecordProcessor() {
|
|
||||||
this.contextRunner.withUserConfiguration(MultipleLogRecordProcessorsConfig.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 shouldAllowMultipleSdkLoggerProviderBuilderCustomizers() {
|
|
||||||
this.contextRunner.withUserConfiguration(MultipleSdkLoggerProviderBuilderCustomizersConfig.class)
|
|
||||||
.run((context) -> {
|
|
||||||
assertThat(context).hasSingleBean(SdkLoggerProvider.class);
|
|
||||||
assertThat(context.getBeansOfType(SdkLoggerProviderBuilderCustomizer.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 MultipleLogRecordExportersConfig {
|
|
||||||
|
|
||||||
@Bean
|
|
||||||
public LogRecordExporter customLogRecordExporter1() {
|
|
||||||
return new NoopLogRecordExporter();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Bean
|
|
||||||
public LogRecordExporter customLogRecordExporter2() {
|
|
||||||
return new NoopLogRecordExporter();
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
@Configuration(proxyBeanMethods = false)
|
|
||||||
public static class MultipleLogRecordProcessorsConfig {
|
|
||||||
|
|
||||||
@Bean
|
|
||||||
public LogRecordProcessor customLogRecordProcessor1() {
|
|
||||||
return new NoopLogRecordProcessor();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Bean
|
|
||||||
public LogRecordProcessor customLogRecordProcessor2() {
|
|
||||||
return new NoopLogRecordProcessor();
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
@Configuration(proxyBeanMethods = false)
|
|
||||||
public static class MultipleSdkLoggerProviderBuilderCustomizersConfig {
|
|
||||||
|
|
||||||
@Bean
|
|
||||||
public SdkLoggerProviderBuilderCustomizer customSdkLoggerProviderBuilderCustomizer1() {
|
|
||||||
return new NoopSdkLoggerProviderBuilderCustomizer();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Bean
|
|
||||||
public SdkLoggerProviderBuilderCustomizer customSdkLoggerProviderBuilderCustomizer2() {
|
|
||||||
return new NoopSdkLoggerProviderBuilderCustomizer();
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
static class NoopLogRecordExporter implements LogRecordExporter {
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public CompletableResultCode export(Collection<LogRecordData> 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();
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -26,7 +26,7 @@ import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
import org.springframework.boot.actuate.autoconfigure.metrics.export.otlp.OtlpMetricsExportAutoConfiguration.PropertiesOtlpMetricsConnectionDetails;
|
import org.springframework.boot.actuate.autoconfigure.metrics.export.otlp.OtlpMetricsExportAutoConfiguration.PropertiesOtlpMetricsConnectionDetails;
|
||||||
import org.springframework.boot.actuate.autoconfigure.metrics.export.otlp.OtlpMetricsProperties.Meter;
|
import org.springframework.boot.actuate.autoconfigure.metrics.export.otlp.OtlpMetricsProperties.Meter;
|
||||||
import org.springframework.boot.actuate.autoconfigure.opentelemetry.OpenTelemetryProperties;
|
import org.springframework.boot.opentelemetry.autoconfigure.OpenTelemetryProperties;
|
||||||
import org.springframework.mock.env.MockEnvironment;
|
import org.springframework.mock.env.MockEnvironment;
|
||||||
|
|
||||||
import static org.assertj.core.api.Assertions.assertThat;
|
import static org.assertj.core.api.Assertions.assertThat;
|
||||||
|
|
|
@ -1,190 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright 2012-present 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.opentelemetry;
|
|
||||||
|
|
||||||
import io.opentelemetry.api.OpenTelemetry;
|
|
||||||
import io.opentelemetry.api.common.AttributeKey;
|
|
||||||
import io.opentelemetry.context.propagation.ContextPropagators;
|
|
||||||
import io.opentelemetry.sdk.OpenTelemetrySdk;
|
|
||||||
import io.opentelemetry.sdk.logs.SdkLoggerProvider;
|
|
||||||
import io.opentelemetry.sdk.metrics.SdkMeterProvider;
|
|
||||||
import io.opentelemetry.sdk.resources.Resource;
|
|
||||||
import io.opentelemetry.sdk.trace.SdkTracerProvider;
|
|
||||||
import org.junit.jupiter.api.Test;
|
|
||||||
|
|
||||||
import org.springframework.boot.autoconfigure.AutoConfiguration;
|
|
||||||
import org.springframework.boot.autoconfigure.AutoConfigurations;
|
|
||||||
import org.springframework.boot.context.annotation.ImportCandidates;
|
|
||||||
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;
|
|
||||||
import static org.assertj.core.api.Assertions.entry;
|
|
||||||
import static org.mockito.Mockito.mock;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Tests for {@link OpenTelemetryAutoConfiguration}.
|
|
||||||
*
|
|
||||||
* @author Moritz Halbritter
|
|
||||||
*/
|
|
||||||
class OpenTelemetryAutoConfigurationTests {
|
|
||||||
|
|
||||||
private final ApplicationContextRunner runner = new ApplicationContextRunner()
|
|
||||||
.withConfiguration(AutoConfigurations.of(OpenTelemetryAutoConfiguration.class));
|
|
||||||
|
|
||||||
@Test
|
|
||||||
void isRegisteredInAutoConfigurationImports() {
|
|
||||||
assertThat(ImportCandidates.load(AutoConfiguration.class, null).getCandidates())
|
|
||||||
.contains(OpenTelemetryAutoConfiguration.class.getName());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
void shouldProvideBeans() {
|
|
||||||
this.runner.run((context) -> {
|
|
||||||
assertThat(context).hasSingleBean(OpenTelemetrySdk.class);
|
|
||||||
assertThat(context).hasSingleBean(Resource.class);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
void shouldBackOffIfOpenTelemetryIsNotOnClasspath() {
|
|
||||||
this.runner.withClassLoader(new FilteredClassLoader("io.opentelemetry")).run((context) -> {
|
|
||||||
assertThat(context).doesNotHaveBean(OpenTelemetrySdk.class);
|
|
||||||
assertThat(context).doesNotHaveBean(Resource.class);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
void backsOffOnUserSuppliedBeans() {
|
|
||||||
this.runner.withUserConfiguration(UserConfiguration.class).run((context) -> {
|
|
||||||
assertThat(context).hasSingleBean(OpenTelemetry.class);
|
|
||||||
assertThat(context).hasBean("customOpenTelemetry");
|
|
||||||
assertThat(context).hasSingleBean(Resource.class);
|
|
||||||
assertThat(context).hasBean("customResource");
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
void shouldApplySpringApplicationNameToResource() {
|
|
||||||
this.runner.withPropertyValues("spring.application.name=my-application").run((context) -> {
|
|
||||||
Resource resource = context.getBean(Resource.class);
|
|
||||||
assertThat(resource.getAttributes().asMap())
|
|
||||||
.contains(entry(AttributeKey.stringKey("service.name"), "my-application"));
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
void shouldApplySpringApplicationGroupToResource() {
|
|
||||||
this.runner.withPropertyValues("spring.application.group=my-group").run((context) -> {
|
|
||||||
Resource resource = context.getBean(Resource.class);
|
|
||||||
assertThat(resource.getAttributes().asMap())
|
|
||||||
.contains(entry(AttributeKey.stringKey("service.group"), "my-group"));
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
void shouldNotApplySpringApplicationGroupIfNotSet() {
|
|
||||||
this.runner.run((context) -> {
|
|
||||||
Resource resource = context.getBean(Resource.class);
|
|
||||||
assertThat(resource.getAttributes().asMap()).doesNotContainKey(AttributeKey.stringKey("service.group"));
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
void shouldApplyServiceNamespaceIfApplicationGroupIsSet() {
|
|
||||||
this.runner.withPropertyValues("spring.application.group=my-group").run((context) -> {
|
|
||||||
Resource resource = context.getBean(Resource.class);
|
|
||||||
assertThat(resource.getAttributes().asMap()).containsEntry(AttributeKey.stringKey("service.namespace"),
|
|
||||||
"my-group");
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
void shouldNotApplyServiceNamespaceIfApplicationGroupIsNotSet() {
|
|
||||||
this.runner.run(((context) -> {
|
|
||||||
Resource resource = context.getBean(Resource.class);
|
|
||||||
assertThat(resource.getAttributes().asMap()).doesNotContainKey(AttributeKey.stringKey("service.namespace"));
|
|
||||||
}));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
void shouldFallbackToDefaultApplicationNameIfSpringApplicationNameIsNotSet() {
|
|
||||||
this.runner.run((context) -> {
|
|
||||||
Resource resource = context.getBean(Resource.class);
|
|
||||||
assertThat(resource.getAttributes().asMap())
|
|
||||||
.contains(entry(AttributeKey.stringKey("service.name"), "unknown_service"));
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
void shouldApplyResourceAttributesFromProperties() {
|
|
||||||
this.runner.withPropertyValues("management.opentelemetry.resource-attributes.region=us-west").run((context) -> {
|
|
||||||
Resource resource = context.getBean(Resource.class);
|
|
||||||
assertThat(resource.getAttributes().asMap()).contains(entry(AttributeKey.stringKey("region"), "us-west"));
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
void shouldRegisterSdkTracerProviderIfAvailable() {
|
|
||||||
this.runner.withBean(SdkTracerProvider.class, () -> SdkTracerProvider.builder().build()).run((context) -> {
|
|
||||||
OpenTelemetry openTelemetry = context.getBean(OpenTelemetry.class);
|
|
||||||
assertThat(openTelemetry.getTracerProvider()).isNotNull();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
void shouldRegisterContextPropagatorsIfAvailable() {
|
|
||||||
this.runner.withBean(ContextPropagators.class, ContextPropagators::noop).run((context) -> {
|
|
||||||
OpenTelemetry openTelemetry = context.getBean(OpenTelemetry.class);
|
|
||||||
assertThat(openTelemetry.getPropagators()).isNotNull();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
void shouldRegisterSdkLoggerProviderIfAvailable() {
|
|
||||||
this.runner.withBean(SdkLoggerProvider.class, () -> SdkLoggerProvider.builder().build()).run((context) -> {
|
|
||||||
OpenTelemetry openTelemetry = context.getBean(OpenTelemetry.class);
|
|
||||||
assertThat(openTelemetry.getLogsBridge()).isNotNull();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
void shouldRegisterSdkMeterProviderIfAvailable() {
|
|
||||||
this.runner.withBean(SdkMeterProvider.class, () -> SdkMeterProvider.builder().build()).run((context) -> {
|
|
||||||
OpenTelemetry openTelemetry = context.getBean(OpenTelemetry.class);
|
|
||||||
assertThat(openTelemetry.getMeterProvider()).isNotNull();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
@Configuration(proxyBeanMethods = false)
|
|
||||||
static class UserConfiguration {
|
|
||||||
|
|
||||||
@Bean
|
|
||||||
OpenTelemetry customOpenTelemetry() {
|
|
||||||
return mock(OpenTelemetry.class);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Bean
|
|
||||||
Resource customResource() {
|
|
||||||
return Resource.getDefault();
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -30,8 +30,8 @@ import org.junit.jupiter.params.ParameterizedTest;
|
||||||
import org.junit.jupiter.params.provider.EnumSource;
|
import org.junit.jupiter.params.provider.EnumSource;
|
||||||
import org.slf4j.MDC;
|
import org.slf4j.MDC;
|
||||||
|
|
||||||
import org.springframework.boot.actuate.autoconfigure.opentelemetry.OpenTelemetryAutoConfiguration;
|
|
||||||
import org.springframework.boot.autoconfigure.AutoConfigurations;
|
import org.springframework.boot.autoconfigure.AutoConfigurations;
|
||||||
|
import org.springframework.boot.opentelemetry.autoconfigure.OpenTelemetrySdkAutoConfiguration;
|
||||||
import org.springframework.boot.test.context.runner.ApplicationContextRunner;
|
import org.springframework.boot.test.context.runner.ApplicationContextRunner;
|
||||||
import org.springframework.boot.testsupport.classpath.ForkedClassPath;
|
import org.springframework.boot.testsupport.classpath.ForkedClassPath;
|
||||||
import org.springframework.context.ApplicationContext;
|
import org.springframework.context.ApplicationContext;
|
||||||
|
@ -173,7 +173,7 @@ class BaggagePropagationIntegrationTests {
|
||||||
@Override
|
@Override
|
||||||
public ApplicationContextRunner get() {
|
public ApplicationContextRunner get() {
|
||||||
return new ApplicationContextRunner().withInitializer(new OtelApplicationContextInitializer())
|
return new ApplicationContextRunner().withInitializer(new OtelApplicationContextInitializer())
|
||||||
.withConfiguration(AutoConfigurations.of(OpenTelemetryAutoConfiguration.class,
|
.withConfiguration(AutoConfigurations.of(OpenTelemetrySdkAutoConfiguration.class,
|
||||||
org.springframework.boot.actuate.autoconfigure.tracing.OpenTelemetryTracingAutoConfiguration.class))
|
org.springframework.boot.actuate.autoconfigure.tracing.OpenTelemetryTracingAutoConfiguration.class))
|
||||||
.withPropertyValues("management.tracing.baggage.remote-fields=x-vcap-request-id,country-code,bp",
|
.withPropertyValues("management.tracing.baggage.remote-fields=x-vcap-request-id,country-code,bp",
|
||||||
"management.tracing.baggage.correlation.fields=country-code,bp");
|
"management.tracing.baggage.correlation.fields=country-code,bp");
|
||||||
|
@ -199,7 +199,7 @@ class BaggagePropagationIntegrationTests {
|
||||||
@Override
|
@Override
|
||||||
public ApplicationContextRunner get() {
|
public ApplicationContextRunner get() {
|
||||||
return new ApplicationContextRunner().withInitializer(new OtelApplicationContextInitializer())
|
return new ApplicationContextRunner().withInitializer(new OtelApplicationContextInitializer())
|
||||||
.withConfiguration(AutoConfigurations.of(OpenTelemetryAutoConfiguration.class,
|
.withConfiguration(AutoConfigurations.of(OpenTelemetrySdkAutoConfiguration.class,
|
||||||
org.springframework.boot.actuate.autoconfigure.tracing.OpenTelemetryTracingAutoConfiguration.class))
|
org.springframework.boot.actuate.autoconfigure.tracing.OpenTelemetryTracingAutoConfiguration.class))
|
||||||
.withPropertyValues("management.tracing.propagation.type=W3C",
|
.withPropertyValues("management.tracing.propagation.type=W3C",
|
||||||
"management.tracing.baggage.remote-fields=x-vcap-request-id,country-code,bp",
|
"management.tracing.baggage.remote-fields=x-vcap-request-id,country-code,bp",
|
||||||
|
@ -239,7 +239,7 @@ class BaggagePropagationIntegrationTests {
|
||||||
@Override
|
@Override
|
||||||
public ApplicationContextRunner get() {
|
public ApplicationContextRunner get() {
|
||||||
return new ApplicationContextRunner().withInitializer(new OtelApplicationContextInitializer())
|
return new ApplicationContextRunner().withInitializer(new OtelApplicationContextInitializer())
|
||||||
.withConfiguration(AutoConfigurations.of(OpenTelemetryAutoConfiguration.class,
|
.withConfiguration(AutoConfigurations.of(OpenTelemetrySdkAutoConfiguration.class,
|
||||||
org.springframework.boot.actuate.autoconfigure.tracing.OpenTelemetryTracingAutoConfiguration.class))
|
org.springframework.boot.actuate.autoconfigure.tracing.OpenTelemetryTracingAutoConfiguration.class))
|
||||||
.withPropertyValues("management.tracing.propagation.type=B3",
|
.withPropertyValues("management.tracing.propagation.type=B3",
|
||||||
"management.tracing.baggage.remote-fields=x-vcap-request-id,country-code,bp",
|
"management.tracing.baggage.remote-fields=x-vcap-request-id,country-code,bp",
|
||||||
|
@ -253,7 +253,7 @@ class BaggagePropagationIntegrationTests {
|
||||||
@Override
|
@Override
|
||||||
public ApplicationContextRunner get() {
|
public ApplicationContextRunner get() {
|
||||||
return new ApplicationContextRunner().withInitializer(new OtelApplicationContextInitializer())
|
return new ApplicationContextRunner().withInitializer(new OtelApplicationContextInitializer())
|
||||||
.withConfiguration(AutoConfigurations.of(OpenTelemetryAutoConfiguration.class,
|
.withConfiguration(AutoConfigurations.of(OpenTelemetrySdkAutoConfiguration.class,
|
||||||
org.springframework.boot.actuate.autoconfigure.tracing.OpenTelemetryTracingAutoConfiguration.class))
|
org.springframework.boot.actuate.autoconfigure.tracing.OpenTelemetryTracingAutoConfiguration.class))
|
||||||
.withPropertyValues("management.tracing.propagation.type=B3_MULTI",
|
.withPropertyValues("management.tracing.propagation.type=B3_MULTI",
|
||||||
"management.tracing.baggage.remote-fields=x-vcap-request-id,country-code,bp",
|
"management.tracing.baggage.remote-fields=x-vcap-request-id,country-code,bp",
|
||||||
|
|
|
@ -90,7 +90,7 @@ class OpenTelemetryTracingAutoConfigurationTests {
|
||||||
|
|
||||||
private final ApplicationContextRunner contextRunner = new ApplicationContextRunner()
|
private final ApplicationContextRunner contextRunner = new ApplicationContextRunner()
|
||||||
.withConfiguration(AutoConfigurations.of(
|
.withConfiguration(AutoConfigurations.of(
|
||||||
org.springframework.boot.actuate.autoconfigure.opentelemetry.OpenTelemetryAutoConfiguration.class,
|
org.springframework.boot.opentelemetry.autoconfigure.OpenTelemetrySdkAutoConfiguration.class,
|
||||||
OpenTelemetryTracingAutoConfiguration.class));
|
OpenTelemetryTracingAutoConfiguration.class));
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
|
|
@ -47,10 +47,10 @@ import org.junit.jupiter.api.BeforeEach;
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
import org.springframework.boot.actuate.autoconfigure.observation.ObservationAutoConfiguration;
|
import org.springframework.boot.actuate.autoconfigure.observation.ObservationAutoConfiguration;
|
||||||
import org.springframework.boot.actuate.autoconfigure.opentelemetry.OpenTelemetryAutoConfiguration;
|
|
||||||
import org.springframework.boot.actuate.autoconfigure.tracing.MicrometerTracingAutoConfiguration;
|
import org.springframework.boot.actuate.autoconfigure.tracing.MicrometerTracingAutoConfiguration;
|
||||||
import org.springframework.boot.actuate.autoconfigure.tracing.otlp.OtlpTracingAutoConfigurationIntegrationTests.MockGrpcServer.RecordedGrpcRequest;
|
import org.springframework.boot.actuate.autoconfigure.tracing.otlp.OtlpTracingAutoConfigurationIntegrationTests.MockGrpcServer.RecordedGrpcRequest;
|
||||||
import org.springframework.boot.autoconfigure.AutoConfigurations;
|
import org.springframework.boot.autoconfigure.AutoConfigurations;
|
||||||
|
import org.springframework.boot.opentelemetry.autoconfigure.OpenTelemetrySdkAutoConfiguration;
|
||||||
import org.springframework.boot.test.context.runner.ApplicationContextRunner;
|
import org.springframework.boot.test.context.runner.ApplicationContextRunner;
|
||||||
|
|
||||||
import static org.assertj.core.api.Assertions.assertThat;
|
import static org.assertj.core.api.Assertions.assertThat;
|
||||||
|
@ -65,7 +65,7 @@ class OtlpTracingAutoConfigurationIntegrationTests {
|
||||||
private final ApplicationContextRunner contextRunner = new ApplicationContextRunner()
|
private final ApplicationContextRunner contextRunner = new ApplicationContextRunner()
|
||||||
.withPropertyValues("management.tracing.sampling.probability=1.0")
|
.withPropertyValues("management.tracing.sampling.probability=1.0")
|
||||||
.withConfiguration(AutoConfigurations.of(ObservationAutoConfiguration.class,
|
.withConfiguration(AutoConfigurations.of(ObservationAutoConfiguration.class,
|
||||||
MicrometerTracingAutoConfiguration.class, OpenTelemetryAutoConfiguration.class,
|
MicrometerTracingAutoConfiguration.class, OpenTelemetrySdkAutoConfiguration.class,
|
||||||
org.springframework.boot.actuate.autoconfigure.tracing.OpenTelemetryTracingAutoConfiguration.class,
|
org.springframework.boot.actuate.autoconfigure.tracing.OpenTelemetryTracingAutoConfiguration.class,
|
||||||
OtlpTracingAutoConfiguration.class));
|
OtlpTracingAutoConfiguration.class));
|
||||||
|
|
||||||
|
|
|
@ -4,4 +4,6 @@ org.springframework.boot.actuate.autoconfigure.health.HealthContributorAutoConfi
|
||||||
org.springframework.boot.actuate.autoconfigure.health.HealthEndpointAutoConfiguration
|
org.springframework.boot.actuate.autoconfigure.health.HealthEndpointAutoConfiguration
|
||||||
org.springframework.boot.actuate.autoconfigure.info.InfoContributorAutoConfiguration
|
org.springframework.boot.actuate.autoconfigure.info.InfoContributorAutoConfiguration
|
||||||
org.springframework.boot.actuate.autoconfigure.info.InfoEndpointAutoConfiguration
|
org.springframework.boot.actuate.autoconfigure.info.InfoEndpointAutoConfiguration
|
||||||
|
org.springframework.boot.actuate.autoconfigure.logging.LogFileWebEndpointAutoConfiguration
|
||||||
|
org.springframework.boot.actuate.autoconfigure.logging.LoggersEndpointAutoConfiguration
|
||||||
org.springframework.boot.actuate.autoconfigure.web.server.ManagementContextAutoConfiguration
|
org.springframework.boot.actuate.autoconfigure.web.server.ManagementContextAutoConfiguration
|
||||||
|
|
|
@ -2048,6 +2048,7 @@ bom {
|
||||||
"spring-boot-mustache",
|
"spring-boot-mustache",
|
||||||
"spring-boot-neo4j",
|
"spring-boot-neo4j",
|
||||||
"spring-boot-netty",
|
"spring-boot-netty",
|
||||||
|
"spring-boot-opentelemetry",
|
||||||
"spring-boot-properties-migrator",
|
"spring-boot-properties-migrator",
|
||||||
"spring-boot-pulsar",
|
"spring-boot-pulsar",
|
||||||
"spring-boot-quartz",
|
"spring-boot-quartz",
|
||||||
|
|
|
@ -32,6 +32,7 @@ dependencies {
|
||||||
dockerTestImplementation(project(":spring-boot-project:spring-boot-jdbc"))
|
dockerTestImplementation(project(":spring-boot-project:spring-boot-jdbc"))
|
||||||
dockerTestImplementation(project(":spring-boot-project:spring-boot-flyway"))
|
dockerTestImplementation(project(":spring-boot-project:spring-boot-flyway"))
|
||||||
dockerTestImplementation(project(":spring-boot-project:spring-boot-liquibase"))
|
dockerTestImplementation(project(":spring-boot-project:spring-boot-liquibase"))
|
||||||
|
dockerTestImplementation(project(":spring-boot-project:spring-boot-opentelemetry"))
|
||||||
dockerTestImplementation(project(":spring-boot-project:spring-boot-pulsar"))
|
dockerTestImplementation(project(":spring-boot-project:spring-boot-pulsar"))
|
||||||
dockerTestImplementation(project(":spring-boot-project:spring-boot-r2dbc"))
|
dockerTestImplementation(project(":spring-boot-project:spring-boot-r2dbc"))
|
||||||
dockerTestImplementation(project(":spring-boot-project:spring-boot-tools:spring-boot-test-support-docker"))
|
dockerTestImplementation(project(":spring-boot-project:spring-boot-tools:spring-boot-test-support-docker"))
|
||||||
|
@ -45,6 +46,7 @@ dependencies {
|
||||||
dockerTestRuntimeOnly("com.clickhouse:clickhouse-r2dbc")
|
dockerTestRuntimeOnly("com.clickhouse:clickhouse-r2dbc")
|
||||||
dockerTestRuntimeOnly("com.microsoft.sqlserver:mssql-jdbc")
|
dockerTestRuntimeOnly("com.microsoft.sqlserver:mssql-jdbc")
|
||||||
dockerTestRuntimeOnly("com.oracle.database.r2dbc:oracle-r2dbc")
|
dockerTestRuntimeOnly("com.oracle.database.r2dbc:oracle-r2dbc")
|
||||||
|
dockerTestRuntimeOnly("io.opentelemetry:opentelemetry-exporter-otlp")
|
||||||
dockerTestRuntimeOnly("io.r2dbc:r2dbc-mssql")
|
dockerTestRuntimeOnly("io.r2dbc:r2dbc-mssql")
|
||||||
dockerTestRuntimeOnly("org.postgresql:postgresql")
|
dockerTestRuntimeOnly("org.postgresql:postgresql")
|
||||||
dockerTestRuntimeOnly("org.postgresql:r2dbc-postgresql")
|
dockerTestRuntimeOnly("org.postgresql:r2dbc-postgresql")
|
||||||
|
@ -67,6 +69,7 @@ dependencies {
|
||||||
optional(project(":spring-boot-project:spring-boot-liquibase"))
|
optional(project(":spring-boot-project:spring-boot-liquibase"))
|
||||||
optional(project(":spring-boot-project:spring-boot-mongodb"))
|
optional(project(":spring-boot-project:spring-boot-mongodb"))
|
||||||
optional(project(":spring-boot-project:spring-boot-neo4j"))
|
optional(project(":spring-boot-project:spring-boot-neo4j"))
|
||||||
|
optional(project(":spring-boot-project:spring-boot-opentelemetry"))
|
||||||
optional(project(":spring-boot-project:spring-boot-pulsar"))
|
optional(project(":spring-boot-project:spring-boot-pulsar"))
|
||||||
optional(project(":spring-boot-project:spring-boot-r2dbc"))
|
optional(project(":spring-boot-project:spring-boot-r2dbc"))
|
||||||
optional(project(":spring-boot-project:spring-boot-zipkin"))
|
optional(project(":spring-boot-project:spring-boot-zipkin"))
|
||||||
|
|
|
@ -16,9 +16,9 @@
|
||||||
|
|
||||||
package org.springframework.boot.docker.compose.service.connection.otlp;
|
package org.springframework.boot.docker.compose.service.connection.otlp;
|
||||||
|
|
||||||
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.docker.compose.service.connection.test.DockerComposeTest;
|
||||||
|
import org.springframework.boot.opentelemetry.actuate.autoconfigure.logging.OpenTelemetryLoggingConnectionDetails;
|
||||||
|
import org.springframework.boot.opentelemetry.actuate.autoconfigure.logging.Transport;
|
||||||
import org.springframework.boot.testsupport.container.TestImage;
|
import org.springframework.boot.testsupport.container.TestImage;
|
||||||
|
|
||||||
import static org.assertj.core.api.Assertions.assertThat;
|
import static org.assertj.core.api.Assertions.assertThat;
|
||||||
|
@ -32,7 +32,7 @@ import static org.assertj.core.api.Assertions.assertThat;
|
||||||
class GrafanaOpenTelemetryLoggingDockerComposeConnectionDetailsFactoryIntegrationTests {
|
class GrafanaOpenTelemetryLoggingDockerComposeConnectionDetailsFactoryIntegrationTests {
|
||||||
|
|
||||||
@DockerComposeTest(composeFile = "otlp-compose.yaml", image = TestImage.GRAFANA_OTEL_LGTM)
|
@DockerComposeTest(composeFile = "otlp-compose.yaml", image = TestImage.GRAFANA_OTEL_LGTM)
|
||||||
void runCreatesConnectionDetails(OtlpLoggingConnectionDetails connectionDetails) {
|
void runCreatesConnectionDetails(OpenTelemetryLoggingConnectionDetails connectionDetails) {
|
||||||
assertThat(connectionDetails.getUrl(Transport.HTTP)).startsWith("http://").endsWith("/v1/logs");
|
assertThat(connectionDetails.getUrl(Transport.HTTP)).startsWith("http://").endsWith("/v1/logs");
|
||||||
assertThat(connectionDetails.getUrl(Transport.GRPC)).startsWith("http://").endsWith("/v1/logs");
|
assertThat(connectionDetails.getUrl(Transport.GRPC)).startsWith("http://").endsWith("/v1/logs");
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,9 +16,9 @@
|
||||||
|
|
||||||
package org.springframework.boot.docker.compose.service.connection.otlp;
|
package org.springframework.boot.docker.compose.service.connection.otlp;
|
||||||
|
|
||||||
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.docker.compose.service.connection.test.DockerComposeTest;
|
||||||
|
import org.springframework.boot.opentelemetry.actuate.autoconfigure.logging.OpenTelemetryLoggingConnectionDetails;
|
||||||
|
import org.springframework.boot.opentelemetry.actuate.autoconfigure.logging.Transport;
|
||||||
import org.springframework.boot.testsupport.container.TestImage;
|
import org.springframework.boot.testsupport.container.TestImage;
|
||||||
|
|
||||||
import static org.assertj.core.api.Assertions.assertThat;
|
import static org.assertj.core.api.Assertions.assertThat;
|
||||||
|
@ -32,7 +32,7 @@ import static org.assertj.core.api.Assertions.assertThat;
|
||||||
class OpenTelemetryLoggingDockerComposeConnectionDetailsFactoryIntegrationTests {
|
class OpenTelemetryLoggingDockerComposeConnectionDetailsFactoryIntegrationTests {
|
||||||
|
|
||||||
@DockerComposeTest(composeFile = "otlp-compose.yaml", image = TestImage.OPENTELEMETRY)
|
@DockerComposeTest(composeFile = "otlp-compose.yaml", image = TestImage.OPENTELEMETRY)
|
||||||
void runCreatesConnectionDetails(OtlpLoggingConnectionDetails connectionDetails) {
|
void runCreatesConnectionDetails(OpenTelemetryLoggingConnectionDetails connectionDetails) {
|
||||||
assertThat(connectionDetails.getUrl(Transport.HTTP)).startsWith("http://").endsWith("/v1/logs");
|
assertThat(connectionDetails.getUrl(Transport.HTTP)).startsWith("http://").endsWith("/v1/logs");
|
||||||
assertThat(connectionDetails.getUrl(Transport.GRPC)).startsWith("http://").endsWith("/v1/logs");
|
assertThat(connectionDetails.getUrl(Transport.GRPC)).startsWith("http://").endsWith("/v1/logs");
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,20 +16,20 @@
|
||||||
|
|
||||||
package org.springframework.boot.docker.compose.service.connection.otlp;
|
package org.springframework.boot.docker.compose.service.connection.otlp;
|
||||||
|
|
||||||
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.core.RunningService;
|
||||||
import org.springframework.boot.docker.compose.service.connection.DockerComposeConnectionDetailsFactory;
|
import org.springframework.boot.docker.compose.service.connection.DockerComposeConnectionDetailsFactory;
|
||||||
import org.springframework.boot.docker.compose.service.connection.DockerComposeConnectionSource;
|
import org.springframework.boot.docker.compose.service.connection.DockerComposeConnectionSource;
|
||||||
|
import org.springframework.boot.opentelemetry.actuate.autoconfigure.logging.OpenTelemetryLoggingConnectionDetails;
|
||||||
|
import org.springframework.boot.opentelemetry.actuate.autoconfigure.logging.Transport;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* {@link DockerComposeConnectionDetailsFactory} to create
|
* {@link DockerComposeConnectionDetailsFactory} to create
|
||||||
* {@link OtlpLoggingConnectionDetails} for an OTLP service.
|
* {@link OpenTelemetryLoggingConnectionDetails} for an OTLP service.
|
||||||
*
|
*
|
||||||
* @author Eddú Meléndez
|
* @author Eddú Meléndez
|
||||||
*/
|
*/
|
||||||
class OpenTelemetryLoggingDockerComposeConnectionDetailsFactory
|
class OpenTelemetryLoggingDockerComposeConnectionDetailsFactory
|
||||||
extends DockerComposeConnectionDetailsFactory<OtlpLoggingConnectionDetails> {
|
extends DockerComposeConnectionDetailsFactory<OpenTelemetryLoggingConnectionDetails> {
|
||||||
|
|
||||||
private static final String[] OPENTELEMETRY_IMAGE_NAMES = { "otel/opentelemetry-collector-contrib",
|
private static final String[] OPENTELEMETRY_IMAGE_NAMES = { "otel/opentelemetry-collector-contrib",
|
||||||
"grafana/otel-lgtm" };
|
"grafana/otel-lgtm" };
|
||||||
|
@ -40,16 +40,17 @@ class OpenTelemetryLoggingDockerComposeConnectionDetailsFactory
|
||||||
|
|
||||||
OpenTelemetryLoggingDockerComposeConnectionDetailsFactory() {
|
OpenTelemetryLoggingDockerComposeConnectionDetailsFactory() {
|
||||||
super(OPENTELEMETRY_IMAGE_NAMES,
|
super(OPENTELEMETRY_IMAGE_NAMES,
|
||||||
"org.springframework.boot.actuate.autoconfigure.logging.otlp.OtlpLoggingAutoConfiguration");
|
"org.springframework.boot.opentelemetry.actuate.autoconfigure.logging.OpenTelemetryLoggingExportAutoConfiguration");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected OtlpLoggingConnectionDetails getDockerComposeConnectionDetails(DockerComposeConnectionSource source) {
|
protected OpenTelemetryLoggingConnectionDetails getDockerComposeConnectionDetails(
|
||||||
|
DockerComposeConnectionSource source) {
|
||||||
return new OpenTelemetryLoggingDockerComposeConnectionDetails(source.getRunningService());
|
return new OpenTelemetryLoggingDockerComposeConnectionDetails(source.getRunningService());
|
||||||
}
|
}
|
||||||
|
|
||||||
private static final class OpenTelemetryLoggingDockerComposeConnectionDetails extends DockerComposeConnectionDetails
|
private static final class OpenTelemetryLoggingDockerComposeConnectionDetails extends DockerComposeConnectionDetails
|
||||||
implements OtlpLoggingConnectionDetails {
|
implements OpenTelemetryLoggingConnectionDetails {
|
||||||
|
|
||||||
private final String host;
|
private final String host;
|
||||||
|
|
||||||
|
|
|
@ -128,6 +128,7 @@ dependencies {
|
||||||
autoConfiguration(project(path: ":spring-boot-project:spring-boot-mustache", configuration: "autoConfigurationMetadata"))
|
autoConfiguration(project(path: ":spring-boot-project:spring-boot-mustache", configuration: "autoConfigurationMetadata"))
|
||||||
autoConfiguration(project(path: ":spring-boot-project:spring-boot-neo4j", configuration: "autoConfigurationMetadata"))
|
autoConfiguration(project(path: ":spring-boot-project:spring-boot-neo4j", configuration: "autoConfigurationMetadata"))
|
||||||
autoConfiguration(project(path: ":spring-boot-project:spring-boot-netty", configuration: "autoConfigurationMetadata"))
|
autoConfiguration(project(path: ":spring-boot-project:spring-boot-netty", configuration: "autoConfigurationMetadata"))
|
||||||
|
autoConfiguration(project(path: ":spring-boot-project:spring-boot-opentelemetry", configuration: "autoConfigurationMetadata"))
|
||||||
autoConfiguration(project(path: ":spring-boot-project:spring-boot-pulsar", configuration: "autoConfigurationMetadata"))
|
autoConfiguration(project(path: ":spring-boot-project:spring-boot-pulsar", configuration: "autoConfigurationMetadata"))
|
||||||
autoConfiguration(project(path: ":spring-boot-project:spring-boot-quartz", configuration: "autoConfigurationMetadata"))
|
autoConfiguration(project(path: ":spring-boot-project:spring-boot-quartz", configuration: "autoConfigurationMetadata"))
|
||||||
autoConfiguration(project(path: ":spring-boot-project:spring-boot-r2dbc", configuration: "autoConfigurationMetadata"))
|
autoConfiguration(project(path: ":spring-boot-project:spring-boot-r2dbc", configuration: "autoConfigurationMetadata"))
|
||||||
|
@ -212,6 +213,7 @@ dependencies {
|
||||||
configurationProperties(project(path: ":spring-boot-project:spring-boot-mustache", configuration: "configurationPropertiesMetadata"))
|
configurationProperties(project(path: ":spring-boot-project:spring-boot-mustache", configuration: "configurationPropertiesMetadata"))
|
||||||
configurationProperties(project(path: ":spring-boot-project:spring-boot-neo4j", configuration: "configurationPropertiesMetadata"))
|
configurationProperties(project(path: ":spring-boot-project:spring-boot-neo4j", configuration: "configurationPropertiesMetadata"))
|
||||||
configurationProperties(project(path: ":spring-boot-project:spring-boot-netty", configuration: "configurationPropertiesMetadata"))
|
configurationProperties(project(path: ":spring-boot-project:spring-boot-netty", configuration: "configurationPropertiesMetadata"))
|
||||||
|
configurationProperties(project(path: ":spring-boot-project:spring-boot-opentelemetry", configuration: "configurationPropertiesMetadata"))
|
||||||
configurationProperties(project(path: ":spring-boot-project:spring-boot-pulsar", configuration: "configurationPropertiesMetadata"))
|
configurationProperties(project(path: ":spring-boot-project:spring-boot-pulsar", configuration: "configurationPropertiesMetadata"))
|
||||||
configurationProperties(project(path: ":spring-boot-project:spring-boot-quartz", configuration: "configurationPropertiesMetadata"))
|
configurationProperties(project(path: ":spring-boot-project:spring-boot-quartz", configuration: "configurationPropertiesMetadata"))
|
||||||
configurationProperties(project(path: ":spring-boot-project:spring-boot-r2dbc", configuration: "configurationPropertiesMetadata"))
|
configurationProperties(project(path: ":spring-boot-project:spring-boot-r2dbc", configuration: "configurationPropertiesMetadata"))
|
||||||
|
|
|
@ -42,8 +42,9 @@ You have to provide the location of the OpenTelemetry logs endpoint to configure
|
||||||
[configprops,yaml]
|
[configprops,yaml]
|
||||||
----
|
----
|
||||||
management:
|
management:
|
||||||
otlp:
|
opentelemetry:
|
||||||
logging:
|
logging:
|
||||||
|
export:
|
||||||
endpoint: "https://otlp.example.com:4318/v1/logs"
|
endpoint: "https://otlp.example.com:4318/v1/logs"
|
||||||
----
|
----
|
||||||
|
|
||||||
|
|
|
@ -110,7 +110,7 @@ The following service connections are currently supported:
|
||||||
| javadoc:org.springframework.boot.neo4j.autoconfigure.Neo4jConnectionDetails[]
|
| javadoc:org.springframework.boot.neo4j.autoconfigure.Neo4jConnectionDetails[]
|
||||||
| Containers named "neo4j" or "bitnami/neo4j"
|
| Containers named "neo4j" or "bitnami/neo4j"
|
||||||
|
|
||||||
| javadoc:org.springframework.boot.actuate.autoconfigure.logging.otlp.OtlpLoggingConnectionDetails[]
|
| javadoc:org.springframework.boot.opentelemetry.actuate.autoconfigure.logging.OpenTelemetryLoggingConnectionDetails[]
|
||||||
| Containers named "otel/opentelemetry-collector-contrib", "grafana/otel-lgtm"
|
| Containers named "otel/opentelemetry-collector-contrib", "grafana/otel-lgtm"
|
||||||
|
|
||||||
| javadoc:org.springframework.boot.actuate.autoconfigure.metrics.export.otlp.OtlpMetricsConnectionDetails[]
|
| javadoc:org.springframework.boot.actuate.autoconfigure.metrics.export.otlp.OtlpMetricsConnectionDetails[]
|
||||||
|
|
|
@ -155,7 +155,7 @@ The following service connection factories are provided in the `spring-boot-test
|
||||||
| javadoc:org.springframework.boot.neo4j.autoconfigure.Neo4jConnectionDetails[]
|
| javadoc:org.springframework.boot.neo4j.autoconfigure.Neo4jConnectionDetails[]
|
||||||
| Containers of type javadoc:{url-testcontainers-neo4j-javadoc}/org.testcontainers.containers.Neo4jContainer[]
|
| Containers of type javadoc:{url-testcontainers-neo4j-javadoc}/org.testcontainers.containers.Neo4jContainer[]
|
||||||
|
|
||||||
| javadoc:org.springframework.boot.actuate.autoconfigure.logging.otlp.OtlpLoggingConnectionDetails[]
|
| javadoc:org.springframework.boot.opentelemetry.actuate.autoconfigure.logging.OpenTelemetryLoggingConnectionDetails[]
|
||||||
| Containers named "otel/opentelemetry-collector-contrib" or of type javadoc:org.testcontainers.grafana.LgtmStackContainer[]
|
| Containers named "otel/opentelemetry-collector-contrib" or of type javadoc:org.testcontainers.grafana.LgtmStackContainer[]
|
||||||
|
|
||||||
| javadoc:org.springframework.boot.actuate.autoconfigure.metrics.export.otlp.OtlpMetricsConnectionDetails[]
|
| javadoc:org.springframework.boot.actuate.autoconfigure.metrics.export.otlp.OtlpMetricsConnectionDetails[]
|
||||||
|
|
|
@ -0,0 +1,44 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2012-present 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
plugins {
|
||||||
|
id "java-library"
|
||||||
|
id "org.springframework.boot.auto-configuration"
|
||||||
|
id "org.springframework.boot.configuration-properties"
|
||||||
|
id "org.springframework.boot.deployed"
|
||||||
|
id "org.springframework.boot.docker-test"
|
||||||
|
id "org.springframework.boot.optional-dependencies"
|
||||||
|
}
|
||||||
|
|
||||||
|
description = "Spring Boot Open Telemetry"
|
||||||
|
|
||||||
|
dependencies {
|
||||||
|
api(project(":spring-boot-project:spring-boot"))
|
||||||
|
api("io.opentelemetry:opentelemetry-api")
|
||||||
|
api("io.opentelemetry:opentelemetry-sdk")
|
||||||
|
|
||||||
|
optional(project(":spring-boot-project:spring-boot-autoconfigure"))
|
||||||
|
optional(project(":spring-boot-project:spring-boot-actuator-autoconfigure"))
|
||||||
|
optional("io.opentelemetry:opentelemetry-exporter-otlp")
|
||||||
|
|
||||||
|
testImplementation(project(":spring-boot-project:spring-boot-test"))
|
||||||
|
testImplementation(project(":spring-boot-project:spring-boot-tools:spring-boot-test-support"))
|
||||||
|
testImplementation("com.squareup.okhttp3:mockwebserver")
|
||||||
|
|
||||||
|
testRuntimeOnly("ch.qos.logback:logback-classic")
|
||||||
|
testRuntimeOnly("io.grpc:grpc-api:1.72.0")
|
||||||
|
}
|
|
@ -14,17 +14,18 @@
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package org.springframework.boot.actuate.autoconfigure.logging.otlp;
|
package org.springframework.boot.opentelemetry.actuate.autoconfigure.logging;
|
||||||
|
|
||||||
import org.springframework.boot.autoconfigure.service.connection.ConnectionDetails;
|
import org.springframework.boot.autoconfigure.service.connection.ConnectionDetails;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Details required to establish a connection to an OpenTelemetry logging service.
|
* Details required for actuator to establish a connection to an OpenTelemetry logging
|
||||||
|
* service.
|
||||||
*
|
*
|
||||||
* @author Toshiaki Maki
|
* @author Toshiaki Maki
|
||||||
* @since 3.4.0
|
* @since 4.0.0
|
||||||
*/
|
*/
|
||||||
public interface OtlpLoggingConnectionDetails extends ConnectionDetails {
|
public interface OpenTelemetryLoggingConnectionDetails extends ConnectionDetails {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Address to where logs will be published.
|
* Address to where logs will be published.
|
|
@ -0,0 +1,63 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2012-present 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.opentelemetry.actuate.autoconfigure.logging;
|
||||||
|
|
||||||
|
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;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@link Configuration @Configuration} for {@link OpenTelemetryLoggingConnectionDetails}.
|
||||||
|
*
|
||||||
|
* @author Toshiaki Maki
|
||||||
|
*/
|
||||||
|
@Configuration(proxyBeanMethods = false)
|
||||||
|
class OpenTelemetryLoggingConnectionDetailsConfiguration {
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
@ConditionalOnMissingBean
|
||||||
|
@ConditionalOnProperty("management.opentelemetry.logging.export.endpoint")
|
||||||
|
PropertiesOpenTelemetryLoggingConnectionDetails openTelemetryLoggingConnectionDetails(
|
||||||
|
OpenTelemetryLoggingExportProperties properties) {
|
||||||
|
return new PropertiesOpenTelemetryLoggingConnectionDetails(properties);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adapts {@link OpenTelemetryLoggingExportProperties} to
|
||||||
|
* {@link OpenTelemetryLoggingConnectionDetails}.
|
||||||
|
*/
|
||||||
|
static class PropertiesOpenTelemetryLoggingConnectionDetails implements OpenTelemetryLoggingConnectionDetails {
|
||||||
|
|
||||||
|
private final OpenTelemetryLoggingExportProperties properties;
|
||||||
|
|
||||||
|
PropertiesOpenTelemetryLoggingConnectionDetails(OpenTelemetryLoggingExportProperties properties) {
|
||||||
|
this.properties = properties;
|
||||||
|
}
|
||||||
|
|
||||||
|
@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();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -14,12 +14,12 @@
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package org.springframework.boot.actuate.autoconfigure.logging.otlp;
|
package org.springframework.boot.opentelemetry.actuate.autoconfigure.logging;
|
||||||
|
|
||||||
import io.opentelemetry.api.OpenTelemetry;
|
import io.opentelemetry.api.OpenTelemetry;
|
||||||
import io.opentelemetry.exporter.otlp.http.logs.OtlpHttpLogRecordExporter;
|
|
||||||
import io.opentelemetry.sdk.logs.SdkLoggerProvider;
|
import io.opentelemetry.sdk.logs.SdkLoggerProvider;
|
||||||
|
|
||||||
|
import org.springframework.boot.actuate.autoconfigure.logging.ConditionalOnEnabledLoggingExport;
|
||||||
import org.springframework.boot.autoconfigure.AutoConfiguration;
|
import org.springframework.boot.autoconfigure.AutoConfiguration;
|
||||||
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
|
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
|
||||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
|
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
|
||||||
|
@ -27,15 +27,16 @@ import org.springframework.boot.context.properties.EnableConfigurationProperties
|
||||||
import org.springframework.context.annotation.Import;
|
import org.springframework.context.annotation.Import;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* {@link EnableAutoConfiguration Auto-configuration} for OTLP logging.
|
* {@link EnableAutoConfiguration Auto-configuration} for OpenTelemetry logging exports.
|
||||||
*
|
*
|
||||||
* @author Toshiaki Maki
|
* @author Toshiaki Maki
|
||||||
* @since 3.4.0
|
* @since 4.0.0
|
||||||
*/
|
*/
|
||||||
@AutoConfiguration
|
@AutoConfiguration
|
||||||
@ConditionalOnClass({ SdkLoggerProvider.class, OpenTelemetry.class, OtlpHttpLogRecordExporter.class })
|
@ConditionalOnClass({ ConditionalOnEnabledLoggingExport.class, OpenTelemetry.class, SdkLoggerProvider.class })
|
||||||
@EnableConfigurationProperties(OtlpLoggingProperties.class)
|
@ConditionalOnEnabledLoggingExport("opentelemetry")
|
||||||
@Import({ OtlpLoggingConfigurations.ConnectionDetails.class, OtlpLoggingConfigurations.Exporters.class })
|
@EnableConfigurationProperties(OpenTelemetryLoggingExportProperties.class)
|
||||||
public class OtlpLoggingAutoConfiguration {
|
@Import({ OpenTelemetryLoggingConnectionDetailsConfiguration.class, OpenTelemetryLoggingTransportConfiguration.class })
|
||||||
|
public class OpenTelemetryLoggingExportAutoConfiguration {
|
||||||
|
|
||||||
}
|
}
|
|
@ -14,7 +14,7 @@
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package org.springframework.boot.actuate.autoconfigure.logging.otlp;
|
package org.springframework.boot.opentelemetry.actuate.autoconfigure.logging;
|
||||||
|
|
||||||
import java.time.Duration;
|
import java.time.Duration;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
|
@ -23,13 +23,13 @@ import java.util.Map;
|
||||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Configuration properties for exporting logs using OTLP.
|
* Configuration properties for exporting logs using OpenTelemetry.
|
||||||
*
|
*
|
||||||
* @author Jonatan Ivanov
|
* @author Jonatan Ivanov
|
||||||
* @since 3.4.0
|
* @since 4.0.0
|
||||||
*/
|
*/
|
||||||
@ConfigurationProperties("management.otlp.logging")
|
@ConfigurationProperties("management.opentelemetry.logging.export")
|
||||||
public class OtlpLoggingProperties {
|
public class OpenTelemetryLoggingExportProperties {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* URL to the OTel collector's HTTP API.
|
* URL to the OTel collector's HTTP API.
|
|
@ -0,0 +1,75 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2012-present 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.opentelemetry.actuate.autoconfigure.logging;
|
||||||
|
|
||||||
|
import java.util.Locale;
|
||||||
|
|
||||||
|
import io.opentelemetry.api.metrics.MeterProvider;
|
||||||
|
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.beans.factory.ObjectProvider;
|
||||||
|
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
|
||||||
|
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
|
||||||
|
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;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@link Configuration @Configuration} for OpenTelemetry log record exporters.
|
||||||
|
*
|
||||||
|
* @author Toshiaki Maki
|
||||||
|
*/
|
||||||
|
@Configuration(proxyBeanMethods = false)
|
||||||
|
@ConditionalOnClass(OtlpHttpLogRecordExporter.class)
|
||||||
|
@ConditionalOnMissingBean({ OtlpGrpcLogRecordExporter.class, OtlpHttpLogRecordExporter.class })
|
||||||
|
@ConditionalOnBean(OpenTelemetryLoggingConnectionDetails.class)
|
||||||
|
class OpenTelemetryLoggingTransportConfiguration {
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
@ConditionalOnProperty(name = "management.opentelemetry.logging.export.transport", havingValue = "http",
|
||||||
|
matchIfMissing = true)
|
||||||
|
OtlpHttpLogRecordExporter otlpHttpLogRecordExporter(OpenTelemetryLoggingExportProperties properties,
|
||||||
|
OpenTelemetryLoggingConnectionDetails connectionDetails, ObjectProvider<MeterProvider> meterProvider) {
|
||||||
|
OtlpHttpLogRecordExporterBuilder builder = OtlpHttpLogRecordExporter.builder()
|
||||||
|
.setEndpoint(connectionDetails.getUrl(Transport.HTTP))
|
||||||
|
.setTimeout(properties.getTimeout())
|
||||||
|
.setConnectTimeout(properties.getConnectTimeout())
|
||||||
|
.setCompression(properties.getCompression().name().toLowerCase(Locale.US));
|
||||||
|
properties.getHeaders().forEach(builder::addHeader);
|
||||||
|
meterProvider.ifAvailable(builder::setMeterProvider);
|
||||||
|
return builder.build();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
@ConditionalOnProperty(name = "management.opentelemetry.logging.export.transport", havingValue = "grpc")
|
||||||
|
OtlpGrpcLogRecordExporter otlpGrpcLogRecordExporter(OpenTelemetryLoggingExportProperties properties,
|
||||||
|
OpenTelemetryLoggingConnectionDetails connectionDetails, ObjectProvider<MeterProvider> meterProvider) {
|
||||||
|
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);
|
||||||
|
meterProvider.ifAvailable(builder::setMeterProvider);
|
||||||
|
return builder.build();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -14,13 +14,13 @@
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package org.springframework.boot.actuate.autoconfigure.logging.otlp;
|
package org.springframework.boot.opentelemetry.actuate.autoconfigure.logging;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Transport used to send OTLP data.
|
* Transport used to send OTLP log data.
|
||||||
*
|
*
|
||||||
* @author Moritz Halbritter
|
* @author Moritz Halbritter
|
||||||
* @since 3.4.0
|
* @since 4.0.0
|
||||||
*/
|
*/
|
||||||
public enum Transport {
|
public enum Transport {
|
||||||
|
|
|
@ -15,6 +15,6 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Auto-configuration for exporting logs with OTLP.
|
* Auto-configuration for exporting logs with OpenTelemetry.
|
||||||
*/
|
*/
|
||||||
package org.springframework.boot.actuate.autoconfigure.logging.otlp;
|
package org.springframework.boot.opentelemetry.actuate.autoconfigure.logging;
|
|
@ -14,7 +14,7 @@
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package org.springframework.boot.actuate.autoconfigure.opentelemetry;
|
package org.springframework.boot.opentelemetry.autoconfigure;
|
||||||
|
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
|
@ -14,7 +14,7 @@
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package org.springframework.boot.actuate.autoconfigure.opentelemetry;
|
package org.springframework.boot.opentelemetry.autoconfigure;
|
||||||
|
|
||||||
import java.io.ByteArrayOutputStream;
|
import java.io.ByteArrayOutputStream;
|
||||||
import java.nio.charset.StandardCharsets;
|
import java.nio.charset.StandardCharsets;
|
||||||
|
@ -39,9 +39,9 @@ import org.springframework.util.StringUtils;
|
||||||
* Resource Specification</a>
|
* Resource Specification</a>
|
||||||
*
|
*
|
||||||
* @author Dmytro Nosan
|
* @author Dmytro Nosan
|
||||||
* @since 3.5.0
|
* @since 4.0.0
|
||||||
*/
|
*/
|
||||||
public final class OpenTelemetryResourceAttributes {
|
public class OpenTelemetryResourceAttributes {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Default value for service name if {@code service.name} is not set.
|
* Default value for service name if {@code service.name} is not set.
|
||||||
|
@ -52,7 +52,7 @@ public final class OpenTelemetryResourceAttributes {
|
||||||
|
|
||||||
private final Map<String, String> resourceAttributes;
|
private final Map<String, String> resourceAttributes;
|
||||||
|
|
||||||
private final Function<String, String> getEnv;
|
private final Function<String, String> systemEnvironment;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a new instance of {@link OpenTelemetryResourceAttributes}.
|
* Creates a new instance of {@link OpenTelemetryResourceAttributes}.
|
||||||
|
@ -67,14 +67,14 @@ public final class OpenTelemetryResourceAttributes {
|
||||||
* Creates a new {@link OpenTelemetryResourceAttributes} instance.
|
* Creates a new {@link OpenTelemetryResourceAttributes} instance.
|
||||||
* @param environment the environment
|
* @param environment the environment
|
||||||
* @param resourceAttributes user-provided resource attributes to be used
|
* @param resourceAttributes user-provided resource attributes to be used
|
||||||
* @param getEnv a function to retrieve environment variables by name
|
* @param systemEnvironment a function to retrieve environment variables by name
|
||||||
*/
|
*/
|
||||||
OpenTelemetryResourceAttributes(Environment environment, Map<String, String> resourceAttributes,
|
OpenTelemetryResourceAttributes(Environment environment, Map<String, String> resourceAttributes,
|
||||||
Function<String, String> getEnv) {
|
Function<String, String> systemEnvironment) {
|
||||||
Assert.notNull(environment, "'environment' must not be null");
|
Assert.notNull(environment, "'environment' must not be null");
|
||||||
this.environment = environment;
|
this.environment = environment;
|
||||||
this.resourceAttributes = (resourceAttributes != null) ? resourceAttributes : Collections.emptyMap();
|
this.resourceAttributes = (resourceAttributes != null) ? resourceAttributes : Collections.emptyMap();
|
||||||
this.getEnv = (getEnv != null) ? getEnv : System::getenv;
|
this.systemEnvironment = (systemEnvironment != null) ? systemEnvironment : System::getenv;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -150,7 +150,7 @@ public final class OpenTelemetryResourceAttributes {
|
||||||
}
|
}
|
||||||
|
|
||||||
private String getEnv(String name) {
|
private String getEnv(String name) {
|
||||||
return this.getEnv.apply(name);
|
return this.systemEnvironment.apply(name);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -166,17 +166,17 @@ public final class OpenTelemetryResourceAttributes {
|
||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
byte[] bytes = value.getBytes(StandardCharsets.UTF_8);
|
byte[] bytes = value.getBytes(StandardCharsets.UTF_8);
|
||||||
ByteArrayOutputStream bos = new ByteArrayOutputStream(bytes.length);
|
ByteArrayOutputStream out = new ByteArrayOutputStream(bytes.length);
|
||||||
for (int i = 0; i < bytes.length; i++) {
|
for (int i = 0; i < bytes.length; i++) {
|
||||||
byte b = bytes[i];
|
byte b = bytes[i];
|
||||||
if (b != '%') {
|
if (b != '%') {
|
||||||
bos.write(b);
|
out.write(b);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
int u = decodeHex(bytes, i + 1);
|
int u = decodeHex(bytes, i + 1);
|
||||||
int l = decodeHex(bytes, i + 2);
|
int l = decodeHex(bytes, i + 2);
|
||||||
if (u >= 0 && l >= 0) {
|
if (u >= 0 && l >= 0) {
|
||||||
bos.write((u << 4) + l);
|
out.write((u << 4) + l);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
throw new IllegalArgumentException(
|
throw new IllegalArgumentException(
|
||||||
|
@ -185,7 +185,7 @@ public final class OpenTelemetryResourceAttributes {
|
||||||
}
|
}
|
||||||
i += 2;
|
i += 2;
|
||||||
}
|
}
|
||||||
return bos.toString(StandardCharsets.UTF_8);
|
return out.toString(StandardCharsets.UTF_8);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static int decodeHex(byte[] bytes, int index) {
|
private static int decodeHex(byte[] bytes, int index) {
|
|
@ -14,13 +14,17 @@
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package org.springframework.boot.actuate.autoconfigure.opentelemetry;
|
package org.springframework.boot.opentelemetry.autoconfigure;
|
||||||
|
|
||||||
import io.opentelemetry.api.OpenTelemetry;
|
import io.opentelemetry.api.OpenTelemetry;
|
||||||
import io.opentelemetry.context.propagation.ContextPropagators;
|
import io.opentelemetry.context.propagation.ContextPropagators;
|
||||||
import io.opentelemetry.sdk.OpenTelemetrySdk;
|
import io.opentelemetry.sdk.OpenTelemetrySdk;
|
||||||
import io.opentelemetry.sdk.OpenTelemetrySdkBuilder;
|
import io.opentelemetry.sdk.OpenTelemetrySdkBuilder;
|
||||||
|
import io.opentelemetry.sdk.logs.LogRecordProcessor;
|
||||||
import io.opentelemetry.sdk.logs.SdkLoggerProvider;
|
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.metrics.SdkMeterProvider;
|
import io.opentelemetry.sdk.metrics.SdkMeterProvider;
|
||||||
import io.opentelemetry.sdk.resources.Resource;
|
import io.opentelemetry.sdk.resources.Resource;
|
||||||
import io.opentelemetry.sdk.resources.ResourceBuilder;
|
import io.opentelemetry.sdk.resources.ResourceBuilder;
|
||||||
|
@ -33,37 +37,41 @@ import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
|
||||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
|
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
|
||||||
import org.springframework.boot.context.properties.EnableConfigurationProperties;
|
import org.springframework.boot.context.properties.EnableConfigurationProperties;
|
||||||
import org.springframework.context.annotation.Bean;
|
import org.springframework.context.annotation.Bean;
|
||||||
|
import org.springframework.context.annotation.Configuration;
|
||||||
import org.springframework.core.env.Environment;
|
import org.springframework.core.env.Environment;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* {@link EnableAutoConfiguration Auto-configuration} for OpenTelemetry.
|
* {@link EnableAutoConfiguration Auto-configuration} for the OpenTelemetry SDK.
|
||||||
*
|
*
|
||||||
* @author Moritz Halbritter
|
* @author Moritz Halbritter
|
||||||
* @since 3.2.0
|
* @since 4.0.0
|
||||||
*/
|
*/
|
||||||
@AutoConfiguration
|
@AutoConfiguration
|
||||||
@ConditionalOnClass(OpenTelemetrySdk.class)
|
@ConditionalOnClass({ OpenTelemetry.class, OpenTelemetrySdk.class })
|
||||||
@EnableConfigurationProperties(OpenTelemetryProperties.class)
|
@EnableConfigurationProperties(OpenTelemetryProperties.class)
|
||||||
public class OpenTelemetryAutoConfiguration {
|
public class OpenTelemetrySdkAutoConfiguration {
|
||||||
|
|
||||||
|
OpenTelemetrySdkAutoConfiguration() {
|
||||||
|
}
|
||||||
|
|
||||||
@Bean
|
@Bean
|
||||||
@ConditionalOnMissingBean(OpenTelemetry.class)
|
@ConditionalOnMissingBean(OpenTelemetry.class)
|
||||||
OpenTelemetrySdk openTelemetry(ObjectProvider<SdkTracerProvider> tracerProvider,
|
OpenTelemetrySdk openTelemetrySdk(ObjectProvider<SdkTracerProvider> openTelemetrySdkTracerProvider,
|
||||||
ObjectProvider<ContextPropagators> propagators, ObjectProvider<SdkLoggerProvider> loggerProvider,
|
ObjectProvider<ContextPropagators> openTelemetryContextPropagators,
|
||||||
ObjectProvider<SdkMeterProvider> meterProvider) {
|
ObjectProvider<SdkLoggerProvider> openTelemetrySdkLoggerProvider,
|
||||||
|
ObjectProvider<SdkMeterProvider> openTelemetrySdkMeterProvider) {
|
||||||
OpenTelemetrySdkBuilder builder = OpenTelemetrySdk.builder();
|
OpenTelemetrySdkBuilder builder = OpenTelemetrySdk.builder();
|
||||||
tracerProvider.ifAvailable(builder::setTracerProvider);
|
openTelemetrySdkTracerProvider.ifAvailable(builder::setTracerProvider);
|
||||||
propagators.ifAvailable(builder::setPropagators);
|
openTelemetryContextPropagators.ifAvailable(builder::setPropagators);
|
||||||
loggerProvider.ifAvailable(builder::setLoggerProvider);
|
openTelemetrySdkLoggerProvider.ifAvailable(builder::setLoggerProvider);
|
||||||
meterProvider.ifAvailable(builder::setMeterProvider);
|
openTelemetrySdkMeterProvider.ifAvailable(builder::setMeterProvider);
|
||||||
return builder.build();
|
return builder.build();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Bean
|
@Bean
|
||||||
@ConditionalOnMissingBean
|
@ConditionalOnMissingBean
|
||||||
Resource openTelemetryResource(Environment environment, OpenTelemetryProperties properties) {
|
Resource openTelemetryResource(Environment environment, OpenTelemetryProperties properties) {
|
||||||
Resource resource = Resource.getDefault();
|
return Resource.getDefault().merge(toResource(environment, properties));
|
||||||
return resource.merge(toResource(environment, properties));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private Resource toResource(Environment environment, OpenTelemetryProperties properties) {
|
private Resource toResource(Environment environment, OpenTelemetryProperties properties) {
|
||||||
|
@ -72,4 +80,30 @@ public class OpenTelemetryAutoConfiguration {
|
||||||
return builder.build();
|
return builder.build();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Configuration(proxyBeanMethods = false)
|
||||||
|
@ConditionalOnClass(SdkLoggerProvider.class)
|
||||||
|
static class LoggerConfiguration {
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
@ConditionalOnMissingBean
|
||||||
|
BatchLogRecordProcessor openTelemetryBatchLogRecordProcessor(
|
||||||
|
ObjectProvider<LogRecordExporter> logRecordExporters) {
|
||||||
|
LogRecordExporter exporter = LogRecordExporter.composite(logRecordExporters.orderedStream().toList());
|
||||||
|
return BatchLogRecordProcessor.builder(exporter).build();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
@ConditionalOnMissingBean
|
||||||
|
SdkLoggerProvider openTelemetrySdkLoggerProvider(Resource openTelemetryResource,
|
||||||
|
ObjectProvider<LogRecordProcessor> logRecordProcessors,
|
||||||
|
ObjectProvider<SdkLoggerProviderBuilderCustomizer> customizers) {
|
||||||
|
SdkLoggerProviderBuilder builder = SdkLoggerProvider.builder();
|
||||||
|
builder.setResource(openTelemetryResource);
|
||||||
|
logRecordProcessors.orderedStream().forEach(builder::addLogRecordProcessor);
|
||||||
|
customizers.orderedStream().forEach((customizer) -> customizer.customize(builder));
|
||||||
|
return builder.build();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
|
@ -14,7 +14,7 @@
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package org.springframework.boot.actuate.autoconfigure.logging;
|
package org.springframework.boot.opentelemetry.autoconfigure;
|
||||||
|
|
||||||
import io.opentelemetry.sdk.logs.SdkLoggerProvider;
|
import io.opentelemetry.sdk.logs.SdkLoggerProvider;
|
||||||
import io.opentelemetry.sdk.logs.SdkLoggerProviderBuilder;
|
import io.opentelemetry.sdk.logs.SdkLoggerProviderBuilder;
|
||||||
|
@ -24,7 +24,7 @@ import io.opentelemetry.sdk.logs.SdkLoggerProviderBuilder;
|
||||||
* that is used to create the auto-configured {@link SdkLoggerProvider}.
|
* that is used to create the auto-configured {@link SdkLoggerProvider}.
|
||||||
*
|
*
|
||||||
* @author Toshiaki Maki
|
* @author Toshiaki Maki
|
||||||
* @since 3.4.0
|
* @since 4.0.0
|
||||||
*/
|
*/
|
||||||
@FunctionalInterface
|
@FunctionalInterface
|
||||||
public interface SdkLoggerProviderBuilderCustomizer {
|
public interface SdkLoggerProviderBuilderCustomizer {
|
|
@ -17,4 +17,4 @@
|
||||||
/**
|
/**
|
||||||
* Auto-configuration for OpenTelemetry.
|
* Auto-configuration for OpenTelemetry.
|
||||||
*/
|
*/
|
||||||
package org.springframework.boot.actuate.autoconfigure.opentelemetry;
|
package org.springframework.boot.opentelemetry.autoconfigure;
|
|
@ -0,0 +1,98 @@
|
||||||
|
{
|
||||||
|
"groups": [],
|
||||||
|
"properties": [
|
||||||
|
{
|
||||||
|
"name": "management.logging.export.enabled",
|
||||||
|
"type": "java.lang.Boolean",
|
||||||
|
"description": "Whether auto-configuration of logging is enabled to export logs.",
|
||||||
|
"defaultValue": true,
|
||||||
|
"deprecation": {
|
||||||
|
"replacement": "management.opentelemetry.logging.export.enabled",
|
||||||
|
"level": "error"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "management.otlp.logging",
|
||||||
|
"type": "org.springframework.boot.opentelemetry.actuate.autoconfigure.logging.OpenTelemetryLoggingExportProperties",
|
||||||
|
"sourceType": "org.springframework.boot.opentelemetry.actuate.autoconfigure.logging.OpenTelemetryLoggingExportProperties",
|
||||||
|
"deprecation": {
|
||||||
|
"replacement": "management.opentelemetry.logging.export",
|
||||||
|
"level": "error"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "management.otlp.logging.compression",
|
||||||
|
"type": "org.springframework.boot.opentelemetry.actuate.autoconfigure.logging.OpenTelemetryLoggingExportProperties$Compression",
|
||||||
|
"description": "Method used to compress the payload.",
|
||||||
|
"sourceType": "org.springframework.boot.opentelemetry.actuate.autoconfigure.logging.OpenTelemetryLoggingExportProperties",
|
||||||
|
"defaultValue": "none",
|
||||||
|
"deprecation": {
|
||||||
|
"replacement": "management.opentelemetry.logging.export.compression",
|
||||||
|
"level": "error"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "management.otlp.logging.connect-timeout",
|
||||||
|
"type": "java.time.Duration",
|
||||||
|
"description": "Connect timeout for the OTel collector connection.",
|
||||||
|
"sourceType": "org.springframework.boot.opentelemetry.actuate.autoconfigure.logging.OpenTelemetryLoggingExportProperties",
|
||||||
|
"defaultValue": "10s",
|
||||||
|
"deprecation": {
|
||||||
|
"replacement": "management.opentelemetry.logging.export.connect-timeout",
|
||||||
|
"level": "error"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "management.otlp.logging.endpoint",
|
||||||
|
"type": "java.lang.String",
|
||||||
|
"description": "URL to the OTel collector's HTTP API.",
|
||||||
|
"sourceType": "org.springframework.boot.opentelemetry.actuate.autoconfigure.logging.OpenTelemetryLoggingExportProperties",
|
||||||
|
"deprecation": {
|
||||||
|
"replacement": "management.opentelemetry.logging.export.endpoint",
|
||||||
|
"level": "error"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "management.otlp.logging.export.enabled",
|
||||||
|
"type": "java.lang.Boolean",
|
||||||
|
"description": "Whether auto-configuration of logging is enabled to export OTLP logs.",
|
||||||
|
"deprecation": {
|
||||||
|
"replacement": "management.opentelemetry.logging.export.enabled",
|
||||||
|
"level": "error"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "management.otlp.logging.headers",
|
||||||
|
"type": "java.util.Map<java.lang.String,java.lang.String>",
|
||||||
|
"description": "Custom HTTP headers you want to pass to the collector, for example auth headers.",
|
||||||
|
"sourceType": "org.springframework.boot.opentelemetry.actuate.autoconfigure.logging.OpenTelemetryLoggingExportProperties",
|
||||||
|
"deprecation": {
|
||||||
|
"replacement": "management.opentelemetry.logging.export.headers",
|
||||||
|
"level": "error"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "management.otlp.logging.timeout",
|
||||||
|
"type": "java.time.Duration",
|
||||||
|
"description": "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.",
|
||||||
|
"sourceType": "org.springframework.boot.opentelemetry.actuate.autoconfigure.logging.OpenTelemetryLoggingExportProperties",
|
||||||
|
"defaultValue": "10s",
|
||||||
|
"deprecation": {
|
||||||
|
"replacement": "management.opentelemetry.logging.export.timeout",
|
||||||
|
"level": "error"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "management.otlp.logging.transport",
|
||||||
|
"type": "org.springframework.boot.opentelemetry.actuate.autoconfigure.logging.Transport",
|
||||||
|
"description": "Transport used to send the logs.",
|
||||||
|
"sourceType": "org.springframework.boot.opentelemetry.actuate.autoconfigure.logging.OpenTelemetryLoggingExportProperties",
|
||||||
|
"defaultValue": "http",
|
||||||
|
"deprecation": {
|
||||||
|
"replacement": "management.opentelemetry.logging.export.transport",
|
||||||
|
"level": "error"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"hints": []
|
||||||
|
}
|
|
@ -0,0 +1,2 @@
|
||||||
|
org.springframework.boot.opentelemetry.actuate.autoconfigure.logging.OpenTelemetryLoggingExportAutoConfiguration
|
||||||
|
org.springframework.boot.opentelemetry.autoconfigure.OpenTelemetrySdkAutoConfiguration
|
|
@ -14,7 +14,7 @@
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package org.springframework.boot.actuate.autoconfigure.logging.otlp;
|
package org.springframework.boot.opentelemetry.actuate.autoconfigure.logging;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.nio.charset.StandardCharsets;
|
import java.nio.charset.StandardCharsets;
|
||||||
|
@ -32,26 +32,25 @@ import org.junit.jupiter.api.AfterEach;
|
||||||
import org.junit.jupiter.api.BeforeEach;
|
import org.junit.jupiter.api.BeforeEach;
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
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.autoconfigure.AutoConfigurations;
|
||||||
|
import org.springframework.boot.opentelemetry.autoconfigure.OpenTelemetrySdkAutoConfiguration;
|
||||||
import org.springframework.boot.test.context.runner.ApplicationContextRunner;
|
import org.springframework.boot.test.context.runner.ApplicationContextRunner;
|
||||||
import org.springframework.context.ApplicationContext;
|
import org.springframework.context.ApplicationContext;
|
||||||
|
|
||||||
import static org.assertj.core.api.Assertions.assertThat;
|
import static org.assertj.core.api.Assertions.assertThat;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Integration tests for {@link OtlpLoggingAutoConfiguration}.
|
* Integration tests for {@link OpenTelemetryLoggingExportAutoConfiguration}.
|
||||||
*
|
*
|
||||||
* @author Toshiaki Maki
|
* @author Toshiaki Maki
|
||||||
*/
|
*/
|
||||||
class OtlpLoggingAutoConfigurationIntegrationTests {
|
class OpenTelemetryLoggingExportAutoConfigurationIntegrationTests {
|
||||||
|
|
||||||
private final ApplicationContextRunner contextRunner = new ApplicationContextRunner()
|
private final ApplicationContextRunner contextRunner = new ApplicationContextRunner()
|
||||||
.withPropertyValues("spring.application.name=otlp-logs-test",
|
.withPropertyValues("spring.application.name=otlp-logs-test",
|
||||||
"management.otlp.logging.headers.Authorization=Bearer my-token")
|
"management.opentelemetry.logging.export.headers.Authorization=Bearer my-token")
|
||||||
.withConfiguration(AutoConfigurations.of(OpenTelemetryAutoConfiguration.class,
|
.withConfiguration(AutoConfigurations.of(OpenTelemetrySdkAutoConfiguration.class,
|
||||||
OpenTelemetryLoggingAutoConfiguration.class, OtlpLoggingAutoConfiguration.class));
|
OpenTelemetryLoggingExportAutoConfiguration.class));
|
||||||
|
|
||||||
private final MockWebServer mockWebServer = new MockWebServer();
|
private final MockWebServer mockWebServer = new MockWebServer();
|
||||||
|
|
||||||
|
@ -69,7 +68,7 @@ class OtlpLoggingAutoConfigurationIntegrationTests {
|
||||||
void httpLogRecordExporterShouldUseProtobufAndNoCompressionByDefault() {
|
void httpLogRecordExporterShouldUseProtobufAndNoCompressionByDefault() {
|
||||||
this.mockWebServer.enqueue(new MockResponse());
|
this.mockWebServer.enqueue(new MockResponse());
|
||||||
this.contextRunner
|
this.contextRunner
|
||||||
.withPropertyValues("management.otlp.logging.endpoint=http://localhost:%d/v1/logs"
|
.withPropertyValues("management.opentelemetry.logging.export.endpoint=http://localhost:%d/v1/logs"
|
||||||
.formatted(this.mockWebServer.getPort()))
|
.formatted(this.mockWebServer.getPort()))
|
||||||
.run((context) -> {
|
.run((context) -> {
|
||||||
logMessage(context);
|
logMessage(context);
|
||||||
|
@ -89,8 +88,8 @@ class OtlpLoggingAutoConfigurationIntegrationTests {
|
||||||
void httpLogRecordExporterCanBeConfiguredToUseGzipCompression() {
|
void httpLogRecordExporterCanBeConfiguredToUseGzipCompression() {
|
||||||
this.mockWebServer.enqueue(new MockResponse());
|
this.mockWebServer.enqueue(new MockResponse());
|
||||||
this.contextRunner
|
this.contextRunner
|
||||||
.withPropertyValues("management.otlp.logging.endpoint=http://localhost:%d/v1/logs"
|
.withPropertyValues("management.opentelemetry.logging.export.endpoint=http://localhost:%d/v1/logs"
|
||||||
.formatted(this.mockWebServer.getPort()), "management.otlp.logging.compression=gzip")
|
.formatted(this.mockWebServer.getPort()), "management.opentelemetry.logging.export.compression=gzip")
|
||||||
.run((context) -> {
|
.run((context) -> {
|
||||||
logMessage(context);
|
logMessage(context);
|
||||||
RecordedRequest request = this.mockWebServer.takeRequest(10, TimeUnit.SECONDS);
|
RecordedRequest request = this.mockWebServer.takeRequest(10, TimeUnit.SECONDS);
|
|
@ -14,13 +14,15 @@
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package org.springframework.boot.actuate.autoconfigure.logging.otlp;
|
package org.springframework.boot.opentelemetry.actuate.autoconfigure.logging;
|
||||||
|
|
||||||
|
import java.util.concurrent.atomic.AtomicInteger;
|
||||||
import java.util.function.Supplier;
|
import java.util.function.Supplier;
|
||||||
|
|
||||||
import io.opentelemetry.api.metrics.MeterProvider;
|
import io.opentelemetry.api.metrics.MeterProvider;
|
||||||
import io.opentelemetry.exporter.otlp.http.logs.OtlpHttpLogRecordExporter;
|
import io.opentelemetry.exporter.otlp.http.logs.OtlpHttpLogRecordExporter;
|
||||||
import io.opentelemetry.exporter.otlp.logs.OtlpGrpcLogRecordExporter;
|
import io.opentelemetry.exporter.otlp.logs.OtlpGrpcLogRecordExporter;
|
||||||
|
import io.opentelemetry.sdk.logs.SdkLoggerProviderBuilder;
|
||||||
import io.opentelemetry.sdk.logs.export.LogRecordExporter;
|
import io.opentelemetry.sdk.logs.export.LogRecordExporter;
|
||||||
import okhttp3.HttpUrl;
|
import okhttp3.HttpUrl;
|
||||||
import org.assertj.core.api.InstanceOfAssertFactories;
|
import org.assertj.core.api.InstanceOfAssertFactories;
|
||||||
|
@ -28,8 +30,12 @@ import org.junit.jupiter.api.Test;
|
||||||
import org.junit.jupiter.params.ParameterizedTest;
|
import org.junit.jupiter.params.ParameterizedTest;
|
||||||
import org.junit.jupiter.params.provider.ValueSource;
|
import org.junit.jupiter.params.provider.ValueSource;
|
||||||
|
|
||||||
import org.springframework.boot.actuate.autoconfigure.logging.otlp.OtlpLoggingConfigurations.ConnectionDetails.PropertiesOtlpLoggingConnectionDetails;
|
import org.springframework.boot.autoconfigure.AutoConfiguration;
|
||||||
import org.springframework.boot.autoconfigure.AutoConfigurations;
|
import org.springframework.boot.autoconfigure.AutoConfigurations;
|
||||||
|
import org.springframework.boot.context.annotation.ImportCandidates;
|
||||||
|
import org.springframework.boot.opentelemetry.actuate.autoconfigure.logging.OpenTelemetryLoggingConnectionDetailsConfiguration.PropertiesOpenTelemetryLoggingConnectionDetails;
|
||||||
|
import org.springframework.boot.opentelemetry.autoconfigure.OpenTelemetrySdkAutoConfiguration;
|
||||||
|
import org.springframework.boot.opentelemetry.autoconfigure.SdkLoggerProviderBuilderCustomizer;
|
||||||
import org.springframework.boot.test.context.FilteredClassLoader;
|
import org.springframework.boot.test.context.FilteredClassLoader;
|
||||||
import org.springframework.boot.test.context.runner.ApplicationContextRunner;
|
import org.springframework.boot.test.context.runner.ApplicationContextRunner;
|
||||||
import org.springframework.context.annotation.Bean;
|
import org.springframework.context.annotation.Bean;
|
||||||
|
@ -38,87 +44,101 @@ import org.springframework.context.annotation.Configuration;
|
||||||
import static org.assertj.core.api.Assertions.assertThat;
|
import static org.assertj.core.api.Assertions.assertThat;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Tests for {@link OtlpLoggingAutoConfiguration}.
|
* Tests for {@link OpenTelemetryLoggingExportAutoConfiguration}.
|
||||||
*
|
*
|
||||||
* @author Toshiaki Maki
|
* @author Toshiaki Maki
|
||||||
* @author Moritz Halbritter
|
* @author Moritz Halbritter
|
||||||
*/
|
*/
|
||||||
class OtlpLoggingAutoConfigurationTests {
|
class OpenTelemetryLoggingExportAutoConfigurationTests {
|
||||||
|
|
||||||
private final ApplicationContextRunner contextRunner = new ApplicationContextRunner()
|
private final ApplicationContextRunner contextRunner;
|
||||||
.withConfiguration(AutoConfigurations.of(OtlpLoggingAutoConfiguration.class));
|
|
||||||
|
|
||||||
@Test
|
OpenTelemetryLoggingExportAutoConfigurationTests() {
|
||||||
void shouldNotSupplyBeansIfPropertyIsNotSet() {
|
this.contextRunner = new ApplicationContextRunner().withConfiguration(AutoConfigurations
|
||||||
this.contextRunner.run((context) -> {
|
.of(OpenTelemetrySdkAutoConfiguration.class, OpenTelemetryLoggingExportAutoConfiguration.class));
|
||||||
assertThat(context).doesNotHaveBean(OtlpLoggingConnectionDetails.class);
|
|
||||||
assertThat(context).doesNotHaveBean(OtlpHttpLogRecordExporter.class);
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void shouldSupplyBeans() {
|
void registeredInAutoConfigurationImports() {
|
||||||
this.contextRunner.withPropertyValues("management.otlp.logging.endpoint=http://localhost:4318/v1/logs")
|
assertThat(ImportCandidates.load(AutoConfiguration.class, null).getCandidates())
|
||||||
.run((context) -> {
|
.contains(OpenTelemetryLoggingExportAutoConfiguration.class.getName());
|
||||||
assertThat(context).hasSingleBean(OtlpLoggingConnectionDetails.class);
|
|
||||||
OtlpLoggingConnectionDetails connectionDetails = context.getBean(OtlpLoggingConnectionDetails.class);
|
|
||||||
assertThat(connectionDetails.getUrl(Transport.HTTP)).isEqualTo("http://localhost:4318/v1/logs");
|
|
||||||
assertThat(context).hasSingleBean(OtlpHttpLogRecordExporter.class)
|
|
||||||
.hasSingleBean(LogRecordExporter.class);
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@ParameterizedTest
|
@ParameterizedTest
|
||||||
@ValueSource(strings = { "io.opentelemetry.sdk.logs", "io.opentelemetry.api",
|
@ValueSource(strings = { "io.opentelemetry.sdk.logs", "io.opentelemetry.api",
|
||||||
"io.opentelemetry.exporter.otlp.http.logs" })
|
"io.opentelemetry.exporter.otlp.http.logs" })
|
||||||
void shouldNotSupplyBeansIfDependencyIsMissing(String packageName) {
|
void whenOpenTelemetryIsNotOnClasspathDoesNotProvideBeans(String packageName) {
|
||||||
this.contextRunner.withClassLoader(new FilteredClassLoader(packageName)).run((context) -> {
|
this.contextRunner.withClassLoader(new FilteredClassLoader(packageName)).run((context) -> {
|
||||||
assertThat(context).doesNotHaveBean(OtlpLoggingConnectionDetails.class);
|
assertThat(context).doesNotHaveBean(OpenTelemetryLoggingConnectionDetails.class);
|
||||||
assertThat(context).doesNotHaveBean(OtlpHttpLogRecordExporter.class);
|
assertThat(context).doesNotHaveBean(OtlpHttpLogRecordExporter.class);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void shouldBackOffWhenLoggingExportPropertyIsNotEnabled() {
|
void whenHasEndpointPropertyProvidesBeans() {
|
||||||
|
this.contextRunner
|
||||||
|
.withPropertyValues("management.opentelemetry.logging.export.endpoint=http://localhost:4318/v1/logs")
|
||||||
|
.run((context) -> {
|
||||||
|
assertThat(context).hasSingleBean(OpenTelemetryLoggingConnectionDetails.class);
|
||||||
|
OpenTelemetryLoggingConnectionDetails connectionDetails = context
|
||||||
|
.getBean(OpenTelemetryLoggingConnectionDetails.class);
|
||||||
|
assertThat(connectionDetails.getUrl(Transport.HTTP)).isEqualTo("http://localhost:4318/v1/logs");
|
||||||
|
assertThat(context).hasSingleBean(OtlpHttpLogRecordExporter.class);
|
||||||
|
assertThat(context).hasSingleBean(LogRecordExporter.class);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void whenHasNoEndpointPropertyDoesNotProvideBeans() {
|
||||||
|
this.contextRunner.run((context) -> {
|
||||||
|
assertThat(context).doesNotHaveBean(OpenTelemetryLoggingConnectionDetails.class);
|
||||||
|
assertThat(context).doesNotHaveBean(OtlpHttpLogRecordExporter.class);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void whenOpenTelemetryLoggingExportEnabledPropertyIsFalseProvidesExpectedBeans() {
|
||||||
|
this.contextRunner
|
||||||
|
.withPropertyValues("management.opentelemetry.logging.export.enabled=false",
|
||||||
|
"management.opentelemetry.logging.export.endpoint=http://localhost:4318/v1/logs")
|
||||||
|
.run((context) -> {
|
||||||
|
assertThat(context).doesNotHaveBean(OpenTelemetryLoggingConnectionDetails.class);
|
||||||
|
assertThat(context).doesNotHaveBean(LogRecordExporter.class);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void whenLoggingExportEnabledPropertyIsFalseNoProvideExpectedBeans() {
|
||||||
this.contextRunner
|
this.contextRunner
|
||||||
.withPropertyValues("management.logging.export.enabled=false",
|
.withPropertyValues("management.logging.export.enabled=false",
|
||||||
"management.otlp.logging.endpoint=http://localhost:4318/v1/logs")
|
"management.opentelemetry.logging.export.endpoint=http://localhost:4318/v1/logs")
|
||||||
.run((context) -> {
|
.run((context) -> {
|
||||||
assertThat(context).hasSingleBean(OtlpLoggingConnectionDetails.class);
|
assertThat(context).doesNotHaveBean(OpenTelemetryLoggingConnectionDetails.class);
|
||||||
assertThat(context).doesNotHaveBean(LogRecordExporter.class);
|
assertThat(context).doesNotHaveBean(LogRecordExporter.class);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void shouldBackOffWhenOtlpLoggingExportPropertyIsNotEnabled() {
|
void whenHasCustomHttpExporterDoesNotProvideExporterBean() {
|
||||||
this.contextRunner
|
|
||||||
.withPropertyValues("management.otlp.logging.export.enabled=false",
|
|
||||||
"management.otlp.logging.endpoint=http://localhost:4318/v1/logs")
|
|
||||||
.run((context) -> {
|
|
||||||
assertThat(context).hasSingleBean(OtlpLoggingConnectionDetails.class);
|
|
||||||
assertThat(context).doesNotHaveBean(LogRecordExporter.class);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
void shouldBackOffWhenCustomHttpExporterIsDefined() {
|
|
||||||
this.contextRunner.withUserConfiguration(CustomHttpExporterConfiguration.class)
|
this.contextRunner.withUserConfiguration(CustomHttpExporterConfiguration.class)
|
||||||
.run((context) -> assertThat(context).hasBean("customOtlpHttpLogRecordExporter")
|
.run((context) -> assertThat(context).hasBean("customOtlpHttpLogRecordExporter")
|
||||||
.hasSingleBean(LogRecordExporter.class));
|
.hasSingleBean(LogRecordExporter.class));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void shouldBackOffWhenCustomGrpcExporterIsDefined() {
|
void whenHasCustomGrpcExporterDoesNotProvideExporterBean() {
|
||||||
this.contextRunner.withUserConfiguration(CustomGrpcExporterConfiguration.class)
|
this.contextRunner.withUserConfiguration(CustomGrpcExporterConfiguration.class)
|
||||||
.run((context) -> assertThat(context).hasBean("customOtlpGrpcLogRecordExporter")
|
.run((context) -> assertThat(context).hasBean("customOtlpGrpcLogRecordExporter")
|
||||||
.hasSingleBean(LogRecordExporter.class));
|
.hasSingleBean(LogRecordExporter.class));
|
||||||
}
|
}
|
||||||
|
// FIXME
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void shouldBackOffWhenCustomOtlpLoggingConnectionDetailsIsDefined() {
|
void whenHasCustomLoggingConnectionDetailsDoesNotProvideExporterBean() {
|
||||||
this.contextRunner.withUserConfiguration(CustomOtlpLoggingConnectionDetails.class).run((context) -> {
|
this.contextRunner.withUserConfiguration(CustomOtlpLoggingConnectionDetailsConfiguration.class)
|
||||||
assertThat(context).hasSingleBean(OtlpLoggingConnectionDetails.class)
|
.run((context) -> {
|
||||||
.doesNotHaveBean(PropertiesOtlpLoggingConnectionDetails.class);
|
assertThat(context).hasSingleBean(OpenTelemetryLoggingConnectionDetails.class)
|
||||||
|
.doesNotHaveBean(PropertiesOpenTelemetryLoggingConnectionDetails.class);
|
||||||
OtlpHttpLogRecordExporter otlpHttpLogRecordExporter = context.getBean(OtlpHttpLogRecordExporter.class);
|
OtlpHttpLogRecordExporter otlpHttpLogRecordExporter = context.getBean(OtlpHttpLogRecordExporter.class);
|
||||||
assertThat(otlpHttpLogRecordExporter).extracting("delegate.httpSender.url")
|
assertThat(otlpHttpLogRecordExporter).extracting("delegate.httpSender.url")
|
||||||
.isEqualTo(HttpUrl.get("https://otel.example.com/v1/logs"));
|
.isEqualTo(HttpUrl.get("https://otel.example.com/v1/logs"));
|
||||||
|
@ -126,43 +146,44 @@ class OtlpLoggingAutoConfigurationTests {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void shouldUseHttpExporterIfTransportIsNotSet() {
|
void whenHasNoTransportPropertySetUsesHttpExporter() {
|
||||||
this.contextRunner.withPropertyValues("management.otlp.logging.endpoint=http://localhost:4318/v1/logs")
|
this.contextRunner
|
||||||
|
.withPropertyValues("management.opentelemetry.logging.export.endpoint=http://localhost:4318/v1/logs")
|
||||||
.run((context) -> {
|
.run((context) -> {
|
||||||
assertThat(context).hasSingleBean(OtlpHttpLogRecordExporter.class)
|
assertThat(context).hasSingleBean(OtlpHttpLogRecordExporter.class);
|
||||||
.hasSingleBean(LogRecordExporter.class);
|
assertThat(context).hasSingleBean(LogRecordExporter.class);
|
||||||
assertThat(context).doesNotHaveBean(OtlpGrpcLogRecordExporter.class);
|
assertThat(context).doesNotHaveBean(OtlpGrpcLogRecordExporter.class);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void shouldUseHttpExporterIfTransportIsSetToHttp() {
|
void whenHasTransportPropertySetToHttpUsesHttpExporter() {
|
||||||
this.contextRunner
|
this.contextRunner
|
||||||
.withPropertyValues("management.otlp.logging.endpoint=http://localhost:4318/v1/logs",
|
.withPropertyValues("management.opentelemetry.logging.export.endpoint=http://localhost:4318/v1/logs",
|
||||||
"management.otlp.logging.transport=http")
|
"management.opentelemetry.logging.export.transport=http")
|
||||||
.run((context) -> {
|
.run((context) -> {
|
||||||
assertThat(context).hasSingleBean(OtlpHttpLogRecordExporter.class)
|
assertThat(context).hasSingleBean(OtlpHttpLogRecordExporter.class);
|
||||||
.hasSingleBean(LogRecordExporter.class);
|
assertThat(context).hasSingleBean(LogRecordExporter.class);
|
||||||
assertThat(context).doesNotHaveBean(OtlpGrpcLogRecordExporter.class);
|
assertThat(context).doesNotHaveBean(OtlpGrpcLogRecordExporter.class);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void shouldUseGrpcExporterIfTransportIsSetToGrpc() {
|
void whenHasTransportPropertySetToGrpcUsesGrpcExporter() {
|
||||||
this.contextRunner
|
this.contextRunner
|
||||||
.withPropertyValues("management.otlp.logging.endpoint=http://localhost:4318/v1/logs",
|
.withPropertyValues("management.opentelemetry.logging.export.endpoint=http://localhost:4318/v1/logs",
|
||||||
"management.otlp.logging.transport=grpc")
|
"management.opentelemetry.logging.export.transport=grpc")
|
||||||
.run((context) -> {
|
.run((context) -> {
|
||||||
assertThat(context).hasSingleBean(OtlpGrpcLogRecordExporter.class)
|
assertThat(context).hasSingleBean(OtlpGrpcLogRecordExporter.class);
|
||||||
.hasSingleBean(LogRecordExporter.class);
|
assertThat(context).hasSingleBean(LogRecordExporter.class);
|
||||||
assertThat(context).doesNotHaveBean(OtlpHttpLogRecordExporter.class);
|
assertThat(context).doesNotHaveBean(OtlpHttpLogRecordExporter.class);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void httpShouldUseMeterProviderIfSet() {
|
void whenHasMeterProviderBeanAddsItToHttpExporter() {
|
||||||
this.contextRunner.withUserConfiguration(MeterProviderConfiguration.class)
|
this.contextRunner.withUserConfiguration(MeterProviderConfiguration.class)
|
||||||
.withPropertyValues("management.otlp.logging.endpoint=http://localhost:4318/v1/logs")
|
.withPropertyValues("management.opentelemetry.logging.export.endpoint=http://localhost:4318/v1/logs")
|
||||||
.run((context) -> {
|
.run((context) -> {
|
||||||
OtlpHttpLogRecordExporter otlpHttpLogRecordExporter = context.getBean(OtlpHttpLogRecordExporter.class);
|
OtlpHttpLogRecordExporter otlpHttpLogRecordExporter = context.getBean(OtlpHttpLogRecordExporter.class);
|
||||||
assertThat(otlpHttpLogRecordExporter.toBuilder())
|
assertThat(otlpHttpLogRecordExporter.toBuilder())
|
||||||
|
@ -173,10 +194,10 @@ class OtlpLoggingAutoConfigurationTests {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void grpcShouldUseMeterProviderIfSet() {
|
void whenHasMeterProviderBeanAddsItToGrpcExporter() {
|
||||||
this.contextRunner.withUserConfiguration(MeterProviderConfiguration.class)
|
this.contextRunner.withUserConfiguration(MeterProviderConfiguration.class)
|
||||||
.withPropertyValues("management.otlp.logging.endpoint=http://localhost:4318/v1/logs",
|
.withPropertyValues("management.opentelemetry.logging.export.endpoint=http://localhost:4318/v1/logs",
|
||||||
"management.otlp.logging.transport=grpc")
|
"management.opentelemetry.logging.export.transport=grpc")
|
||||||
.run((context) -> {
|
.run((context) -> {
|
||||||
OtlpGrpcLogRecordExporter otlpGrpcLogRecordExporter = context.getBean(OtlpGrpcLogRecordExporter.class);
|
OtlpGrpcLogRecordExporter otlpGrpcLogRecordExporter = context.getBean(OtlpGrpcLogRecordExporter.class);
|
||||||
assertThat(otlpGrpcLogRecordExporter.toBuilder())
|
assertThat(otlpGrpcLogRecordExporter.toBuilder())
|
||||||
|
@ -186,6 +207,36 @@ class OtlpLoggingAutoConfigurationTests {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Configuration(proxyBeanMethods = false)
|
||||||
|
public static class MultipleSdkLoggerProviderBuilderCustomizersConfig {
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
public SdkLoggerProviderBuilderCustomizer customSdkLoggerProviderBuilderCustomizer1() {
|
||||||
|
return new NoopSdkLoggerProviderBuilderCustomizer();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
public SdkLoggerProviderBuilderCustomizer customSdkLoggerProviderBuilderCustomizer2() {
|
||||||
|
return new NoopSdkLoggerProviderBuilderCustomizer();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
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();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
@Configuration(proxyBeanMethods = false)
|
@Configuration(proxyBeanMethods = false)
|
||||||
private static final class MeterProviderConfiguration {
|
private static final class MeterProviderConfiguration {
|
||||||
|
|
||||||
|
@ -219,10 +270,10 @@ class OtlpLoggingAutoConfigurationTests {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Configuration(proxyBeanMethods = false)
|
@Configuration(proxyBeanMethods = false)
|
||||||
private static final class CustomOtlpLoggingConnectionDetails {
|
private static final class CustomOtlpLoggingConnectionDetailsConfiguration {
|
||||||
|
|
||||||
@Bean
|
@Bean
|
||||||
OtlpLoggingConnectionDetails customOtlpLoggingConnectionDetails() {
|
OpenTelemetryLoggingConnectionDetails customOtlpLoggingConnectionDetails() {
|
||||||
return (transport) -> "https://otel.example.com/v1/logs";
|
return (transport) -> "https://otel.example.com/v1/logs";
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,7 +14,7 @@
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package org.springframework.boot.actuate.autoconfigure.opentelemetry;
|
package org.springframework.boot.opentelemetry.autoconfigure;
|
||||||
|
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
|
@ -14,7 +14,7 @@
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package org.springframework.boot.actuate.autoconfigure.opentelemetry;
|
package org.springframework.boot.opentelemetry.autoconfigure;
|
||||||
|
|
||||||
import java.util.LinkedHashMap;
|
import java.util.LinkedHashMap;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
@ -99,7 +99,7 @@ class OpenTelemetryResourceAttributesTests {
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
void systemGetEnvShouldBeUsedAsDefaultEnvFunction() {
|
void systemGetEnvShouldBeUsedAsDefaultEnvFunction() {
|
||||||
OpenTelemetryResourceAttributes attributes = new OpenTelemetryResourceAttributes(this.environment, null);
|
OpenTelemetryResourceAttributes attributes = new OpenTelemetryResourceAttributes(this.environment, null);
|
||||||
Function<String, String> getEnv = assertThat(attributes).extracting("getEnv")
|
Function<String, String> getEnv = assertThat(attributes).extracting("systemEnvironment")
|
||||||
.asInstanceOf(InstanceOfAssertFactories.type(Function.class))
|
.asInstanceOf(InstanceOfAssertFactories.type(Function.class))
|
||||||
.actual();
|
.actual();
|
||||||
System.getenv().forEach((key, value) -> assertThat(getEnv.apply(key)).isEqualTo(value));
|
System.getenv().forEach((key, value) -> assertThat(getEnv.apply(key)).isEqualTo(value));
|
|
@ -0,0 +1,364 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2012-present 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.opentelemetry.autoconfigure;
|
||||||
|
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.concurrent.atomic.AtomicInteger;
|
||||||
|
|
||||||
|
import io.opentelemetry.api.OpenTelemetry;
|
||||||
|
import io.opentelemetry.api.common.AttributeKey;
|
||||||
|
import io.opentelemetry.context.Context;
|
||||||
|
import io.opentelemetry.context.propagation.ContextPropagators;
|
||||||
|
import io.opentelemetry.sdk.OpenTelemetrySdk;
|
||||||
|
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 io.opentelemetry.sdk.metrics.SdkMeterProvider;
|
||||||
|
import io.opentelemetry.sdk.resources.Resource;
|
||||||
|
import io.opentelemetry.sdk.trace.SdkTracerProvider;
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
import org.junit.jupiter.params.ParameterizedTest;
|
||||||
|
import org.junit.jupiter.params.provider.ValueSource;
|
||||||
|
|
||||||
|
import org.springframework.boot.autoconfigure.AutoConfiguration;
|
||||||
|
import org.springframework.boot.autoconfigure.AutoConfigurations;
|
||||||
|
import org.springframework.boot.context.annotation.ImportCandidates;
|
||||||
|
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;
|
||||||
|
import static org.assertj.core.api.Assertions.entry;
|
||||||
|
import static org.mockito.Mockito.mock;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tests for {@link OpenTelemetrySdkAutoConfiguration}.
|
||||||
|
*
|
||||||
|
* @author Moritz Halbritter
|
||||||
|
* @author Toshiaki Maki
|
||||||
|
* @author Phillip Webb
|
||||||
|
*/
|
||||||
|
class OpenTelemetrySdkAutoConfigurationTests {
|
||||||
|
|
||||||
|
private final ApplicationContextRunner contextRunner = new ApplicationContextRunner()
|
||||||
|
.withConfiguration(AutoConfigurations.of(OpenTelemetrySdkAutoConfiguration.class));
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void registeredInAutoConfigurationImports() {
|
||||||
|
assertThat(ImportCandidates.load(AutoConfiguration.class, null).getCandidates())
|
||||||
|
.contains(OpenTelemetrySdkAutoConfiguration.class.getName());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void providesBeans() {
|
||||||
|
this.contextRunner.run((context) -> {
|
||||||
|
assertThat(context).hasSingleBean(OpenTelemetrySdk.class);
|
||||||
|
assertThat(context).hasSingleBean(Resource.class);
|
||||||
|
assertThat(context).hasSingleBean(BatchLogRecordProcessor.class);
|
||||||
|
assertThat(context).hasSingleBean(SdkLoggerProvider.class);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@ParameterizedTest
|
||||||
|
@ValueSource(strings = { "io.opentelemetry", "io.opentelemetry.api" })
|
||||||
|
void whenOpenTelemetryIsNotOnClasspathDoesNotProvideBeans(String packageName) {
|
||||||
|
this.contextRunner.withClassLoader(new FilteredClassLoader(packageName)).run((context) -> {
|
||||||
|
assertThat(context).doesNotHaveBean(OpenTelemetrySdk.class);
|
||||||
|
assertThat(context).doesNotHaveBean(Resource.class);
|
||||||
|
assertThat(context).doesNotHaveBean(BatchLogRecordProcessor.class);
|
||||||
|
assertThat(context).doesNotHaveBean(SdkLoggerProvider.class);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void whenOpenTelemetryLogsIsNotOnClasspathDoesNotProvideBeans() {
|
||||||
|
this.contextRunner.withClassLoader(new FilteredClassLoader("io.opentelemetry.sdk.logs")).run((context) -> {
|
||||||
|
assertThat(context).hasSingleBean(OpenTelemetrySdk.class);
|
||||||
|
assertThat(context).hasSingleBean(Resource.class);
|
||||||
|
assertThat(context).doesNotHaveBean(BatchLogRecordProcessor.class);
|
||||||
|
assertThat(context).doesNotHaveBean(SdkLoggerProvider.class);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void whenHasUserSuppliedBeansDoesNotProvideBeans() {
|
||||||
|
this.contextRunner.withUserConfiguration(UserConfiguration.class).run((context) -> {
|
||||||
|
assertThat(context).hasSingleBean(OpenTelemetry.class);
|
||||||
|
assertThat(context).hasBean("customOpenTelemetry");
|
||||||
|
assertThat(context).hasSingleBean(Resource.class);
|
||||||
|
assertThat(context).hasBean("customResource");
|
||||||
|
assertThat(context).hasSingleBean(BatchLogRecordProcessor.class);
|
||||||
|
assertThat(context).hasBean("customBatchLogRecordProcessor").hasSingleBean(BatchLogRecordProcessor.class);
|
||||||
|
assertThat(context).hasSingleBean(LogRecordProcessor.class);
|
||||||
|
assertThat(context).hasBean("customSdkLoggerProvider").hasSingleBean(SdkLoggerProvider.class);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void whenHasApplicationNamePropertyProvidesServiceNameResourceAttribute() {
|
||||||
|
this.contextRunner.withPropertyValues("spring.application.name=my-application").run((context) -> {
|
||||||
|
Resource resource = context.getBean(Resource.class);
|
||||||
|
assertThat(resource.getAttributes().asMap())
|
||||||
|
.contains(entry(AttributeKey.stringKey("service.name"), "my-application"));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void whenHasApplicationGroupPropertyProvidesServiceGroupResourceAttribute() {
|
||||||
|
this.contextRunner.withPropertyValues("spring.application.group=my-group").run((context) -> {
|
||||||
|
Resource resource = context.getBean(Resource.class);
|
||||||
|
assertThat(resource.getAttributes().asMap())
|
||||||
|
.contains(entry(AttributeKey.stringKey("service.group"), "my-group"));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void whenHasApplicationGroupPropertyProvidesServiceNamespaceResourceAttribute() {
|
||||||
|
this.contextRunner.withPropertyValues("spring.application.group=my-group").run((context) -> {
|
||||||
|
Resource resource = context.getBean(Resource.class);
|
||||||
|
assertThat(resource.getAttributes().asMap()).containsEntry(AttributeKey.stringKey("service.namespace"),
|
||||||
|
"my-group");
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void whenHasNoApplicationGroupPropertyProvidesNoServiceGroupResourceAttribute() {
|
||||||
|
this.contextRunner.run((context) -> {
|
||||||
|
Resource resource = context.getBean(Resource.class);
|
||||||
|
assertThat(resource.getAttributes().asMap()).doesNotContainKey(AttributeKey.stringKey("service.group"));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void whenHasNoApplicationGroupPropertyProvidesNoServiceNamespaceResourceAttribute() {
|
||||||
|
this.contextRunner.run(((context) -> {
|
||||||
|
Resource resource = context.getBean(Resource.class);
|
||||||
|
assertThat(resource.getAttributes().asMap()).doesNotContainKey(AttributeKey.stringKey("service.namespace"));
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void whenHasNoApplicationNamePropertyProvidesDefaultApplicationName() {
|
||||||
|
this.contextRunner.run((context) -> {
|
||||||
|
Resource resource = context.getBean(Resource.class);
|
||||||
|
assertThat(resource.getAttributes().asMap())
|
||||||
|
.contains(entry(AttributeKey.stringKey("service.name"), "unknown_service"));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void whenHasResourceAttributesPropertyProvidesResourceAttributes() {
|
||||||
|
this.contextRunner.withPropertyValues("management.opentelemetry.resource-attributes.region=us-west")
|
||||||
|
.run((context) -> {
|
||||||
|
Resource resource = context.getBean(Resource.class);
|
||||||
|
assertThat(resource.getAttributes().asMap())
|
||||||
|
.contains(entry(AttributeKey.stringKey("region"), "us-west"));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void whenHasSdkTracerProviderBeanProvidesTracerProvider() {
|
||||||
|
this.contextRunner.withBean(SdkTracerProvider.class, () -> SdkTracerProvider.builder().build())
|
||||||
|
.run((context) -> {
|
||||||
|
OpenTelemetry openTelemetry = context.getBean(OpenTelemetry.class);
|
||||||
|
assertThat(openTelemetry.getTracerProvider()).isNotNull();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void whenHasContextPropagatorsBeanProvidesPropagators() {
|
||||||
|
this.contextRunner.withBean(ContextPropagators.class, ContextPropagators::noop).run((context) -> {
|
||||||
|
OpenTelemetry openTelemetry = context.getBean(OpenTelemetry.class);
|
||||||
|
assertThat(openTelemetry.getPropagators()).isNotNull();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void whenHasSdkLoggerProviderBeanProvidesLogsBridge() {
|
||||||
|
this.contextRunner.withBean(SdkLoggerProvider.class, () -> SdkLoggerProvider.builder().build())
|
||||||
|
.run((context) -> {
|
||||||
|
OpenTelemetry openTelemetry = context.getBean(OpenTelemetry.class);
|
||||||
|
assertThat(openTelemetry.getLogsBridge()).isNotNull();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void whenHasSdkMeterProviderProvidesMeterProvider() {
|
||||||
|
this.contextRunner.withBean(SdkMeterProvider.class, () -> SdkMeterProvider.builder().build()).run((context) -> {
|
||||||
|
OpenTelemetry openTelemetry = context.getBean(OpenTelemetry.class);
|
||||||
|
assertThat(openTelemetry.getMeterProvider()).isNotNull();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void whenHasMultipleLogRecordExportersProvidesBatchLogRecordProcessor() {
|
||||||
|
this.contextRunner.withUserConfiguration(MultipleLogRecordExportersConfiguration.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 whenHasMultipleLogRecordProcessorsStillProvidesBatchLogRecordProcessor() {
|
||||||
|
this.contextRunner.withUserConfiguration(MultipleLogRecordProcessorsConfiguration.class).run((context) -> {
|
||||||
|
assertThat(context).hasSingleBean(BatchLogRecordProcessor.class);
|
||||||
|
assertThat(context).hasSingleBean(SdkLoggerProvider.class);
|
||||||
|
assertThat(context.getBeansOfType(LogRecordProcessor.class)).hasSize(3);
|
||||||
|
assertThat(context).hasBean("openTelemetryBatchLogRecordProcessor");
|
||||||
|
assertThat(context).hasBean("customLogRecordProcessor1");
|
||||||
|
assertThat(context).hasBean("customLogRecordProcessor2");
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void whenHasMultipleSdkLoggerProviderBuilderCustomizersCallsCustomizeMethod() {
|
||||||
|
this.contextRunner.withUserConfiguration(MultipleSdkLoggerProviderBuilderCustomizersConfiguration.class)
|
||||||
|
.run((context) -> {
|
||||||
|
assertThat(context).hasSingleBean(SdkLoggerProvider.class);
|
||||||
|
assertThat(context.getBeansOfType(SdkLoggerProviderBuilderCustomizer.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)
|
||||||
|
static class UserConfiguration {
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
OpenTelemetry customOpenTelemetry() {
|
||||||
|
return mock(OpenTelemetry.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
Resource customResource() {
|
||||||
|
return Resource.getDefault();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
BatchLogRecordProcessor customBatchLogRecordProcessor() {
|
||||||
|
return BatchLogRecordProcessor.builder(new NoopLogRecordExporter()).build();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
SdkLoggerProvider customSdkLoggerProvider() {
|
||||||
|
return SdkLoggerProvider.builder().build();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Configuration(proxyBeanMethods = false)
|
||||||
|
static class MultipleLogRecordExportersConfiguration {
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
LogRecordExporter customLogRecordExporter1() {
|
||||||
|
return new NoopLogRecordExporter();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
LogRecordExporter customLogRecordExporter2() {
|
||||||
|
return new NoopLogRecordExporter();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Configuration(proxyBeanMethods = false)
|
||||||
|
static class MultipleLogRecordProcessorsConfiguration {
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
LogRecordProcessor customLogRecordProcessor1() {
|
||||||
|
return new NoopLogRecordProcessor();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
LogRecordProcessor customLogRecordProcessor2() {
|
||||||
|
return new NoopLogRecordProcessor();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Configuration(proxyBeanMethods = false)
|
||||||
|
static class MultipleSdkLoggerProviderBuilderCustomizersConfiguration {
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
SdkLoggerProviderBuilderCustomizer customSdkLoggerProviderBuilderCustomizer1() {
|
||||||
|
return new NoopSdkLoggerProviderBuilderCustomizer();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
SdkLoggerProviderBuilderCustomizer customSdkLoggerProviderBuilderCustomizer2() {
|
||||||
|
return new NoopSdkLoggerProviderBuilderCustomizer();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
static class NoopLogRecordExporter implements LogRecordExporter {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public CompletableResultCode export(Collection<LogRecordData> 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();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -44,6 +44,7 @@ dependencies {
|
||||||
dockerTestImplementation("org.testcontainers:junit-jupiter")
|
dockerTestImplementation("org.testcontainers:junit-jupiter")
|
||||||
|
|
||||||
optional(project(":spring-boot-project:spring-boot-actuator-autoconfigure-all"))
|
optional(project(":spring-boot-project:spring-boot-actuator-autoconfigure-all"))
|
||||||
|
optional(project(":spring-boot-project:spring-boot-opentelemetry"))
|
||||||
optional(project(":spring-boot-project:spring-boot-tx"))
|
optional(project(":spring-boot-project:spring-boot-tx"))
|
||||||
optional(project(":spring-boot-project:spring-boot-zipkin"))
|
optional(project(":spring-boot-project:spring-boot-zipkin"))
|
||||||
optional("org.springframework:spring-test")
|
optional("org.springframework:spring-test")
|
||||||
|
|
|
@ -22,10 +22,10 @@ import org.testcontainers.junit.jupiter.Container;
|
||||||
import org.testcontainers.junit.jupiter.Testcontainers;
|
import org.testcontainers.junit.jupiter.Testcontainers;
|
||||||
|
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
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.autoconfigure.ImportAutoConfiguration;
|
||||||
|
import org.springframework.boot.opentelemetry.actuate.autoconfigure.logging.OpenTelemetryLoggingConnectionDetails;
|
||||||
|
import org.springframework.boot.opentelemetry.actuate.autoconfigure.logging.OpenTelemetryLoggingExportAutoConfiguration;
|
||||||
|
import org.springframework.boot.opentelemetry.actuate.autoconfigure.logging.Transport;
|
||||||
import org.springframework.boot.testcontainers.service.connection.ServiceConnection;
|
import org.springframework.boot.testcontainers.service.connection.ServiceConnection;
|
||||||
import org.springframework.boot.testsupport.container.TestImage;
|
import org.springframework.boot.testsupport.container.TestImage;
|
||||||
import org.springframework.context.annotation.Configuration;
|
import org.springframework.context.annotation.Configuration;
|
||||||
|
@ -47,7 +47,7 @@ class GrafanaOpenTelemetryLoggingContainerConnectionDetailsFactoryIntegrationTes
|
||||||
static final LgtmStackContainer container = TestImage.container(LgtmStackContainer.class);
|
static final LgtmStackContainer container = TestImage.container(LgtmStackContainer.class);
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
private OtlpLoggingConnectionDetails connectionDetails;
|
private OpenTelemetryLoggingConnectionDetails connectionDetails;
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void connectionCanBeMadeToOpenTelemetryContainer() {
|
void connectionCanBeMadeToOpenTelemetryContainer() {
|
||||||
|
@ -58,7 +58,7 @@ class GrafanaOpenTelemetryLoggingContainerConnectionDetailsFactoryIntegrationTes
|
||||||
}
|
}
|
||||||
|
|
||||||
@Configuration(proxyBeanMethods = false)
|
@Configuration(proxyBeanMethods = false)
|
||||||
@ImportAutoConfiguration(OtlpLoggingAutoConfiguration.class)
|
@ImportAutoConfiguration(OpenTelemetryLoggingExportAutoConfiguration.class)
|
||||||
static class TestConfiguration {
|
static class TestConfiguration {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -22,10 +22,10 @@ import org.testcontainers.junit.jupiter.Container;
|
||||||
import org.testcontainers.junit.jupiter.Testcontainers;
|
import org.testcontainers.junit.jupiter.Testcontainers;
|
||||||
|
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
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.actuate.autoconfigure.tracing.otlp.OtlpTracingAutoConfiguration;
|
||||||
import org.springframework.boot.autoconfigure.ImportAutoConfiguration;
|
import org.springframework.boot.autoconfigure.ImportAutoConfiguration;
|
||||||
|
import org.springframework.boot.opentelemetry.actuate.autoconfigure.logging.OpenTelemetryLoggingConnectionDetails;
|
||||||
|
import org.springframework.boot.opentelemetry.actuate.autoconfigure.logging.Transport;
|
||||||
import org.springframework.boot.testcontainers.service.connection.ServiceConnection;
|
import org.springframework.boot.testcontainers.service.connection.ServiceConnection;
|
||||||
import org.springframework.boot.testsupport.container.TestImage;
|
import org.springframework.boot.testsupport.container.TestImage;
|
||||||
import org.springframework.context.annotation.Configuration;
|
import org.springframework.context.annotation.Configuration;
|
||||||
|
@ -48,7 +48,7 @@ class OpenTelemetryLoggingContainerConnectionDetailsFactoryIntegrationTests {
|
||||||
.withExposedPorts(4317, 4318);
|
.withExposedPorts(4317, 4318);
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
private OtlpLoggingConnectionDetails connectionDetails;
|
private OpenTelemetryLoggingConnectionDetails connectionDetails;
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void connectionCanBeMadeToOpenTelemetryContainer() {
|
void connectionCanBeMadeToOpenTelemetryContainer() {
|
||||||
|
|
|
@ -18,36 +18,36 @@ package org.springframework.boot.testcontainers.service.connection.otlp;
|
||||||
|
|
||||||
import org.testcontainers.grafana.LgtmStackContainer;
|
import org.testcontainers.grafana.LgtmStackContainer;
|
||||||
|
|
||||||
import org.springframework.boot.actuate.autoconfigure.logging.otlp.OtlpLoggingConnectionDetails;
|
import org.springframework.boot.opentelemetry.actuate.autoconfigure.logging.OpenTelemetryLoggingConnectionDetails;
|
||||||
import org.springframework.boot.actuate.autoconfigure.logging.otlp.Transport;
|
import org.springframework.boot.opentelemetry.actuate.autoconfigure.logging.Transport;
|
||||||
import org.springframework.boot.testcontainers.service.connection.ContainerConnectionDetailsFactory;
|
import org.springframework.boot.testcontainers.service.connection.ContainerConnectionDetailsFactory;
|
||||||
import org.springframework.boot.testcontainers.service.connection.ContainerConnectionSource;
|
import org.springframework.boot.testcontainers.service.connection.ContainerConnectionSource;
|
||||||
import org.springframework.boot.testcontainers.service.connection.ServiceConnection;
|
import org.springframework.boot.testcontainers.service.connection.ServiceConnection;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* {@link ContainerConnectionDetailsFactory} to create
|
* {@link ContainerConnectionDetailsFactory} to create
|
||||||
* {@link OtlpLoggingConnectionDetails} from a
|
* {@link OpenTelemetryLoggingConnectionDetails} from a
|
||||||
* {@link ServiceConnection @ServiceConnection}-annotated {@link LgtmStackContainer} using
|
* {@link ServiceConnection @ServiceConnection}-annotated {@link LgtmStackContainer} using
|
||||||
* the {@code "grafana/otel-lgtm"} image.
|
* the {@code "grafana/otel-lgtm"} image.
|
||||||
*
|
*
|
||||||
* @author Eddú Meléndez
|
* @author Eddú Meléndez
|
||||||
*/
|
*/
|
||||||
class GrafanaOpenTelemetryLoggingContainerConnectionDetailsFactory
|
class GrafanaOpenTelemetryLoggingContainerConnectionDetailsFactory
|
||||||
extends ContainerConnectionDetailsFactory<LgtmStackContainer, OtlpLoggingConnectionDetails> {
|
extends ContainerConnectionDetailsFactory<LgtmStackContainer, OpenTelemetryLoggingConnectionDetails> {
|
||||||
|
|
||||||
GrafanaOpenTelemetryLoggingContainerConnectionDetailsFactory() {
|
GrafanaOpenTelemetryLoggingContainerConnectionDetailsFactory() {
|
||||||
super(ANY_CONNECTION_NAME,
|
super(ANY_CONNECTION_NAME,
|
||||||
"org.springframework.boot.actuate.autoconfigure.logging.otlp.OtlpLoggingAutoConfiguration");
|
"org.springframework.boot.opentelemetry.actuate.autoconfigure.logging.OpenTelemetryLoggingExportAutoConfiguration");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected OtlpLoggingConnectionDetails getContainerConnectionDetails(
|
protected OpenTelemetryLoggingConnectionDetails getContainerConnectionDetails(
|
||||||
ContainerConnectionSource<LgtmStackContainer> source) {
|
ContainerConnectionSource<LgtmStackContainer> source) {
|
||||||
return new OpenTelemetryLoggingContainerConnectionDetails(source);
|
return new OpenTelemetryLoggingContainerConnectionDetails(source);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static final class OpenTelemetryLoggingContainerConnectionDetails
|
private static final class OpenTelemetryLoggingContainerConnectionDetails
|
||||||
extends ContainerConnectionDetails<LgtmStackContainer> implements OtlpLoggingConnectionDetails {
|
extends ContainerConnectionDetails<LgtmStackContainer> implements OpenTelemetryLoggingConnectionDetails {
|
||||||
|
|
||||||
private OpenTelemetryLoggingContainerConnectionDetails(ContainerConnectionSource<LgtmStackContainer> source) {
|
private OpenTelemetryLoggingContainerConnectionDetails(ContainerConnectionSource<LgtmStackContainer> source) {
|
||||||
super(source);
|
super(source);
|
||||||
|
|
|
@ -19,15 +19,15 @@ package org.springframework.boot.testcontainers.service.connection.otlp;
|
||||||
import org.testcontainers.containers.Container;
|
import org.testcontainers.containers.Container;
|
||||||
import org.testcontainers.containers.GenericContainer;
|
import org.testcontainers.containers.GenericContainer;
|
||||||
|
|
||||||
import org.springframework.boot.actuate.autoconfigure.logging.otlp.OtlpLoggingConnectionDetails;
|
import org.springframework.boot.opentelemetry.actuate.autoconfigure.logging.OpenTelemetryLoggingConnectionDetails;
|
||||||
import org.springframework.boot.actuate.autoconfigure.logging.otlp.Transport;
|
import org.springframework.boot.opentelemetry.actuate.autoconfigure.logging.Transport;
|
||||||
import org.springframework.boot.testcontainers.service.connection.ContainerConnectionDetailsFactory;
|
import org.springframework.boot.testcontainers.service.connection.ContainerConnectionDetailsFactory;
|
||||||
import org.springframework.boot.testcontainers.service.connection.ContainerConnectionSource;
|
import org.springframework.boot.testcontainers.service.connection.ContainerConnectionSource;
|
||||||
import org.springframework.boot.testcontainers.service.connection.ServiceConnection;
|
import org.springframework.boot.testcontainers.service.connection.ServiceConnection;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* {@link ContainerConnectionDetailsFactory} to create
|
* {@link ContainerConnectionDetailsFactory} to create
|
||||||
* {@link OtlpLoggingConnectionDetails} from a
|
* {@link OpenTelemetryLoggingConnectionDetails} from a
|
||||||
* {@link ServiceConnection @ServiceConnection}-annotated {@link GenericContainer} using
|
* {@link ServiceConnection @ServiceConnection}-annotated {@link GenericContainer} using
|
||||||
* the {@code "otel/opentelemetry-collector-contrib"} image.
|
* the {@code "otel/opentelemetry-collector-contrib"} image.
|
||||||
*
|
*
|
||||||
|
@ -35,7 +35,7 @@ import org.springframework.boot.testcontainers.service.connection.ServiceConnect
|
||||||
* @author Moritz Halbritter
|
* @author Moritz Halbritter
|
||||||
*/
|
*/
|
||||||
class OpenTelemetryLoggingContainerConnectionDetailsFactory
|
class OpenTelemetryLoggingContainerConnectionDetailsFactory
|
||||||
extends ContainerConnectionDetailsFactory<Container<?>, OtlpLoggingConnectionDetails> {
|
extends ContainerConnectionDetailsFactory<Container<?>, OpenTelemetryLoggingConnectionDetails> {
|
||||||
|
|
||||||
private static final int OTLP_GRPC_PORT = 4317;
|
private static final int OTLP_GRPC_PORT = 4317;
|
||||||
|
|
||||||
|
@ -43,17 +43,17 @@ class OpenTelemetryLoggingContainerConnectionDetailsFactory
|
||||||
|
|
||||||
OpenTelemetryLoggingContainerConnectionDetailsFactory() {
|
OpenTelemetryLoggingContainerConnectionDetailsFactory() {
|
||||||
super("otel/opentelemetry-collector-contrib",
|
super("otel/opentelemetry-collector-contrib",
|
||||||
"org.springframework.boot.actuate.autoconfigure.logging.otlp.OtlpLoggingAutoConfiguration");
|
"org.springframework.boot.opentelemetry.actuate.autoconfigure.logging.OpenTelemetryLoggingExportAutoConfiguration");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected OtlpLoggingConnectionDetails getContainerConnectionDetails(
|
protected OpenTelemetryLoggingConnectionDetails getContainerConnectionDetails(
|
||||||
ContainerConnectionSource<Container<?>> source) {
|
ContainerConnectionSource<Container<?>> source) {
|
||||||
return new OpenTelemetryLoggingContainerConnectionDetails(source);
|
return new OpenTelemetryLoggingContainerConnectionDetails(source);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static final class OpenTelemetryLoggingContainerConnectionDetails
|
private static final class OpenTelemetryLoggingContainerConnectionDetails
|
||||||
extends ContainerConnectionDetails<Container<?>> implements OtlpLoggingConnectionDetails {
|
extends ContainerConnectionDetails<Container<?>> implements OpenTelemetryLoggingConnectionDetails {
|
||||||
|
|
||||||
private OpenTelemetryLoggingContainerConnectionDetails(ContainerConnectionSource<Container<?>> source) {
|
private OpenTelemetryLoggingContainerConnectionDetails(ContainerConnectionSource<Container<?>> source) {
|
||||||
super(source);
|
super(source);
|
||||||
|
|
Loading…
Reference in New Issue