Spring use sdk autoconfig (#10453)

This commit is contained in:
Gregor Zeitlinger 2024-03-13 15:41:47 +01:00 committed by GitHub
parent b78316b8d4
commit b7e847c4f1
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
40 changed files with 464 additions and 1591 deletions

View File

@ -7,49 +7,31 @@ package io.opentelemetry.instrumentation.spring.autoconfigure;
import io.opentelemetry.api.OpenTelemetry;
import io.opentelemetry.api.trace.TracerProvider;
import io.opentelemetry.context.propagation.ContextPropagators;
import io.opentelemetry.instrumentation.spring.autoconfigure.exporters.otlp.OtlpExporterProperties;
import io.opentelemetry.instrumentation.spring.autoconfigure.exporters.otlp.OtlpLogRecordExporterAutoConfiguration;
import io.opentelemetry.instrumentation.spring.autoconfigure.exporters.otlp.OtlpMetricExporterAutoConfiguration;
import io.opentelemetry.instrumentation.spring.autoconfigure.exporters.otlp.OtlpSpanExporterAutoConfiguration;
import io.opentelemetry.instrumentation.spring.autoconfigure.internal.MapConverter;
import io.opentelemetry.instrumentation.spring.autoconfigure.propagators.PropagationProperties;
import io.opentelemetry.instrumentation.spring.autoconfigure.resources.OtelResourceAutoConfiguration;
import io.opentelemetry.instrumentation.spring.autoconfigure.resources.OtelResourceProperties;
import io.opentelemetry.instrumentation.spring.autoconfigure.resources.SpringConfigProperties;
import io.opentelemetry.sdk.OpenTelemetrySdk;
import io.opentelemetry.sdk.autoconfigure.spi.ConfigProperties;
import io.opentelemetry.instrumentation.spring.autoconfigure.properties.OtelResourceProperties;
import io.opentelemetry.instrumentation.spring.autoconfigure.properties.OtlpExporterProperties;
import io.opentelemetry.instrumentation.spring.autoconfigure.properties.PropagationProperties;
import io.opentelemetry.instrumentation.spring.autoconfigure.properties.SpringConfigProperties;
import io.opentelemetry.instrumentation.spring.autoconfigure.resources.DistroVersionResourceProvider;
import io.opentelemetry.instrumentation.spring.autoconfigure.resources.SpringResourceProvider;
import io.opentelemetry.sdk.autoconfigure.AutoConfiguredOpenTelemetrySdk;
import io.opentelemetry.sdk.autoconfigure.internal.AutoConfigureUtil;
import io.opentelemetry.sdk.autoconfigure.internal.ComponentLoader;
import io.opentelemetry.sdk.autoconfigure.internal.SpiHelper;
import io.opentelemetry.sdk.autoconfigure.spi.ResourceProvider;
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.SdkMeterProviderBuilder;
import io.opentelemetry.sdk.metrics.export.MetricExporter;
import io.opentelemetry.sdk.metrics.export.PeriodicMetricReader;
import io.opentelemetry.sdk.metrics.export.PeriodicMetricReaderBuilder;
import io.opentelemetry.sdk.resources.Resource;
import io.opentelemetry.sdk.trace.SdkTracerProvider;
import io.opentelemetry.sdk.trace.SdkTracerProviderBuilder;
import io.opentelemetry.sdk.trace.export.BatchSpanProcessor;
import io.opentelemetry.sdk.trace.export.SpanExporter;
import io.opentelemetry.sdk.trace.samplers.Sampler;
import java.time.Duration;
import java.util.Collections;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;
import org.springframework.beans.factory.ObjectProvider;
import org.springframework.boot.autoconfigure.condition.AnyNestedCondition;
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.context.properties.ConfigurationPropertiesBinding;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.boot.info.BuildProperties;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Conditional;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.env.Environment;
import org.springframework.expression.spel.standard.SpelExpressionParser;
/**
* Create {@link io.opentelemetry.api.OpenTelemetry} bean if bean is missing.
@ -60,7 +42,6 @@ import org.springframework.expression.spel.standard.SpelExpressionParser;
*/
@Configuration
@EnableConfigurationProperties({
SamplerProperties.class,
OtlpExporterProperties.class,
OtelResourceProperties.class,
PropagationProperties.class
@ -76,143 +57,54 @@ public class OpenTelemetryAutoConfiguration {
@Bean
@ConfigurationPropertiesBinding
@Conditional(MapConverterCondition.class)
public MapConverter mapConverter() {
// needed for otlp exporter headers and OtelResourceProperties
return new MapConverter();
}
static final class MapConverterCondition extends AnyNestedCondition {
public MapConverterCondition() {
super(ConfigurationPhase.REGISTER_BEAN);
}
@ConditionalOnBean(OtelResourceAutoConfiguration.class)
static class Resource {}
@ConditionalOnBean(OtlpLogRecordExporterAutoConfiguration.class)
static class Logger {}
@ConditionalOnBean(OtlpSpanExporterAutoConfiguration.class)
static class Span {}
@ConditionalOnBean(OtlpMetricExporterAutoConfiguration.class)
static class Metric {}
@Bean
public OpenTelemetrySdkComponentLoader openTelemetrySdkComponentLoader(
ApplicationContext applicationContext) {
return new OpenTelemetrySdkComponentLoader(applicationContext);
}
@Bean
@ConditionalOnMissingBean
ConfigProperties configProperties(
Environment env,
OtlpExporterProperties otlpExporterProperties,
OtelResourceProperties resourceProperties,
PropagationProperties propagationProperties) {
return new SpringConfigProperties(
env,
new SpelExpressionParser(),
otlpExporterProperties,
resourceProperties,
propagationProperties);
}
@Bean(destroyMethod = "") // SDK components are shutdown from the OpenTelemetry instance
@ConditionalOnMissingBean
public SdkTracerProvider sdkTracerProvider(
SamplerProperties samplerProperties,
ObjectProvider<List<SpanExporter>> spanExportersProvider,
Resource otelResource) {
SdkTracerProviderBuilder tracerProviderBuilder = SdkTracerProvider.builder();
spanExportersProvider.getIfAvailable(Collections::emptyList).stream()
.map(spanExporter -> BatchSpanProcessor.builder(spanExporter).build())
.forEach(tracerProviderBuilder::addSpanProcessor);
return tracerProviderBuilder
.setResource(otelResource)
.setSampler(Sampler.traceIdRatioBased(samplerProperties.getProbability()))
.build();
}
@Bean(destroyMethod = "") // SDK components are shutdown from the OpenTelemetry instance
@ConditionalOnMissingBean
public SdkLoggerProvider sdkLoggerProvider(
ObjectProvider<List<LogRecordExporter>> loggerExportersProvider, Resource otelResource) {
SdkLoggerProviderBuilder loggerProviderBuilder = SdkLoggerProvider.builder();
loggerProviderBuilder.setResource(otelResource);
loggerExportersProvider
.getIfAvailable(Collections::emptyList)
.forEach(
loggerExporter ->
loggerProviderBuilder.addLogRecordProcessor(
BatchLogRecordProcessor.builder(loggerExporter).build()));
return loggerProviderBuilder.build();
}
@Bean(destroyMethod = "") // SDK components are shutdown from the OpenTelemetry instance
@ConditionalOnMissingBean
public SdkMeterProvider sdkMeterProvider(
ConfigProperties configProperties,
ObjectProvider<List<MetricExporter>> metricExportersProvider,
Resource otelResource) {
SdkMeterProviderBuilder meterProviderBuilder = SdkMeterProvider.builder();
metricExportersProvider.getIfAvailable(Collections::emptyList).stream()
.map(metricExporter -> createPeriodicMetricReader(configProperties, metricExporter))
.forEach(meterProviderBuilder::registerMetricReader);
return meterProviderBuilder.setResource(otelResource).build();
}
private static PeriodicMetricReader createPeriodicMetricReader(
ConfigProperties properties, MetricExporter metricExporter) {
PeriodicMetricReaderBuilder metricReaderBuilder =
PeriodicMetricReader.builder(metricExporter);
Duration interval = properties.getDuration("otel.metric.export.interval");
if (interval != null) {
metricReaderBuilder.setInterval(interval);
}
return metricReaderBuilder.build();
public ResourceProvider otelSpringResourceProvider(Optional<BuildProperties> buildProperties) {
return new SpringResourceProvider(buildProperties);
}
@Bean
@ConditionalOnMissingBean
public Resource otelResource(
ConfigProperties config, ObjectProvider<List<ResourceProvider>> resourceProviders) {
Resource resource = Resource.getDefault();
for (ResourceProvider resourceProvider :
resourceProviders.getIfAvailable(Collections::emptyList)) {
resource = resource.merge(resourceProvider.createResource(config));
}
return resource;
public ResourceProvider otelDistroVersionResourceProvider() {
return new DistroVersionResourceProvider();
}
@Bean
// If you change the bean name, also change it in the OpenTelemetryJdbcDriverAutoConfiguration
// class
public OpenTelemetry openTelemetry(
ObjectProvider<ContextPropagators> propagatorsProvider,
SdkTracerProvider tracerProvider,
SdkMeterProvider meterProvider,
SdkLoggerProvider loggerProvider,
ObjectProvider<List<OpenTelemetryInjector>> openTelemetryConsumerProvider) {
Environment env,
OtlpExporterProperties otlpExporterProperties,
OtelResourceProperties resourceProperties,
PropagationProperties propagationProperties,
OpenTelemetrySdkComponentLoader componentLoader,
ObjectProvider<OpenTelemetryInjector> openTelemetryConsumerProvider) {
ContextPropagators propagators = propagatorsProvider.getIfAvailable(ContextPropagators::noop);
OpenTelemetry openTelemetry =
AutoConfigureUtil.setComponentLoader(
AutoConfigureUtil.setConfigPropertiesCustomizer(
AutoConfiguredOpenTelemetrySdk.builder(),
c ->
SpringConfigProperties.create(
env,
otlpExporterProperties,
resourceProperties,
propagationProperties,
c)),
componentLoader)
.build()
.getOpenTelemetrySdk();
OpenTelemetrySdk openTelemetry =
OpenTelemetrySdk.builder()
.setTracerProvider(tracerProvider)
.setMeterProvider(meterProvider)
.setLoggerProvider(loggerProvider)
.setPropagators(propagators)
.build();
List<OpenTelemetryInjector> openTelemetryInjectors =
openTelemetryConsumerProvider.getIfAvailable(() -> Collections.emptyList());
openTelemetryInjectors.forEach(consumer -> consumer.accept(openTelemetry));
openTelemetryConsumerProvider.forEach(consumer -> consumer.accept(openTelemetry));
return openTelemetry;
}
@ -228,4 +120,29 @@ public class OpenTelemetryAutoConfiguration {
return OpenTelemetry.noop();
}
}
/**
* The {@link ComponentLoader} is used by the SDK autoconfiguration to load all components, e.g.
* <a
* href="https://github.com/open-telemetry/opentelemetry-java/blob/4519a7e90243e5b75b3a46a14c872de88b95a9a1/sdk-extensions/autoconfigure/src/main/java/io/opentelemetry/sdk/autoconfigure/AutoConfiguredOpenTelemetrySdkBuilder.java#L405-L408">here</a>
*/
public static class OpenTelemetrySdkComponentLoader implements ComponentLoader {
private final ApplicationContext applicationContext;
private final SpiHelper spiHelper =
SpiHelper.create(OpenTelemetrySdkComponentLoader.class.getClassLoader());
public OpenTelemetrySdkComponentLoader(ApplicationContext applicationContext) {
this.applicationContext = applicationContext;
}
@Override
public <T> Iterable<T> load(Class<T> spiClass) {
List<T> spi = spiHelper.load(spiClass);
List<T> beans =
applicationContext.getBeanProvider(spiClass).orderedStream().collect(Collectors.toList());
spi.addAll(beans);
return spi;
}
}
}

View File

@ -1,33 +0,0 @@
/*
* Copyright The OpenTelemetry Authors
* SPDX-License-Identifier: Apache-2.0
*/
package io.opentelemetry.instrumentation.spring.autoconfigure;
import javax.validation.constraints.DecimalMax;
import javax.validation.constraints.DecimalMin;
import org.springframework.boot.context.properties.ConfigurationProperties;
/**
* Configuration for OpenTelemetry Sampler.
*
* <p>Get Sampling Probability
*/
@ConfigurationProperties(prefix = "otel.traces.sampler")
public final class SamplerProperties {
// if Sample probability == 1: always sample
// if Sample probability == 0: never sample
@DecimalMin("0.0")
@DecimalMax("1.0")
private double probability = 1.0;
public double getProbability() {
return probability;
}
public void setProbability(double probability) {
this.probability = probability;
}
}

View File

@ -1,32 +0,0 @@
/*
* Copyright The OpenTelemetry Authors
* SPDX-License-Identifier: Apache-2.0
*/
package io.opentelemetry.instrumentation.spring.autoconfigure.exporters.internal;
import java.util.Arrays;
import org.springframework.core.env.Environment;
/**
* This class is internal and is hence not for public use. Its APIs are unstable and can change at
* any time.
*/
public final class ExporterConfigEvaluator {
private ExporterConfigEvaluator() {}
/**
* Returns whether the exporter is enabled. This method is used for OTLP, logging and zipkin
* exporters.
*/
public static boolean isExporterEnabled(
Environment environment, String exportersKey, String wantExporter, boolean defaultValue) {
String exporter = environment.getProperty(exportersKey);
if (exporter != null) {
return Arrays.asList(exporter.split(",")).contains(wantExporter);
}
return defaultValue;
}
}

View File

@ -1,42 +0,0 @@
/*
* Copyright The OpenTelemetry Authors
* SPDX-License-Identifier: Apache-2.0
*/
package io.opentelemetry.instrumentation.spring.autoconfigure.exporters.logging;
import io.opentelemetry.exporter.logging.LoggingMetricExporter;
import io.opentelemetry.instrumentation.spring.autoconfigure.OpenTelemetryAutoConfiguration;
import io.opentelemetry.instrumentation.spring.autoconfigure.exporters.internal.ExporterConfigEvaluator;
import io.opentelemetry.instrumentation.spring.autoconfigure.internal.SdkEnabled;
import org.springframework.boot.autoconfigure.AutoConfigureBefore;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Condition;
import org.springframework.context.annotation.ConditionContext;
import org.springframework.context.annotation.Conditional;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.type.AnnotatedTypeMetadata;
/** Configures {@link LoggingMetricExporter} bean for tracing. */
@Configuration
@AutoConfigureBefore(OpenTelemetryAutoConfiguration.class)
@Conditional({LoggingMetricExporterAutoConfiguration.CustomCondition.class, SdkEnabled.class})
@ConditionalOnClass(LoggingMetricExporter.class)
public class LoggingMetricExporterAutoConfiguration {
@Bean(destroyMethod = "") // SDK components are shutdown from the OpenTelemetry instance
@ConditionalOnMissingBean
public LoggingMetricExporter otelLoggingMetricExporter() {
return LoggingMetricExporter.create();
}
static final class CustomCondition implements Condition {
@Override
public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
return ExporterConfigEvaluator.isExporterEnabled(
context.getEnvironment(), "otel.metrics.exporter", "logging", false);
}
}
}

View File

@ -1,42 +0,0 @@
/*
* Copyright The OpenTelemetry Authors
* SPDX-License-Identifier: Apache-2.0
*/
package io.opentelemetry.instrumentation.spring.autoconfigure.exporters.logging;
import io.opentelemetry.exporter.logging.LoggingSpanExporter;
import io.opentelemetry.instrumentation.spring.autoconfigure.OpenTelemetryAutoConfiguration;
import io.opentelemetry.instrumentation.spring.autoconfigure.exporters.internal.ExporterConfigEvaluator;
import io.opentelemetry.instrumentation.spring.autoconfigure.internal.SdkEnabled;
import org.springframework.boot.autoconfigure.AutoConfigureBefore;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Condition;
import org.springframework.context.annotation.ConditionContext;
import org.springframework.context.annotation.Conditional;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.type.AnnotatedTypeMetadata;
/** Configures {@link LoggingSpanExporter} bean for tracing. */
@Configuration
@AutoConfigureBefore(OpenTelemetryAutoConfiguration.class)
@Conditional({LoggingSpanExporterAutoConfiguration.CustomCondition.class, SdkEnabled.class})
@ConditionalOnClass(LoggingSpanExporter.class)
public class LoggingSpanExporterAutoConfiguration {
@Bean(destroyMethod = "") // SDK components are shutdown from the OpenTelemetry instance
@ConditionalOnMissingBean
public LoggingSpanExporter otelLoggingSpanExporter() {
return LoggingSpanExporter.create();
}
static final class CustomCondition implements Condition {
@Override
public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
return ExporterConfigEvaluator.isExporterEnabled(
context.getEnvironment(), "otel.traces.exporter", "logging", false);
}
}
}

View File

@ -1,42 +0,0 @@
/*
* Copyright The OpenTelemetry Authors
* SPDX-License-Identifier: Apache-2.0
*/
package io.opentelemetry.instrumentation.spring.autoconfigure.exporters.logging;
import io.opentelemetry.exporter.logging.SystemOutLogRecordExporter;
import io.opentelemetry.instrumentation.spring.autoconfigure.OpenTelemetryAutoConfiguration;
import io.opentelemetry.instrumentation.spring.autoconfigure.exporters.internal.ExporterConfigEvaluator;
import io.opentelemetry.instrumentation.spring.autoconfigure.internal.SdkEnabled;
import org.springframework.boot.autoconfigure.AutoConfigureBefore;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Condition;
import org.springframework.context.annotation.ConditionContext;
import org.springframework.context.annotation.Conditional;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.type.AnnotatedTypeMetadata;
/** Configures {@link SystemOutLogRecordExporter} bean for tracing. */
@Configuration
@AutoConfigureBefore(OpenTelemetryAutoConfiguration.class)
@Conditional({SystemOutLogRecordExporterAutoConfiguration.CustomCondition.class, SdkEnabled.class})
@ConditionalOnClass(SystemOutLogRecordExporter.class)
public class SystemOutLogRecordExporterAutoConfiguration {
@Bean(destroyMethod = "") // SDK components are shutdown from the OpenTelemetry instance
@ConditionalOnMissingBean
public SystemOutLogRecordExporter otelSystemOutLogRecordExporter() {
return SystemOutLogRecordExporter.create();
}
static final class CustomCondition implements Condition {
@Override
public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
return ExporterConfigEvaluator.isExporterEnabled(
context.getEnvironment(), "otel.logs.exporter", "logging", false);
}
}
}

View File

@ -1,43 +0,0 @@
/*
* Copyright The OpenTelemetry Authors
* SPDX-License-Identifier: Apache-2.0
*/
package io.opentelemetry.instrumentation.spring.autoconfigure.exporters.otlp;
import io.opentelemetry.exporter.otlp.http.logs.OtlpHttpLogRecordExporter;
import io.opentelemetry.exporter.otlp.internal.OtlpLogRecordExporterProvider;
import io.opentelemetry.exporter.otlp.logs.OtlpGrpcLogRecordExporter;
import io.opentelemetry.instrumentation.spring.autoconfigure.OpenTelemetryAutoConfiguration;
import io.opentelemetry.instrumentation.spring.autoconfigure.exporters.internal.ExporterConfigEvaluator;
import io.opentelemetry.instrumentation.spring.autoconfigure.internal.SdkEnabled;
import io.opentelemetry.sdk.autoconfigure.spi.ConfigProperties;
import io.opentelemetry.sdk.logs.export.LogRecordExporter;
import org.springframework.boot.autoconfigure.AutoConfigureBefore;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Condition;
import org.springframework.context.annotation.ConditionContext;
import org.springframework.context.annotation.Conditional;
import org.springframework.core.type.AnnotatedTypeMetadata;
@AutoConfigureBefore(OpenTelemetryAutoConfiguration.class)
@Conditional({OtlpLogRecordExporterAutoConfiguration.CustomCondition.class, SdkEnabled.class})
@ConditionalOnClass(OtlpGrpcLogRecordExporter.class)
public class OtlpLogRecordExporterAutoConfiguration {
@Bean(destroyMethod = "") // SDK components are shutdown from the OpenTelemetry instance
@ConditionalOnMissingBean({OtlpGrpcLogRecordExporter.class, OtlpHttpLogRecordExporter.class})
public LogRecordExporter otelOtlpLogRecordExporter(ConfigProperties configProperties) {
return new OtlpLogRecordExporterProvider().createExporter(configProperties);
}
static final class CustomCondition implements Condition {
@Override
public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
return ExporterConfigEvaluator.isExporterEnabled(
context.getEnvironment(), "otel.logs.exporter", "otlp", true);
}
}
}

View File

@ -1,45 +0,0 @@
/*
* Copyright The OpenTelemetry Authors
* SPDX-License-Identifier: Apache-2.0
*/
package io.opentelemetry.instrumentation.spring.autoconfigure.exporters.otlp;
import io.opentelemetry.exporter.otlp.http.metrics.OtlpHttpMetricExporter;
import io.opentelemetry.exporter.otlp.internal.OtlpMetricExporterProvider;
import io.opentelemetry.exporter.otlp.metrics.OtlpGrpcMetricExporter;
import io.opentelemetry.instrumentation.spring.autoconfigure.OpenTelemetryAutoConfiguration;
import io.opentelemetry.instrumentation.spring.autoconfigure.exporters.internal.ExporterConfigEvaluator;
import io.opentelemetry.instrumentation.spring.autoconfigure.internal.SdkEnabled;
import io.opentelemetry.sdk.autoconfigure.spi.ConfigProperties;
import io.opentelemetry.sdk.metrics.export.MetricExporter;
import org.springframework.boot.autoconfigure.AutoConfigureBefore;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Condition;
import org.springframework.context.annotation.ConditionContext;
import org.springframework.context.annotation.Conditional;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.type.AnnotatedTypeMetadata;
@Configuration
@AutoConfigureBefore(OpenTelemetryAutoConfiguration.class)
@Conditional({OtlpMetricExporterAutoConfiguration.CustomCondition.class, SdkEnabled.class})
@ConditionalOnClass(OtlpGrpcMetricExporter.class)
public class OtlpMetricExporterAutoConfiguration {
@Bean(destroyMethod = "") // SDK components are shutdown from the OpenTelemetry instance
@ConditionalOnMissingBean({OtlpGrpcMetricExporter.class, OtlpHttpMetricExporter.class})
public MetricExporter otelOtlpMetricExporter(ConfigProperties configProperties) {
return new OtlpMetricExporterProvider().createExporter(configProperties);
}
static final class CustomCondition implements Condition {
@Override
public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
return ExporterConfigEvaluator.isExporterEnabled(
context.getEnvironment(), "otel.metrics.exporter", "otlp", true);
}
}
}

View File

@ -1,50 +0,0 @@
/*
* Copyright The OpenTelemetry Authors
* SPDX-License-Identifier: Apache-2.0
*/
package io.opentelemetry.instrumentation.spring.autoconfigure.exporters.otlp;
import io.opentelemetry.exporter.otlp.http.trace.OtlpHttpSpanExporter;
import io.opentelemetry.exporter.otlp.internal.OtlpSpanExporterProvider;
import io.opentelemetry.exporter.otlp.trace.OtlpGrpcSpanExporter;
import io.opentelemetry.instrumentation.spring.autoconfigure.OpenTelemetryAutoConfiguration;
import io.opentelemetry.instrumentation.spring.autoconfigure.exporters.internal.ExporterConfigEvaluator;
import io.opentelemetry.instrumentation.spring.autoconfigure.internal.SdkEnabled;
import io.opentelemetry.sdk.autoconfigure.spi.ConfigProperties;
import io.opentelemetry.sdk.trace.export.SpanExporter;
import org.springframework.boot.autoconfigure.AutoConfigureBefore;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Condition;
import org.springframework.context.annotation.ConditionContext;
import org.springframework.context.annotation.Conditional;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.type.AnnotatedTypeMetadata;
/**
* Configures {@link OtlpGrpcSpanExporter} for tracing.
*
* <p>Initializes {@link OtlpGrpcSpanExporter} bean if bean is missing.
*/
@Configuration
@AutoConfigureBefore(OpenTelemetryAutoConfiguration.class)
@Conditional({OtlpSpanExporterAutoConfiguration.CustomCondition.class, SdkEnabled.class})
@ConditionalOnClass(OtlpGrpcSpanExporter.class)
public class OtlpSpanExporterAutoConfiguration {
@Bean(destroyMethod = "") // SDK components are shutdown from the OpenTelemetry instance
@ConditionalOnMissingBean({OtlpGrpcSpanExporter.class, OtlpHttpSpanExporter.class})
public SpanExporter otelOtlpSpanExporter(ConfigProperties configProperties) {
return new OtlpSpanExporterProvider().createExporter(configProperties);
}
static final class CustomCondition implements Condition {
@Override
public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
return ExporterConfigEvaluator.isExporterEnabled(
context.getEnvironment(), "otel.traces.exporter", "otlp", true);
}
}
}

View File

@ -1,54 +0,0 @@
/*
* Copyright The OpenTelemetry Authors
* SPDX-License-Identifier: Apache-2.0
*/
package io.opentelemetry.instrumentation.spring.autoconfigure.exporters.zipkin;
import io.opentelemetry.exporter.zipkin.ZipkinSpanExporter;
import io.opentelemetry.exporter.zipkin.ZipkinSpanExporterBuilder;
import io.opentelemetry.instrumentation.spring.autoconfigure.OpenTelemetryAutoConfiguration;
import io.opentelemetry.instrumentation.spring.autoconfigure.exporters.internal.ExporterConfigEvaluator;
import io.opentelemetry.instrumentation.spring.autoconfigure.internal.SdkEnabled;
import org.springframework.boot.autoconfigure.AutoConfigureBefore;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Condition;
import org.springframework.context.annotation.ConditionContext;
import org.springframework.context.annotation.Conditional;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.type.AnnotatedTypeMetadata;
/**
* Configures {@link ZipkinSpanExporter} for tracing.
*
* <p>Initializes {@link ZipkinSpanExporter} bean if bean is missing.
*/
@Configuration
@AutoConfigureBefore(OpenTelemetryAutoConfiguration.class)
@EnableConfigurationProperties(ZipkinSpanExporterProperties.class)
@Conditional({ZipkinSpanExporterAutoConfiguration.CustomCondition.class, SdkEnabled.class})
@ConditionalOnClass(ZipkinSpanExporter.class)
public class ZipkinSpanExporterAutoConfiguration {
@Bean(destroyMethod = "") // SDK components are shutdown from the OpenTelemetry instance
@ConditionalOnMissingBean
public ZipkinSpanExporter otelZipkinSpanExporter(ZipkinSpanExporterProperties properties) {
ZipkinSpanExporterBuilder builder = ZipkinSpanExporter.builder();
if (properties.getEndpoint() != null) {
builder.setEndpoint(properties.getEndpoint());
}
return builder.build();
}
static final class CustomCondition implements Condition {
@Override
public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
return ExporterConfigEvaluator.isExporterEnabled(
context.getEnvironment(), "otel.traces.exporter", "zipkin", true);
}
}
}

View File

@ -1,29 +0,0 @@
/*
* Copyright The OpenTelemetry Authors
* SPDX-License-Identifier: Apache-2.0
*/
package io.opentelemetry.instrumentation.spring.autoconfigure.exporters.zipkin;
import javax.annotation.Nullable;
import org.springframework.boot.context.properties.ConfigurationProperties;
/**
* Configuration for {@link io.opentelemetry.exporter.zipkin.ZipkinSpanExporter}.
*
* <p>Get Exporter Endpoint
*/
@ConfigurationProperties(prefix = "otel.exporter.zipkin")
public class ZipkinSpanExporterProperties {
@Nullable private String endpoint;
@Nullable
public String getEndpoint() {
return endpoint;
}
public void setEndpoint(String endpoint) {
this.endpoint = endpoint;
}
}

View File

@ -1,88 +0,0 @@
/*
* Copyright The OpenTelemetry Authors
* SPDX-License-Identifier: Apache-2.0
*/
package io.opentelemetry.instrumentation.spring.autoconfigure.propagators;
import static java.util.logging.Level.WARNING;
import io.opentelemetry.api.baggage.propagation.W3CBaggagePropagator;
import io.opentelemetry.api.trace.propagation.W3CTraceContextPropagator;
import io.opentelemetry.context.propagation.TextMapPropagator;
import io.opentelemetry.contrib.awsxray.propagator.AwsXrayPropagator;
import io.opentelemetry.extension.trace.propagation.B3Propagator;
import io.opentelemetry.extension.trace.propagation.OtTracePropagator;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.logging.Logger;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.util.ClassUtils;
/** Factory of composite {@link TextMapPropagator}. Defaults to W3C and BAGGAGE. */
public final class CompositeTextMapPropagatorFactory {
private static final Logger logger =
Logger.getLogger(CompositeTextMapPropagatorFactory.class.getName());
static TextMapPropagator getCompositeTextMapPropagator(
BeanFactory beanFactory, List<String> types) {
Set<TextMapPropagator> propagators = new HashSet<>();
for (String type : types) {
switch (type) {
case "b3":
if (isOnClasspath("io.opentelemetry.extension.trace.propagation.B3Propagator")) {
propagators.add(
beanFactory
.getBeanProvider(B3Propagator.class)
.getIfAvailable(B3Propagator::injectingSingleHeader));
}
break;
case "b3multi":
if (isOnClasspath("io.opentelemetry.extension.trace.propagation.B3Propagator")) {
propagators.add(
beanFactory
.getBeanProvider(B3Propagator.class)
.getIfAvailable(B3Propagator::injectingMultiHeaders));
}
break;
case "ottrace":
if (isOnClasspath("io.opentelemetry.extension.trace.propagation.OtTracerPropagator")) {
propagators.add(
beanFactory
.getBeanProvider(OtTracePropagator.class)
.getIfAvailable(OtTracePropagator::getInstance));
}
break;
case "xray":
if (isOnClasspath("io.opentelemetry.contrib.awsxray.propagator.AwsXrayPropagator")) {
propagators.add(
beanFactory
.getBeanProvider(AwsXrayPropagator.class)
.getIfAvailable(AwsXrayPropagator::getInstance));
}
break;
case "tracecontext":
propagators.add(W3CTraceContextPropagator.getInstance());
break;
case "baggage":
propagators.add(W3CBaggagePropagator.getInstance());
break;
default:
logger.log(WARNING, "Unsupported type of propagator: {0}", type);
break;
}
}
return TextMapPropagator.composite(propagators);
}
private static boolean isOnClasspath(String clazz) {
return ClassUtils.isPresent(clazz, CompositeTextMapPropagatorFactory.class.getClassLoader());
}
private CompositeTextMapPropagatorFactory() {}
}

View File

@ -1,56 +0,0 @@
/*
* Copyright The OpenTelemetry Authors
* SPDX-License-Identifier: Apache-2.0
*/
package io.opentelemetry.instrumentation.spring.autoconfigure.propagators;
import io.opentelemetry.context.propagation.ContextPropagators;
import io.opentelemetry.context.propagation.TextMapPropagator;
import io.opentelemetry.instrumentation.spring.autoconfigure.OpenTelemetryAutoConfiguration;
import io.opentelemetry.instrumentation.spring.autoconfigure.internal.SdkEnabled;
import io.opentelemetry.sdk.autoconfigure.spi.ConfigProperties;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.ObjectProvider;
import org.springframework.boot.autoconfigure.AutoConfigureBefore;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Conditional;
import org.springframework.context.annotation.Configuration;
/** Configures {@link ContextPropagators} bean for propagation. */
@Configuration
@EnableConfigurationProperties(PropagationProperties.class)
@AutoConfigureBefore(OpenTelemetryAutoConfiguration.class)
@ConditionalOnProperty(prefix = "otel.propagation", name = "enabled", matchIfMissing = true)
@Conditional(SdkEnabled.class)
public class PropagationAutoConfiguration {
private static final List<String> DEFAULT_PROPAGATORS = Arrays.asList("tracecontext", "baggage");
@Bean
@ConditionalOnMissingBean
ContextPropagators contextPropagators(ObjectProvider<List<TextMapPropagator>> propagators) {
List<TextMapPropagator> mapPropagators = propagators.getIfAvailable(Collections::emptyList);
if (mapPropagators.isEmpty()) {
return ContextPropagators.noop();
}
return ContextPropagators.create(TextMapPropagator.composite(mapPropagators));
}
@Configuration
static class PropagatorsConfiguration {
@Bean
TextMapPropagator compositeTextMapPropagator(
BeanFactory beanFactory, ConfigProperties configProperties) {
return CompositeTextMapPropagatorFactory.getCompositeTextMapPropagator(
beanFactory, configProperties.getList("otel.propagators", DEFAULT_PROPAGATORS));
}
}
}

View File

@ -3,7 +3,7 @@
* SPDX-License-Identifier: Apache-2.0
*/
package io.opentelemetry.instrumentation.spring.autoconfigure.resources;
package io.opentelemetry.instrumentation.spring.autoconfigure.properties;
import java.util.Collections;
import java.util.Map;

View File

@ -3,7 +3,7 @@
* SPDX-License-Identifier: Apache-2.0
*/
package io.opentelemetry.instrumentation.spring.autoconfigure.exporters.otlp;
package io.opentelemetry.instrumentation.spring.autoconfigure.properties;
import java.util.HashMap;
import java.util.Map;

View File

@ -3,7 +3,7 @@
* SPDX-License-Identifier: Apache-2.0
*/
package io.opentelemetry.instrumentation.spring.autoconfigure.propagators;
package io.opentelemetry.instrumentation.spring.autoconfigure.properties;
import java.util.Collections;
import java.util.List;

View File

@ -3,11 +3,9 @@
* SPDX-License-Identifier: Apache-2.0
*/
package io.opentelemetry.instrumentation.spring.autoconfigure.resources;
package io.opentelemetry.instrumentation.spring.autoconfigure.properties;
import io.opentelemetry.exporter.otlp.internal.OtlpConfigUtil;
import io.opentelemetry.instrumentation.spring.autoconfigure.exporters.otlp.OtlpExporterProperties;
import io.opentelemetry.instrumentation.spring.autoconfigure.propagators.PropagationProperties;
import io.opentelemetry.sdk.autoconfigure.spi.ConfigProperties;
import io.opentelemetry.sdk.autoconfigure.spi.internal.DefaultConfigProperties;
import java.time.Duration;
@ -17,6 +15,7 @@ import java.util.Map;
import javax.annotation.Nullable;
import org.springframework.core.env.Environment;
import org.springframework.expression.ExpressionParser;
import org.springframework.expression.spel.standard.SpelExpressionParser;
public class SpringConfigProperties implements ConfigProperties {
private final Environment environment;
@ -25,18 +24,37 @@ public class SpringConfigProperties implements ConfigProperties {
private final OtlpExporterProperties otlpExporterProperties;
private final OtelResourceProperties resourceProperties;
private final PropagationProperties propagationProperties;
private final ConfigProperties fallback;
public SpringConfigProperties(
Environment environment,
ExpressionParser parser,
OtlpExporterProperties otlpExporterProperties,
OtelResourceProperties resourceProperties,
PropagationProperties propagationProperties) {
PropagationProperties propagationProperties,
ConfigProperties fallback) {
this.environment = environment;
this.parser = parser;
this.otlpExporterProperties = otlpExporterProperties;
this.resourceProperties = resourceProperties;
this.propagationProperties = propagationProperties;
this.fallback = fallback;
}
// visible for testing
public static ConfigProperties create(
Environment env,
OtlpExporterProperties otlpExporterProperties,
OtelResourceProperties resourceProperties,
PropagationProperties propagationProperties,
ConfigProperties fallback) {
return new SpringConfigProperties(
env,
new SpelExpressionParser(),
otlpExporterProperties,
resourceProperties,
propagationProperties,
fallback);
}
@Nullable
@ -48,31 +66,31 @@ public class SpringConfigProperties implements ConfigProperties {
// in specification to default to `http/protobuf`
return OtlpConfigUtil.PROTOCOL_HTTP_PROTOBUF;
}
return value;
return or(value, fallback.getString(name));
}
@Nullable
@Override
public Boolean getBoolean(String name) {
return environment.getProperty(name, Boolean.class);
return or(environment.getProperty(name, Boolean.class), fallback.getBoolean(name));
}
@Nullable
@Override
public Integer getInt(String name) {
return environment.getProperty(name, Integer.class);
return or(environment.getProperty(name, Integer.class), fallback.getInt(name));
}
@Nullable
@Override
public Long getLong(String name) {
return environment.getProperty(name, Long.class);
return or(environment.getProperty(name, Long.class), fallback.getLong(name));
}
@Nullable
@Override
public Double getDouble(String name) {
return environment.getProperty(name, Double.class);
return or(environment.getProperty(name, Double.class), fallback.getDouble(name));
}
@SuppressWarnings("unchecked")
@ -82,8 +100,7 @@ public class SpringConfigProperties implements ConfigProperties {
return propagationProperties.getPropagators();
}
List<String> value = environment.getProperty(name, List.class);
return value == null ? Collections.emptyList() : value;
return or(environment.getProperty(name, List.class), fallback.getList(name));
}
@Nullable
@ -91,7 +108,7 @@ public class SpringConfigProperties implements ConfigProperties {
public Duration getDuration(String name) {
String value = getString(name);
if (value == null) {
return null;
return fallback.getDuration(name);
}
return DefaultConfigProperties.createFromMap(Collections.singletonMap(name, value))
.getDuration(name);
@ -118,8 +135,13 @@ public class SpringConfigProperties implements ConfigProperties {
String value = environment.getProperty(name);
if (value == null) {
return Collections.emptyMap();
return fallback.getMap(name);
}
return (Map<String, String>) parser.parseExpression(value).getValue();
}
@Nullable
private static <T> T or(@Nullable T first, @Nullable T second) {
return first != null ? first : second;
}
}

View File

@ -1,83 +0,0 @@
/*
* Copyright The OpenTelemetry Authors
* SPDX-License-Identifier: Apache-2.0
*/
package io.opentelemetry.instrumentation.spring.autoconfigure.resources;
import io.opentelemetry.instrumentation.resources.ContainerResource;
import io.opentelemetry.instrumentation.resources.ContainerResourceProvider;
import io.opentelemetry.instrumentation.resources.HostResource;
import io.opentelemetry.instrumentation.resources.HostResourceProvider;
import io.opentelemetry.instrumentation.resources.OsResource;
import io.opentelemetry.instrumentation.resources.OsResourceProvider;
import io.opentelemetry.instrumentation.resources.ProcessResource;
import io.opentelemetry.instrumentation.resources.ProcessResourceProvider;
import io.opentelemetry.instrumentation.resources.ProcessRuntimeResource;
import io.opentelemetry.instrumentation.resources.ProcessRuntimeResourceProvider;
import io.opentelemetry.instrumentation.spring.autoconfigure.OpenTelemetryAutoConfiguration;
import io.opentelemetry.instrumentation.spring.autoconfigure.internal.SdkEnabled;
import io.opentelemetry.sdk.autoconfigure.internal.EnvironmentResourceProvider;
import io.opentelemetry.sdk.autoconfigure.spi.ResourceProvider;
import java.util.Optional;
import org.springframework.boot.autoconfigure.AutoConfigureBefore;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.boot.info.BuildProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Conditional;
import org.springframework.context.annotation.Configuration;
@Configuration
@EnableConfigurationProperties({OtelResourceProperties.class})
@AutoConfigureBefore(OpenTelemetryAutoConfiguration.class)
@ConditionalOnProperty(prefix = "otel.springboot.resource", name = "enabled", matchIfMissing = true)
@Conditional(SdkEnabled.class)
public class OtelResourceAutoConfiguration {
@Bean
public ResourceProvider otelEnvironmentResourceProvider() {
return new EnvironmentResourceProvider();
}
@Bean
public ResourceProvider otelSpringResourceProvider(Optional<BuildProperties> buildProperties) {
return new SpringResourceProvider(buildProperties);
}
@Bean
public ResourceProvider otelDistroVersionResourceProvider() {
return new DistroVersionResourceProvider();
}
@Bean
@ConditionalOnClass(OsResource.class)
public ResourceProvider otelOsResourceProvider() {
return new OsResourceProvider();
}
@Bean
@ConditionalOnClass(ProcessResource.class)
public ResourceProvider otelProcessResourceProvider() {
return new ProcessResourceProvider();
}
@Bean
@ConditionalOnClass(ProcessRuntimeResource.class)
public ResourceProvider otelProcessRuntimeResourceProvider() {
return new ProcessRuntimeResourceProvider();
}
@Bean
@ConditionalOnClass(HostResource.class)
public ResourceProvider otelHostResourceProvider() {
return new HostResourceProvider();
}
@Bean
@ConditionalOnClass(ContainerResource.class)
public ResourceProvider otelContainerResourceProvider() {
return new ContainerResourceProvider();
}
}

View File

@ -5,12 +5,82 @@
}
],
"properties": [
{
"name": "otel.attribute.count.limit",
"type": "java.lang.Integer",
"description": "The maximum number of attributes. Applies to spans, span events, span links, and logs.",
"defaultValue": 128
},
{
"name": "otel.attribute.value.length.limit",
"type": "java.lang.String",
"description": "The maximum length of attribute values. Applies to spans and logs. By default, there is no limit."
},
{
"name": "otel.blrp.export.timeout",
"type": "java.lang.String",
"description": "The maximum allowed time, in milliseconds, to export OTLP log batch data.<br/>Durations can be of the form <code>{number}{unit}</code>, where unit is one of:<ul><li>ms<li>s<li>m<li>h<li>d</ul><p>If no unit is specified, milliseconds is the assumed duration unit.",
"defaultValue": 30000
},
{
"name": "otel.blrp.max.export.batch.size",
"type": "java.lang.Integer",
"description": "The maximum OTLP log batch size.",
"defaultValue": 512
},
{
"name": "otel.blrp.max.queue.size",
"type": "java.lang.Integer",
"description": "The maximum OTLP log batch queue size.",
"defaultValue": 2048
},
{
"name": "otel.blrp.schedule.delay",
"type": "java.lang.String",
"description": "The interval, in milliseconds, between two consecutive OTLP log batch exports.<br/>Durations can be of the form <code>{number}{unit}</code>, where unit is one of:<ul><li>ms<li>s<li>m<li>h<li>d</ul><p>If no unit is specified, milliseconds is the assumed duration unit.",
"defaultValue": 1000
},
{
"name": "otel.bsp.schedule.delay",
"type": "java.lang.String",
"description": "The interval, in milliseconds, between two consecutive OTLP span batch exports.<br/>Durations can be of the form <code>{number}{unit}</code>, where unit is one of:<ul><li>ms<li>s<li>m<li>h<li>d</ul><p>If no unit is specified, milliseconds is the assumed duration unit.",
"defaultValue": 5000
},
{
"name": "otel.bsp.export.timeout",
"type": "java.lang.String",
"description": "The maximum allowed time, in milliseconds, to export OTLP span batch data.<br/>Durations can be of the form <code>{number}{unit}</code>, where unit is one of:<ul><li>ms<li>s<li>m<li>h<li>d</ul><p>If no unit is specified, milliseconds is the assumed duration unit.",
"defaultValue": 30000
},
{
"name": "otel.bsp.max.export.batch.size",
"type": "java.lang.Integer",
"description": "The maximum OTLP span batch size.",
"defaultValue": 512
},
{
"name": "otel.bsp.max.queue.size",
"type": "java.lang.Integer",
"description": "The maximum OTLP span batch queue size.",
"defaultValue": 2048
},
{
"name": "otel.experimental.exporter.otlp.retry.enabled",
"type": "java.lang.Boolean",
"description": "Enable experimental retry support. See https://github.com/open-telemetry/opentelemetry-java/blob/main/sdk-extensions/autoconfigure/README.md#otlp-exporter-retry.",
"defaultValue": false
},
{
"name": "otel.experimental.metrics.cardinality.limit",
"type": "java.lang.Integer",
"description": "If set, configure experimental cardinality limit. The value dictates the maximum number of distinct points per metric.",
"defaultValue": 2000
},
{
"name": "otel.experimental.resource.disabled.keys",
"type": "java.util.List<java.lang.String>",
"description": "Filter out resource entries with these keys."
},
{
"name": "otel.exporter.otlp.certificate",
"type": "java.lang.String",
@ -280,6 +350,16 @@
"description": "Enable the Servlet instrumentation.",
"defaultValue": true
},
{
"name": "otel.java.enabled.resource.providers",
"type": "java.util.List<java.lang.String>",
"description": "Enables one or more <code>ResourceProvider</code> types. If unset, all resource providers are enabled. Each entry is the fully qualified classname of a <code>ResourceProvider</code>."
},
{
"name": "otel.java.disabled.resource.providers",
"type": "java.util.List<java.lang.String>",
"description": " Disables one or more <code>ResourceProvider</code> types. Each entry is the fully qualified classname of a <code>ResourceProvider</code>."
},
{
"name": "otel.logs.exporter",
"type": "java.util.List<java.lang.String>",
@ -292,6 +372,12 @@
"description": "The interval, in milliseconds, between the start of two export attempts.<br/>Durations can be of the form <code>{number}{unit}</code>, where unit is one of:<ul><li>ms<li>s<li>m<li>h<li>d</ul><p>If no unit is specified, milliseconds is the assumed duration unit.",
"defaultValue": "60000"
},
{
"name": "otel.metrics.exemplar.filter",
"type": "java.lang.String",
"description": "The filter for exemplar sampling.",
"defaultValue": "TRACE_BASED"
},
{
"name": "otel.metrics.exporter",
"type": "java.util.List<java.lang.String>",
@ -316,10 +402,32 @@
"defaultValue": false
},
{
"name": "otel.springboot.resource.enabled",
"type": "java.lang.Boolean",
"description": "Enable the resource auto-configuration.",
"defaultValue": true
"name": "otel.service.name",
"type": "java.lang.String",
"description": "Specify logical service name. Takes precedence over <code>service.name</code> defined with <code>otel.resource.attributes</code>."
},
{
"name": "otel.span.attribute.value.length.limit",
"type": "java.lang.Integer",
"description": "The maximum length of span attribute values. Takes precedence over <code>otel.attribute.value.length.limit</code>. By default, there is no limit."
},
{
"name": "otel.span.attribute.count.limit",
"type": "java.lang.Integer",
"description": "The maximum number of attributes per span. Takes precedence over <code>otel.attribute.count.limit<code>.",
"defaultValue": 128
},
{
"name": "otel.span.event.count.limit",
"type": "java.lang.Integer",
"description": "The maximum number of events per span.",
"defaultValue": 128
},
{
"name": "otel.span.link.count.limit",
"type": "java.lang.Integer",
"description": "The maximum number of links per span.",
"defaultValue": 128
},
{
"name": "otel.traces.exporter",
@ -328,9 +436,15 @@
"defaultValue": "otlp"
},
{
"name": "otel.traces.sampler.probability",
"name": "otel.traces.sampler",
"type": "java.lang.String",
"description": "The sampler to use for tracing.",
"defaultValue": "parentbased_always_on"
},
{
"name": "otel.traces.sampler.arg",
"type": "java.lang.Double",
"description": "The probability of sampling.<br/>The value should be within [0.0, 1.0]. 1.0 means keep everything, 0.0 means drop all spans.",
"description": "An argument to the configured tracer if supported, for example a ratio.",
"defaultValue": 1.0
}
],
@ -424,6 +538,23 @@
}
]
},
{
"name": "otel.metrics.exemplar.filter",
"values": [
{
"value": "ALWAYS_ON",
"description": "Take all exemplars."
},
{
"value": "ALWAYS_OFF",
"description": "Drop all exemplars."
},
{
"value": "TRACE_BASED",
"description": "Choose exemplars that correspond to a sampled span."
}
]
},
{
"name": "otel.metrics.exporter",
"values": [
@ -494,6 +625,35 @@
"description": "Zipkin exporter."
}
]
},
{
"name": "otel.traces.sampler",
"values": [
{
"value": "always_on",
"description": "Keep all spans."
},
{
"value": "always_off",
"description": "Drop all spans."
},
{
"value": "traceidratio",
"description": "Keep a ratio of <code>otel.traces.sampler.arg<code> of all spans."
},
{
"value": "parentbased_always_on",
"description": "Keep all spans where the parent is also kept. If there is no parent, keep all spans."
},
{
"value": "parentbased_always_off",
"description": "Keep all spans where the parent is also kept. If there is no parent, drop all spans."
},
{
"value": "parentbased_traceidratio",
"description": "Keep all spans where the parent is also kept. If there is no parent, keep a ratio of <code>otel.traces.sampler.arg<code> of all spans."
}
]
}
]
}

View File

@ -1,11 +1,5 @@
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
io.opentelemetry.instrumentation.spring.autoconfigure.OpenTelemetryAutoConfiguration,\
io.opentelemetry.instrumentation.spring.autoconfigure.exporters.logging.LoggingMetricExporterAutoConfiguration,\
io.opentelemetry.instrumentation.spring.autoconfigure.exporters.logging.LoggingSpanExporterAutoConfiguration,\
io.opentelemetry.instrumentation.spring.autoconfigure.exporters.otlp.OtlpLogRecordExporterAutoConfiguration,\
io.opentelemetry.instrumentation.spring.autoconfigure.exporters.otlp.OtlpMetricExporterAutoConfiguration,\
io.opentelemetry.instrumentation.spring.autoconfigure.exporters.otlp.OtlpSpanExporterAutoConfiguration,\
io.opentelemetry.instrumentation.spring.autoconfigure.exporters.zipkin.ZipkinSpanExporterAutoConfiguration,\
io.opentelemetry.instrumentation.spring.autoconfigure.instrumentation.annotations.InstrumentationAnnotationsAutoConfiguration,\
io.opentelemetry.instrumentation.spring.autoconfigure.instrumentation.kafka.KafkaInstrumentationAutoConfiguration,\
io.opentelemetry.instrumentation.spring.autoconfigure.instrumentation.logging.OpenTelemetryAppenderAutoConfiguration,\
@ -13,9 +7,7 @@ io.opentelemetry.instrumentation.spring.autoconfigure.instrumentation.jdbc.OpenT
io.opentelemetry.instrumentation.spring.autoconfigure.instrumentation.micrometer.MicrometerBridgeAutoConfiguration,\
io.opentelemetry.instrumentation.spring.autoconfigure.instrumentation.web.SpringWebInstrumentationAutoConfiguration,\
io.opentelemetry.instrumentation.spring.autoconfigure.instrumentation.webflux.SpringWebfluxInstrumentationAutoConfiguration,\
io.opentelemetry.instrumentation.spring.autoconfigure.instrumentation.webmvc.SpringWebMvc5InstrumentationAutoConfiguration,\
io.opentelemetry.instrumentation.spring.autoconfigure.propagators.PropagationAutoConfiguration,\
io.opentelemetry.instrumentation.spring.autoconfigure.resources.OtelResourceAutoConfiguration
io.opentelemetry.instrumentation.spring.autoconfigure.instrumentation.webmvc.SpringWebMvc5InstrumentationAutoConfiguration
org.springframework.context.ApplicationListener=\
io.opentelemetry.instrumentation.spring.autoconfigure.instrumentation.logging.LogbackAppenderApplicationListener

View File

@ -1,10 +1,4 @@
io.opentelemetry.instrumentation.spring.autoconfigure.OpenTelemetryAutoConfiguration
io.opentelemetry.instrumentation.spring.autoconfigure.exporters.logging.LoggingMetricExporterAutoConfiguration
io.opentelemetry.instrumentation.spring.autoconfigure.exporters.logging.LoggingSpanExporterAutoConfiguration
io.opentelemetry.instrumentation.spring.autoconfigure.exporters.otlp.OtlpLogRecordExporterAutoConfiguration
io.opentelemetry.instrumentation.spring.autoconfigure.exporters.otlp.OtlpMetricExporterAutoConfiguration
io.opentelemetry.instrumentation.spring.autoconfigure.exporters.otlp.OtlpSpanExporterAutoConfiguration
io.opentelemetry.instrumentation.spring.autoconfigure.exporters.zipkin.ZipkinSpanExporterAutoConfiguration
io.opentelemetry.instrumentation.spring.autoconfigure.instrumentation.annotations.InstrumentationAnnotationsAutoConfiguration
io.opentelemetry.instrumentation.spring.autoconfigure.instrumentation.kafka.KafkaInstrumentationAutoConfiguration
io.opentelemetry.instrumentation.spring.autoconfigure.instrumentation.logging.OpenTelemetryAppenderAutoConfiguration
@ -13,5 +7,3 @@ io.opentelemetry.instrumentation.spring.autoconfigure.instrumentation.micrometer
io.opentelemetry.instrumentation.spring.autoconfigure.instrumentation.web.SpringWebInstrumentationAutoConfiguration
io.opentelemetry.instrumentation.spring.autoconfigure.instrumentation.webflux.SpringWebfluxInstrumentationAutoConfiguration
io.opentelemetry.instrumentation.spring.autoconfigure.instrumentation.webmvc.SpringWebMvc6InstrumentationAutoConfiguration
io.opentelemetry.instrumentation.spring.autoconfigure.propagators.PropagationAutoConfiguration
io.opentelemetry.instrumentation.spring.autoconfigure.resources.OtelResourceAutoConfiguration

View File

@ -6,17 +6,17 @@
package io.opentelemetry.instrumentation.spring.autoconfigure;
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.withSettings;
import io.opentelemetry.api.OpenTelemetry;
import io.opentelemetry.api.common.AttributeKey;
import io.opentelemetry.instrumentation.spring.autoconfigure.resources.OtelResourceAutoConfiguration;
import io.opentelemetry.exporter.otlp.internal.OtlpSpanExporterProvider;
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 io.opentelemetry.sdk.autoconfigure.spi.internal.AutoConfigureListener;
import io.opentelemetry.sdk.trace.export.SpanExporter;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import org.mockito.Mockito;
import org.springframework.boot.autoconfigure.AutoConfigurations;
import org.springframework.boot.test.context.TestConfiguration;
import org.springframework.boot.test.context.runner.ApplicationContextRunner;
@ -32,7 +32,10 @@ class OpenTelemetryAutoConfigurationTest {
}
}
private final ApplicationContextRunner contextRunner = new ApplicationContextRunner();
private final ApplicationContextRunner contextRunner =
new ApplicationContextRunner()
.withPropertyValues(
"otel.traces.exporter=none", "otel.metrics.exporter=none", "otel.logs.exporter=none");
@Test
@DisplayName(
@ -45,10 +48,7 @@ class OpenTelemetryAutoConfigurationTest {
context ->
assertThat(context)
.hasBean("customOpenTelemetry")
.doesNotHaveBean("openTelemetry")
.doesNotHaveBean("sdkTracerProvider")
.doesNotHaveBean("sdkMeterProvider")
.doesNotHaveBean("sdkLoggerProvider"));
.doesNotHaveBean("openTelemetry"));
}
@Test
@ -57,69 +57,32 @@ class OpenTelemetryAutoConfigurationTest {
void initializeProvidersAndOpenTelemetry() {
this.contextRunner
.withConfiguration(AutoConfigurations.of(OpenTelemetryAutoConfiguration.class))
.run(
context ->
assertThat(context)
.hasBean("openTelemetry")
.hasBean("sdkTracerProvider")
.hasBean("sdkMeterProvider")
.hasBean("sdkLoggerProvider"));
.run(context -> assertThat(context).hasBean("openTelemetry"));
}
@Test
@DisplayName(
"when Application Context DOES NOT contain OpenTelemetry bean but TracerProvider should initialize openTelemetry")
"when Application Context DOES NOT contain OpenTelemetry bean but SpanExporter should initialize openTelemetry")
void initializeOpenTelemetryWithCustomProviders() {
OtlpSpanExporterProvider spanExporterProvider =
Mockito.mock(
OtlpSpanExporterProvider.class,
withSettings().extraInterfaces(AutoConfigureListener.class));
Mockito.when(spanExporterProvider.getName()).thenReturn("custom");
Mockito.when(spanExporterProvider.createExporter(any()))
.thenReturn(Mockito.mock(SpanExporter.class));
this.contextRunner
.withBean(
"customTracerProvider",
SdkTracerProvider.class,
() -> SdkTracerProvider.builder().build(),
bd -> bd.setDestroyMethodName(""))
.withBean(
"customMeterProvider",
SdkMeterProvider.class,
() -> SdkMeterProvider.builder().build(),
bd -> bd.setDestroyMethodName(""))
.withBean(
"customLoggerProvider",
SdkLoggerProvider.class,
() -> SdkLoggerProvider.builder().build(),
"customSpanExporter",
OtlpSpanExporterProvider.class,
() -> spanExporterProvider,
bd -> bd.setDestroyMethodName(""))
.withConfiguration(AutoConfigurations.of(OpenTelemetryAutoConfiguration.class))
.run(
context ->
assertThat(context)
.hasBean("openTelemetry")
.hasBean("customTracerProvider")
.doesNotHaveBean("sdkTracerProvider")
.hasBean("customMeterProvider")
.doesNotHaveBean("sdkMeterProvider")
.hasBean("customLoggerProvider")
.doesNotHaveBean("sdkLoggerProvider"));
}
.withPropertyValues("otel.traces.exporter=custom")
.run(context -> assertThat(context).hasBean("openTelemetry"));
@Test
@DisplayName("when otel attributes are set in properties they should be put in resource")
void shouldInitializeAttributes() {
this.contextRunner
.withConfiguration(
AutoConfigurations.of(
OtelResourceAutoConfiguration.class, OpenTelemetryAutoConfiguration.class))
.withPropertyValues(
"otel.resource.attributes.xyz=foo",
"otel.resource.attributes.environment=dev",
"otel.resource.attributes.service.instance.id=id-example")
.run(
context -> {
Resource otelResource = context.getBean("otelResource", Resource.class);
assertThat(otelResource.getAttribute(AttributeKey.stringKey("environment")))
.isEqualTo("dev");
assertThat(otelResource.getAttribute(AttributeKey.stringKey("xyz"))).isEqualTo("foo");
assertThat(otelResource.getAttribute(AttributeKey.stringKey("service.instance.id")))
.isEqualTo("id-example");
});
Mockito.verify(spanExporterProvider).afterAutoConfigure(any());
}
@Test
@ -130,10 +93,7 @@ class OpenTelemetryAutoConfigurationTest {
.run(
context -> {
assertThat(context).getBean("openTelemetry").isInstanceOf(OpenTelemetrySdk.class);
assertThat(context)
.hasBean("openTelemetry")
.hasBean("sdkTracerProvider")
.hasBean("sdkMeterProvider");
assertThat(context).hasBean("openTelemetry");
});
}
@ -143,11 +103,7 @@ class OpenTelemetryAutoConfigurationTest {
.withConfiguration(AutoConfigurations.of(OpenTelemetryAutoConfiguration.class))
.withPropertyValues("otel.sdk.disabled=true")
.run(
context -> {
assertThat(context).getBean("openTelemetry").isEqualTo(OpenTelemetry.noop());
assertThat(context)
.doesNotHaveBean("sdkTracerProvider")
.doesNotHaveBean("sdkMeterProvider");
});
context ->
assertThat(context).getBean("openTelemetry").isEqualTo(OpenTelemetry.noop()));
}
}

View File

@ -1,56 +0,0 @@
/*
* Copyright The OpenTelemetry Authors
* SPDX-License-Identifier: Apache-2.0
*/
package io.opentelemetry.instrumentation.spring.autoconfigure.exporters;
import static org.assertj.core.api.Assertions.assertThat;
import io.opentelemetry.exporter.logging.LoggingMetricExporter;
import io.opentelemetry.exporter.otlp.http.metrics.OtlpHttpMetricExporter;
import io.opentelemetry.instrumentation.spring.autoconfigure.OpenTelemetryAutoConfiguration;
import io.opentelemetry.instrumentation.spring.autoconfigure.exporters.logging.LoggingMetricExporterAutoConfiguration;
import io.opentelemetry.instrumentation.spring.autoconfigure.exporters.otlp.OtlpMetricExporterAutoConfiguration;
import org.junit.jupiter.api.Test;
import org.springframework.boot.autoconfigure.AutoConfigurations;
import org.springframework.boot.test.context.runner.ApplicationContextRunner;
class MetricExporterAutoConfigurationTest {
private final ApplicationContextRunner contextRunner =
new ApplicationContextRunner()
.withConfiguration(
AutoConfigurations.of(
OpenTelemetryAutoConfiguration.class,
OtlpMetricExporterAutoConfiguration.class,
LoggingMetricExporterAutoConfiguration.class));
@Test
void defaultConfiguration() {
contextRunner.run(
context -> {
assertThat(context.getBean("otelOtlpMetricExporter", OtlpHttpMetricExporter.class))
.as("OTLP exporter is enabled by default")
.isNotNull();
assertThat(context.containsBean("otelLoggingMetricExporter"))
.as("Logging exporter is not created unless explicitly configured")
.isFalse();
});
}
@Test
void loggingEnabledByConfiguration() {
contextRunner
.withPropertyValues("otel.metrics.exporter=logging,otlp")
.run(
context -> {
assertThat(context.getBean("otelOtlpMetricExporter", OtlpHttpMetricExporter.class))
.as("OTLP exporter is present even with logging enabled")
.isNotNull();
assertThat(context.getBean("otelLoggingMetricExporter", LoggingMetricExporter.class))
.as("Logging exporter is explicitly enabled")
.isNotNull();
});
}
}

View File

@ -1,56 +0,0 @@
/*
* Copyright The OpenTelemetry Authors
* SPDX-License-Identifier: Apache-2.0
*/
package io.opentelemetry.instrumentation.spring.autoconfigure.exporters;
import static org.assertj.core.api.Assertions.assertThat;
import io.opentelemetry.exporter.logging.LoggingSpanExporter;
import io.opentelemetry.exporter.otlp.http.trace.OtlpHttpSpanExporter;
import io.opentelemetry.instrumentation.spring.autoconfigure.OpenTelemetryAutoConfiguration;
import io.opentelemetry.instrumentation.spring.autoconfigure.exporters.logging.LoggingSpanExporterAutoConfiguration;
import io.opentelemetry.instrumentation.spring.autoconfigure.exporters.otlp.OtlpSpanExporterAutoConfiguration;
import org.junit.jupiter.api.Test;
import org.springframework.boot.autoconfigure.AutoConfigurations;
import org.springframework.boot.test.context.runner.ApplicationContextRunner;
class SpanExporterAutoConfigurationTest {
private final ApplicationContextRunner contextRunner =
new ApplicationContextRunner()
.withConfiguration(
AutoConfigurations.of(
OpenTelemetryAutoConfiguration.class,
OtlpSpanExporterAutoConfiguration.class,
LoggingSpanExporterAutoConfiguration.class));
@Test
void defaultConfiguration() {
contextRunner.run(
context -> {
assertThat(context.getBean("otelOtlpSpanExporter", OtlpHttpSpanExporter.class))
.as("OTLP exporter is enabled by default")
.isNotNull();
assertThat(context.containsBean("otelLoggingSpanExporter"))
.as("Logging exporter is not created unless explicitly configured")
.isFalse();
});
}
@Test
void loggingEnabledByConfiguration() {
contextRunner
.withPropertyValues("otel.traces.exporter=logging,otlp")
.run(
context -> {
assertThat(context.getBean("otelOtlpSpanExporter", OtlpHttpSpanExporter.class))
.as("OTLP exporter is present even with logging enabled")
.isNotNull();
assertThat(context.getBean("otelLoggingSpanExporter", LoggingSpanExporter.class))
.as("Logging exporter is explicitly enabled")
.isNotNull();
});
}
}

View File

@ -1,47 +0,0 @@
/*
* Copyright The OpenTelemetry Authors
* SPDX-License-Identifier: Apache-2.0
*/
package io.opentelemetry.instrumentation.spring.autoconfigure.exporters.logging;
import static org.assertj.core.api.Assertions.assertThat;
import io.opentelemetry.exporter.logging.LoggingMetricExporter;
import io.opentelemetry.instrumentation.spring.autoconfigure.OpenTelemetryAutoConfiguration;
import org.junit.jupiter.api.Test;
import org.springframework.boot.autoconfigure.AutoConfigurations;
import org.springframework.boot.test.context.runner.ApplicationContextRunner;
class LoggingMetricExporterAutoConfigurationTest {
private final ApplicationContextRunner runner =
new ApplicationContextRunner()
.withConfiguration(
AutoConfigurations.of(
OpenTelemetryAutoConfiguration.class,
LoggingMetricExporterAutoConfiguration.class));
@Test
void enabled() {
runner
.withPropertyValues("otel.metrics.exporter=logging")
.run(
context ->
assertThat(
context.getBean("otelLoggingMetricExporter", LoggingMetricExporter.class))
.isNotNull());
}
@Test
void disabled() {
runner
.withPropertyValues("otel.metrics.exporter=none")
.run(context -> assertThat(context.containsBean("otelOtlpMetricExporter")).isFalse());
}
@Test
void noProperties() {
runner.run(context -> assertThat(context.containsBean("otelLoggingMetricExporter")).isFalse());
}
}

View File

@ -1,47 +0,0 @@
/*
* Copyright The OpenTelemetry Authors
* SPDX-License-Identifier: Apache-2.0
*/
package io.opentelemetry.instrumentation.spring.autoconfigure.exporters.logging;
import static org.assertj.core.api.Assertions.assertThat;
import io.opentelemetry.exporter.logging.LoggingSpanExporter;
import io.opentelemetry.instrumentation.spring.autoconfigure.OpenTelemetryAutoConfiguration;
import org.junit.jupiter.api.Test;
import org.springframework.boot.autoconfigure.AutoConfigurations;
import org.springframework.boot.test.context.runner.ApplicationContextRunner;
/** Spring Boot auto configuration test for {@link LoggingSpanExporter}. */
class LoggingSpanExporterAutoConfigurationTest {
private final ApplicationContextRunner runner =
new ApplicationContextRunner()
.withConfiguration(
AutoConfigurations.of(
OpenTelemetryAutoConfiguration.class,
LoggingSpanExporterAutoConfiguration.class));
@Test
void enabled() {
runner
.withPropertyValues("otel.traces.exporter=logging")
.run(
context ->
assertThat(context.getBean("otelLoggingSpanExporter", LoggingSpanExporter.class))
.isNotNull());
}
@Test
void disabled() {
runner
.withPropertyValues("otel.traces.exporter=none")
.run(context -> assertThat(context.containsBean("otelOtlpMetricExporter")).isFalse());
}
@Test
void noProperties() {
runner.run(context -> assertThat(context.containsBean("otelLoggingSpanExporter")).isFalse());
}
}

View File

@ -1,49 +0,0 @@
/*
* Copyright The OpenTelemetry Authors
* SPDX-License-Identifier: Apache-2.0
*/
package io.opentelemetry.instrumentation.spring.autoconfigure.exporters.logging;
import static org.assertj.core.api.Assertions.assertThat;
import io.opentelemetry.exporter.logging.SystemOutLogRecordExporter;
import io.opentelemetry.instrumentation.spring.autoconfigure.OpenTelemetryAutoConfiguration;
import org.junit.jupiter.api.Test;
import org.springframework.boot.autoconfigure.AutoConfigurations;
import org.springframework.boot.test.context.runner.ApplicationContextRunner;
/** Spring Boot auto configuration test for {@link SystemOutLogRecordExporter}. */
class SystemOutLogRecordExporterAutoConfigurationTest {
private final ApplicationContextRunner runner =
new ApplicationContextRunner()
.withConfiguration(
AutoConfigurations.of(
OpenTelemetryAutoConfiguration.class,
SystemOutLogRecordExporterAutoConfiguration.class));
@Test
void enabled() {
runner
.withPropertyValues("otel.logs.exporter=logging")
.run(
context ->
assertThat(
context.getBean(
"otelSystemOutLogRecordExporter", SystemOutLogRecordExporter.class))
.isNotNull());
}
@Test
void disabled() {
runner
.withPropertyValues("otel.logs.exporter=none")
.run(context -> assertThat(context.containsBean("otelOtlpMetricExporter")).isFalse());
}
@Test
void noProperties() {
runner.run(context -> assertThat(context.containsBean("otelLoggingSpanExporter")).isFalse());
}
}

View File

@ -1,30 +0,0 @@
/*
* Copyright The OpenTelemetry Authors
* SPDX-License-Identifier: Apache-2.0
*/
package io.opentelemetry.instrumentation.spring.autoconfigure.exporters.otlp;
import static org.assertj.core.api.Assertions.assertThat;
import io.opentelemetry.instrumentation.spring.autoconfigure.OpenTelemetryAutoConfiguration;
import org.junit.jupiter.api.Test;
import org.springframework.boot.autoconfigure.AutoConfigurations;
import org.springframework.boot.test.context.runner.ApplicationContextRunner;
class OtlpLogExporterAutoConfigurationTest {
private final ApplicationContextRunner runner =
new ApplicationContextRunner()
.withConfiguration(
AutoConfigurations.of(
OpenTelemetryAutoConfiguration.class,
OtlpLogRecordExporterAutoConfiguration.class));
@Test
void otlpDisabled() {
runner
.withPropertyValues("otel.logs.exporter=none")
.run(context -> assertThat(context.containsBean("otelOtlpLogRecordExporter")).isFalse());
}
}

View File

@ -1,29 +0,0 @@
/*
* Copyright The OpenTelemetry Authors
* SPDX-License-Identifier: Apache-2.0
*/
package io.opentelemetry.instrumentation.spring.autoconfigure.exporters.otlp;
import static org.assertj.core.api.Assertions.assertThat;
import io.opentelemetry.instrumentation.spring.autoconfigure.OpenTelemetryAutoConfiguration;
import org.junit.jupiter.api.Test;
import org.springframework.boot.autoconfigure.AutoConfigurations;
import org.springframework.boot.test.context.runner.ApplicationContextRunner;
class OtlpMetricExporterAutoConfigurationTest {
private final ApplicationContextRunner runner =
new ApplicationContextRunner()
.withConfiguration(
AutoConfigurations.of(
OpenTelemetryAutoConfiguration.class, OtlpMetricExporterAutoConfiguration.class));
@Test
void otlpDisabled() {
runner
.withPropertyValues("otel.metrics.exporter=none")
.run(context -> assertThat(context.containsBean("otelOtlpMetricExporter")).isFalse());
}
}

View File

@ -1,30 +0,0 @@
/*
* Copyright The OpenTelemetry Authors
* SPDX-License-Identifier: Apache-2.0
*/
package io.opentelemetry.instrumentation.spring.autoconfigure.exporters.otlp;
import static org.assertj.core.api.Assertions.assertThat;
import io.opentelemetry.instrumentation.spring.autoconfigure.OpenTelemetryAutoConfiguration;
import org.junit.jupiter.api.Test;
import org.springframework.boot.autoconfigure.AutoConfigurations;
import org.springframework.boot.test.context.runner.ApplicationContextRunner;
/** Spring Boot auto configuration test for {@link OtlpSpanExporterAutoConfiguration}. */
class OtlpSpanExporterAutoConfigurationTest {
private final ApplicationContextRunner contextRunner =
new ApplicationContextRunner()
.withConfiguration(
AutoConfigurations.of(
OpenTelemetryAutoConfiguration.class, OtlpSpanExporterAutoConfiguration.class));
@Test
void otlpDisabled() {
contextRunner
.withPropertyValues("otel.traces.exporter=none")
.run(context -> assertThat(context.containsBean("otelOtlpSpanExporter")).isFalse());
}
}

View File

@ -1,70 +0,0 @@
/*
* Copyright The OpenTelemetry Authors
* SPDX-License-Identifier: Apache-2.0
*/
package io.opentelemetry.instrumentation.spring.autoconfigure.exporters.zipkin;
import static org.assertj.core.api.Assertions.assertThat;
import io.opentelemetry.exporter.zipkin.ZipkinSpanExporter;
import io.opentelemetry.instrumentation.spring.autoconfigure.OpenTelemetryAutoConfiguration;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import org.springframework.boot.autoconfigure.AutoConfigurations;
import org.springframework.boot.test.context.runner.ApplicationContextRunner;
/** Spring Boot auto configuration test for {@link ZipkinSpanExporter}. */
class ZipkinSpanExporterAutoConfigurationTest {
private final ApplicationContextRunner contextRunner =
new ApplicationContextRunner()
.withConfiguration(
AutoConfigurations.of(
OpenTelemetryAutoConfiguration.class, ZipkinSpanExporterAutoConfiguration.class));
@Test
@DisplayName("when exporters are ENABLED should initialize ZipkinSpanExporter bean")
void exportersEnabled() {
this.contextRunner
.withPropertyValues("otel.traces.exporter=zipkin")
.run(
context ->
assertThat(context.getBean("otelZipkinSpanExporter", ZipkinSpanExporter.class))
.isNotNull());
}
@Test
@DisplayName(
"when otel.exporter.zipkin properties are set should initialize ZipkinSpanExporterProperties with property values")
void handlesProperties() {
this.contextRunner
.withPropertyValues(
"otel.traces.exporter=zipkin",
"otel.exporter.zipkin.endpoint=http://localhost:8080/test")
.run(
context -> {
ZipkinSpanExporterProperties zipkinSpanExporterProperties =
context.getBean(ZipkinSpanExporterProperties.class);
assertThat(zipkinSpanExporterProperties.getEndpoint())
.isEqualTo("http://localhost:8080/test");
});
}
@Test
@DisplayName("when exporters are DISABLED should NOT initialize ZipkinSpanExporter bean")
void disabledProperty() {
this.contextRunner
.withPropertyValues("otel.traces.exporter=none")
.run(context -> assertThat(context.containsBean("otelZipkinSpanExporter")).isFalse());
}
@Test
@DisplayName("when zipkin enabled property is MISSING should initialize ZipkinSpanExporter bean")
void noProperty() {
this.contextRunner.run(
context ->
assertThat(context.getBean("otelZipkinSpanExporter", ZipkinSpanExporter.class))
.isNotNull());
}
}

View File

@ -1,121 +0,0 @@
/*
* Copyright The OpenTelemetry Authors
* SPDX-License-Identifier: Apache-2.0
*/
package io.opentelemetry.instrumentation.spring.autoconfigure.propagators;
import static org.assertj.core.api.Assertions.assertThat;
import io.opentelemetry.context.propagation.TextMapPropagator;
import io.opentelemetry.instrumentation.spring.autoconfigure.OpenTelemetryAutoConfiguration;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import org.springframework.boot.autoconfigure.AutoConfigurations;
import org.springframework.boot.test.context.runner.ApplicationContextRunner;
class PropagationAutoConfigurationTest {
private final ApplicationContextRunner contextRunner =
new ApplicationContextRunner()
.withConfiguration(
AutoConfigurations.of(
OpenTelemetryAutoConfiguration.class, PropagationAutoConfiguration.class));
@Test
@DisplayName("when propagation is ENABLED should initialize PropagationAutoConfiguration bean")
void shouldBeConfigured() {
this.contextRunner
.withPropertyValues("otel.propagation.enabled=true")
.run(context -> assertThat(context.containsBean("propagationAutoConfiguration")).isTrue());
}
@Test
@DisplayName(
"when propagation is DISABLED should NOT initialize PropagationAutoConfiguration bean")
void shouldNotBeConfigured() {
this.contextRunner
.withPropertyValues("otel.propagation.enabled=false")
.run(context -> assertThat(context.containsBean("propagationAutoConfiguration")).isFalse());
}
@Test
@DisplayName(
"when propagation enabled property is MISSING should initialize PropagationAutoConfiguration bean")
void noProperty() {
this.contextRunner.run(
context -> assertThat(context.containsBean("propagationAutoConfiguration")).isTrue());
}
@Test
@DisplayName("when no propagators are defined should contain default propagators")
void shouldContainDefaults() {
this.contextRunner.run(
context ->
assertThat(
context.getBean("compositeTextMapPropagator", TextMapPropagator.class).fields())
.contains("traceparent", "baggage"));
}
@Test
@DisplayName("when propagation is set to b3 should contain only b3 propagator")
void shouldContainB3() {
this.contextRunner
.withPropertyValues("otel.propagators=b3")
.run(
context -> {
TextMapPropagator compositePropagator =
context.getBean("compositeTextMapPropagator", TextMapPropagator.class);
assertThat(compositePropagator.fields())
.contains("b3")
.doesNotContain("baggage", "traceparent");
});
}
@Test
@DisplayName("when propagation is set to unsupported value should create an empty propagator")
void shouldCreateNoop() {
this.contextRunner
.withPropertyValues("otel.propagators=invalid")
.run(
context -> {
TextMapPropagator compositePropagator =
context.getBean("compositeTextMapPropagator", TextMapPropagator.class);
assertThat(compositePropagator.fields()).isEmpty();
});
}
@Test
@DisplayName("when propagation is set to some values should contain only supported values - List")
void shouldContainOnlySupportedList() {
this.contextRunner
.withPropertyValues("otel.propagators=invalid,b3")
.run(
context -> {
TextMapPropagator compositePropagator =
context.getBean("compositeTextMapPropagator", TextMapPropagator.class);
assertThat(compositePropagator.fields()).containsExactly("b3");
});
}
@Test
@DisplayName("when propagation is set to some values should contain only supported values")
void shouldContainOnlySupported() {
this.contextRunner
.withPropertyValues("otel.propagators=invalid,b3")
.run(
context -> {
TextMapPropagator compositePropagator =
context.getBean("compositeTextMapPropagator", TextMapPropagator.class);
assertThat(compositePropagator.fields()).containsExactly("b3");
});
}
}

View File

@ -3,18 +3,16 @@
* SPDX-License-Identifier: Apache-2.0
*/
package io.opentelemetry.instrumentation.spring.autoconfigure.exporters.otlp;
package io.opentelemetry.instrumentation.spring.autoconfigure.properties;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.entry;
import io.opentelemetry.instrumentation.spring.autoconfigure.OpenTelemetryAutoConfiguration;
import io.opentelemetry.instrumentation.spring.autoconfigure.propagators.PropagationProperties;
import io.opentelemetry.instrumentation.spring.autoconfigure.resources.OtelResourceAutoConfiguration;
import io.opentelemetry.instrumentation.spring.autoconfigure.resources.OtelResourceProperties;
import io.opentelemetry.instrumentation.spring.autoconfigure.resources.SpringConfigProperties;
import io.opentelemetry.sdk.autoconfigure.spi.ConfigProperties;
import io.opentelemetry.sdk.autoconfigure.spi.internal.DefaultConfigProperties;
import java.util.Arrays;
import java.util.Collections;
import java.util.stream.Stream;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
@ -38,9 +36,9 @@ class OtlpExporterPropertiesTest {
private final ApplicationContextRunner contextRunner =
new ApplicationContextRunner()
.withConfiguration(
AutoConfigurations.of(
OpenTelemetryAutoConfiguration.class, OtelResourceAutoConfiguration.class));
.withConfiguration(AutoConfigurations.of(OpenTelemetryAutoConfiguration.class))
.withPropertyValues(
"otel.traces.exporter=none", "otel.metrics.exporter=none", "otel.logs.exporter=none");
public static Stream<Arguments> headerKeys() {
return Arrays.stream(HEADER_KEYS).map(Arguments::of);
@ -94,6 +92,7 @@ class OtlpExporterPropertiesTest {
new SpelExpressionParser(),
context.getBean(OtlpExporterProperties.class),
new OtelResourceProperties(),
new PropagationProperties());
new PropagationProperties(),
DefaultConfigProperties.createFromMap(Collections.emptyMap()));
}
}

View File

@ -9,6 +9,7 @@ import static org.assertj.core.api.Assertions.assertThat;
import com.google.common.collect.ImmutableMap;
import io.opentelemetry.api.common.AttributeKey;
import io.opentelemetry.instrumentation.spring.autoconfigure.OpenTelemetryAutoConfiguration;
import io.opentelemetry.sdk.autoconfigure.spi.ResourceProvider;
import io.opentelemetry.sdk.autoconfigure.spi.internal.DefaultConfigProperties;
import org.junit.jupiter.api.DisplayName;
@ -19,7 +20,9 @@ import org.springframework.boot.test.context.runner.ApplicationContextRunner;
public class DistroVersionResourceProviderTest {
private final ApplicationContextRunner contextRunner =
new ApplicationContextRunner()
.withConfiguration(AutoConfigurations.of(OtelResourceAutoConfiguration.class));
.withPropertyValues(
"otel.traces.exporter=none", "otel.metrics.exporter=none", "otel.logs.exporter=none")
.withConfiguration(AutoConfigurations.of(OpenTelemetryAutoConfiguration.class));
@Test
@DisplayName("distro version should be set")

View File

@ -1,48 +0,0 @@
/*
* Copyright The OpenTelemetry Authors
* SPDX-License-Identifier: Apache-2.0
*/
package io.opentelemetry.instrumentation.spring.autoconfigure.resources;
import static org.assertj.core.api.Assertions.assertThat;
import io.opentelemetry.instrumentation.spring.autoconfigure.OpenTelemetryAutoConfiguration;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import org.springframework.boot.autoconfigure.AutoConfigurations;
import org.springframework.boot.test.context.runner.ApplicationContextRunner;
public class OtelResourceAutoConfigurationTest {
private final ApplicationContextRunner contextRunner =
new ApplicationContextRunner()
.withConfiguration(
AutoConfigurations.of(
OtelResourceAutoConfiguration.class, OpenTelemetryAutoConfiguration.class));
@Test
@DisplayName(
"when otel.springboot.resource.enabled is set to true configuration should be initialized")
void shouldDetermineServiceNameByOtelServiceName() {
this.contextRunner
.withPropertyValues("otel.springboot.resource.enabled=true")
.run(context -> assertThat(context.containsBean("otelSpringResourceProvider")).isTrue());
}
@Test
@DisplayName(
"when otel.springboot.resource.enabled is not specified configuration should be initialized")
void shouldInitAutoConfigurationByDefault() {
this.contextRunner.run(
context -> assertThat(context.containsBean("otelSpringResourceProvider")).isTrue());
}
@Test
@DisplayName(
"when otel.springboot.resource.enabled is set to false configuration should NOT be initialized")
void shouldNotInitAutoConfiguration() {
this.contextRunner
.withPropertyValues("otel.springboot.resource.enabled=false")
.run(context -> assertThat(context.containsBean("otelSpringResourceProvider")).isFalse());
}
}

View File

@ -8,8 +8,13 @@ package io.opentelemetry.instrumentation.spring.autoconfigure.resources;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.entry;
import io.opentelemetry.instrumentation.spring.autoconfigure.exporters.otlp.OtlpExporterProperties;
import io.opentelemetry.instrumentation.spring.autoconfigure.propagators.PropagationProperties;
import io.opentelemetry.instrumentation.spring.autoconfigure.properties.OtelResourceProperties;
import io.opentelemetry.instrumentation.spring.autoconfigure.properties.OtlpExporterProperties;
import io.opentelemetry.instrumentation.spring.autoconfigure.properties.PropagationProperties;
import io.opentelemetry.instrumentation.spring.autoconfigure.properties.SpringConfigProperties;
import io.opentelemetry.sdk.autoconfigure.spi.internal.DefaultConfigProperties;
import java.util.HashMap;
import java.util.Map;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.runner.ApplicationContextRunner;
@ -28,19 +33,26 @@ class SpringConfigPropertiesTest {
.run(
context -> {
Environment env = context.getBean("environment", Environment.class);
Map<String, String> fallback = new HashMap<>();
fallback.put("fallback", "fallbackVal");
fallback.put("otel.springboot.test.map", "hidden");
SpringConfigProperties config =
new SpringConfigProperties(
env,
new SpelExpressionParser(),
new OtlpExporterProperties(),
new OtelResourceProperties(),
new PropagationProperties());
new PropagationProperties(),
DefaultConfigProperties.createFromMap(fallback));
assertThat(config.getMap("otel.springboot.test.map"))
.contains(
entry("environment", "dev"),
entry("xyz", "foo"),
entry("service.instance.id", "id-example"));
assertThat(config.getString("fallback")).isEqualTo("fallbackVal");
});
}
}

View File

@ -7,58 +7,33 @@ package io.opentelemetry.instrumentation.spring.autoconfigure.resources;
import static io.opentelemetry.semconv.ResourceAttributes.SERVICE_NAME;
import static io.opentelemetry.semconv.ResourceAttributes.SERVICE_VERSION;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.entry;
import com.google.common.collect.ImmutableMap;
import io.opentelemetry.api.common.AttributeKey;
import io.opentelemetry.instrumentation.spring.autoconfigure.OpenTelemetryAutoConfiguration;
import io.opentelemetry.sdk.autoconfigure.spi.ResourceProvider;
import io.opentelemetry.instrumentation.spring.autoconfigure.properties.OtelResourceProperties;
import io.opentelemetry.instrumentation.spring.autoconfigure.properties.OtlpExporterProperties;
import io.opentelemetry.instrumentation.spring.autoconfigure.properties.PropagationProperties;
import io.opentelemetry.instrumentation.spring.autoconfigure.properties.SpringConfigProperties;
import io.opentelemetry.sdk.autoconfigure.spi.ConfigProperties;
import io.opentelemetry.sdk.autoconfigure.spi.internal.DefaultConfigProperties;
import io.opentelemetry.sdk.resources.Resource;
import io.opentelemetry.sdk.testing.assertj.AttributesAssert;
import io.opentelemetry.sdk.testing.assertj.OpenTelemetryAssertions;
import java.util.Collections;
import java.util.Properties;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import org.springframework.boot.autoconfigure.AutoConfigurations;
import org.springframework.boot.info.BuildProperties;
import org.springframework.boot.test.context.assertj.AssertableApplicationContext;
import org.springframework.boot.test.context.runner.ApplicationContextRunner;
import org.springframework.core.env.Environment;
public class SpringResourceProviderTest {
private final ApplicationContextRunner contextRunner =
new ApplicationContextRunner()
.withPropertyValues("otel.springboot.resource.enabled=true")
.withConfiguration(
AutoConfigurations.of(
OtelResourceAutoConfiguration.class, OpenTelemetryAutoConfiguration.class));
@Test
@DisplayName("when attributes are SET should set OtelResourceProperties with given attributes")
void hasAttributes() {
this.contextRunner.run(
context -> {
ResourceProvider resource =
context.getBean("otelSpringResourceProvider", ResourceProvider.class);
assertThat(
resource
.createResource(
DefaultConfigProperties.createFromMap(
ImmutableMap.of("spring.application.name", "backend")))
.getAttributes()
.asMap())
.contains(entry(AttributeKey.stringKey("service.name"), "backend"));
});
}
@Test
@DisplayName("when attributes are DEFAULT should set OtelResourceProperties to default values")
void hasDefaultTypes() {
this.contextRunner.run(
context ->
assertThat(context.getBean(OtelResourceProperties.class).getAttributes()).isEmpty());
}
.withPropertyValues(
"otel.traces.exporter=none", "otel.metrics.exporter=none", "otel.logs.exporter=none")
.withConfiguration(AutoConfigurations.of(OpenTelemetryAutoConfiguration.class));
@Test
@DisplayName(
@ -66,15 +41,9 @@ public class SpringResourceProviderTest {
void shouldDetermineServiceNameBySpringApplicationName() {
this.contextRunner
.withPropertyValues("spring.application.name=myapp-backend")
.withConfiguration(
AutoConfigurations.of(
OtelResourceAutoConfiguration.class, OpenTelemetryAutoConfiguration.class))
.run(
context -> {
Resource otelResource = context.getBean("otelResource", Resource.class);
assertThat(otelResource.getAttribute(SERVICE_NAME)).isEqualTo("myapp-backend");
});
context ->
assertResourceAttributes(context).containsEntry(SERVICE_NAME, "myapp-backend"));
}
@Test
@ -86,47 +55,26 @@ public class SpringResourceProviderTest {
properties.put("version", "0.3");
this.contextRunner
.withBean("buildProperties", BuildProperties.class, () -> new BuildProperties(properties))
.withConfiguration(
AutoConfigurations.of(
OtelResourceAutoConfiguration.class, OpenTelemetryAutoConfiguration.class))
.run(
context -> {
Resource otelResource = context.getBean("otelResource", Resource.class);
assertThat(otelResource.getAttribute(SERVICE_NAME)).isEqualTo("demo");
assertThat(otelResource.getAttribute(SERVICE_VERSION)).isEqualTo("0.3");
});
context ->
assertResourceAttributes(context)
.containsEntry(SERVICE_NAME, "demo")
.containsEntry(SERVICE_VERSION, "0.3"));
}
@Test
@DisplayName(
"when spring application name and otel service name are not set service name should be default")
void hasDefaultServiceName() {
this.contextRunner
.withConfiguration(
AutoConfigurations.of(
OtelResourceAutoConfiguration.class, OpenTelemetryAutoConfiguration.class))
.run(
context -> {
Resource otelResource = context.getBean("otelResource", Resource.class);
private static AttributesAssert assertResourceAttributes(AssertableApplicationContext context) {
ConfigProperties configProperties =
SpringConfigProperties.create(
context.getBean(Environment.class),
new OtlpExporterProperties(),
new OtelResourceProperties(),
new PropagationProperties(),
DefaultConfigProperties.createFromMap(Collections.emptyMap()));
assertThat(otelResource.getAttribute(SERVICE_NAME)).isEqualTo("unknown_service:java");
});
}
@Test
@DisplayName("when otel service name is set it should be set as service name attribute")
void shouldDetermineServiceNameByOtelServiceName() {
this.contextRunner
.withConfiguration(
AutoConfigurations.of(
OtelResourceAutoConfiguration.class, OpenTelemetryAutoConfiguration.class))
.withPropertyValues("otel.resource.attributes.service.name=otel-name-backend")
.run(
context -> {
Resource otelResource = context.getBean("otelResource", Resource.class);
assertThat(otelResource.getAttribute(SERVICE_NAME)).isEqualTo("otel-name-backend");
});
return OpenTelemetryAssertions.assertThat(
context
.getBean(SpringResourceProvider.class)
.createResource(configProperties)
.getAttributes());
}
}

View File

@ -16,6 +16,7 @@ dependencies {
implementation("com.h2database:h2")
implementation("org.apache.commons:commons-dbcp2")
implementation(project(":instrumentation:jdbc:library"))
implementation("io.opentelemetry:opentelemetry-extension-trace-propagators")
implementation(project(":instrumentation:spring:starters:spring-boot-starter"))
implementation(platform(org.springframework.boot.gradle.plugin.SpringBootPlugin.BOM_COORDINATES))

View File

@ -5,3 +5,6 @@ otel:
capture-code-attributes: true
propagators:
- b3
resource:
attributes:
attributeFromYaml: true # boolean will be automatically converted to string by spring

View File

@ -7,13 +7,25 @@ package io.opentelemetry.smoketest;
import static org.assertj.core.api.Assertions.assertThat;
import io.opentelemetry.api.common.AttributeKey;
import io.opentelemetry.api.common.Attributes;
import io.opentelemetry.api.trace.SpanKind;
import io.opentelemetry.instrumentation.spring.autoconfigure.properties.OtelResourceProperties;
import io.opentelemetry.instrumentation.spring.autoconfigure.properties.OtlpExporterProperties;
import io.opentelemetry.instrumentation.spring.autoconfigure.properties.PropagationProperties;
import io.opentelemetry.instrumentation.spring.autoconfigure.properties.SpringConfigProperties;
import io.opentelemetry.sdk.autoconfigure.spi.AutoConfigurationCustomizerProvider;
import io.opentelemetry.sdk.autoconfigure.spi.ConfigProperties;
import io.opentelemetry.sdk.autoconfigure.spi.internal.DefaultConfigProperties;
import io.opentelemetry.sdk.autoconfigure.spi.logs.ConfigurableLogRecordExporterProvider;
import io.opentelemetry.sdk.autoconfigure.spi.metrics.ConfigurableMetricExporterProvider;
import io.opentelemetry.sdk.autoconfigure.spi.traces.ConfigurableSpanExporterProvider;
import io.opentelemetry.sdk.logs.data.LogRecordData;
import io.opentelemetry.sdk.logs.export.LogRecordExporter;
import io.opentelemetry.sdk.metrics.data.AggregationTemporality;
import io.opentelemetry.sdk.metrics.data.MetricData;
import io.opentelemetry.sdk.metrics.export.MetricExporter;
import io.opentelemetry.sdk.resources.Resource;
import io.opentelemetry.sdk.testing.assertj.TracesAssert;
import io.opentelemetry.sdk.testing.exporter.InMemoryLogRecordExporter;
import io.opentelemetry.sdk.testing.exporter.InMemoryMetricExporter;
@ -23,6 +35,7 @@ import io.opentelemetry.sdk.trace.export.SpanExporter;
import io.opentelemetry.semconv.SemanticAttributes;
import io.opentelemetry.spring.smoketest.OtelSpringStarterSmokeTestApplication;
import io.opentelemetry.spring.smoketest.OtelSpringStarterSmokeTestController;
import java.util.Collections;
import java.util.List;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
@ -30,6 +43,8 @@ import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.web.client.TestRestTemplate;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.annotation.Order;
import org.springframework.core.env.Environment;
@SpringBootTest(
classes = {
@ -43,6 +58,9 @@ import org.springframework.context.annotation.Configuration;
"otel.logs.exporter=none",
"otel.metric.export.interval=100",
"otel.exporter.otlp.headers=a=1,b=2",
"otel.traces.exporter=memory",
"otel.metrics.exporter=memory",
"otel.logs.exporter=memory"
// We set the export interval of the metrics to 100 ms. The default value is 1 minute.
// the headers are simply set here to make sure that headers can be parsed
})
@ -56,28 +74,93 @@ class OtelSpringStarterSmokeTest {
@Autowired private TestRestTemplate testRestTemplate;
@Autowired private ConfigProperties configProperties;
@Autowired private Environment environment;
@Autowired private PropagationProperties propagationProperties;
@Autowired private OtelResourceProperties otelResourceProperties;
@Autowired private OtlpExporterProperties otlpExporterProperties;
@Configuration(proxyBeanMethods = false)
static class TestConfiguration {
@Bean
public MetricExporter metricExporter() {
return METRIC_EXPORTER;
ConfigurableMetricExporterProvider otlpMetricExporterProvider() {
return new ConfigurableMetricExporterProvider() {
@Override
public MetricExporter createExporter(ConfigProperties configProperties) {
return METRIC_EXPORTER;
}
@Override
public String getName() {
return "memory";
}
};
}
@Bean
public SpanExporter spanExporter() {
return SPAN_EXPORTER;
ConfigurableSpanExporterProvider otlpSpanExporterProvider() {
return new ConfigurableSpanExporterProvider() {
@Override
public SpanExporter createExporter(ConfigProperties configProperties) {
return SPAN_EXPORTER;
}
@Override
public String getName() {
return "memory";
}
};
}
@Bean
public LogRecordExporter logRecordExporter() {
return LOG_RECORD_EXPORTER;
ConfigurableLogRecordExporterProvider otlpLogRecordExporterProvider() {
return new ConfigurableLogRecordExporterProvider() {
@Override
public LogRecordExporter createExporter(ConfigProperties configProperties) {
return LOG_RECORD_EXPORTER;
}
@Override
public String getName() {
return "memory";
}
};
}
@Bean
@Order(1)
AutoConfigurationCustomizerProvider hiddenPropagatorCustomizer() {
return customizer ->
customizer.addResourceCustomizer(
(resource, config) ->
resource.merge(
Resource.create(
Attributes.of(
AttributeKey.booleanKey("keyFromResourceCustomizer"), false))));
}
@Bean
@Order(2)
AutoConfigurationCustomizerProvider propagatorCustomizer() {
return customizer ->
customizer.addResourceCustomizer(
(resource, config) ->
resource.merge(
Resource.create(
Attributes.of(
AttributeKey.booleanKey("keyFromResourceCustomizer"), true))));
}
}
@Test
void propertyConversion() {
ConfigProperties configProperties =
SpringConfigProperties.create(
environment,
otlpExporterProperties,
otelResourceProperties,
propagationProperties,
DefaultConfigProperties.createFromMap(Collections.emptyMap()));
assertThat(configProperties.getMap("otel.exporter.otlp.headers"))
.containsEntry("a", "1")
.containsEntry("b", "2");
@ -111,6 +194,13 @@ class OtelSpringStarterSmokeTest {
spanDataAssert ->
spanDataAssert
.hasKind(SpanKind.SERVER)
.hasResourceSatisfying(
r ->
r.hasAttribute(
AttributeKey.booleanKey("keyFromResourceCustomizer"),
true)
.hasAttribute(
AttributeKey.stringKey("attributeFromYaml"), "true"))
.hasAttribute(SemanticAttributes.HTTP_REQUEST_METHOD, "GET")
.hasAttribute(SemanticAttributes.HTTP_RESPONSE_STATUS_CODE, 200L)
.hasAttribute(SemanticAttributes.HTTP_ROUTE, "/ping")));