Add metrics & micrometer support to spring-boot-autoconfigure (#6270)

* Add metrics & micrometer support to spring-boot-autoconfigure

* Apply suggestions from code review

Co-authored-by: Trask Stalnaker <trask.stalnaker@gmail.com>

* code review comments

Co-authored-by: Trask Stalnaker <trask.stalnaker@gmail.com>
This commit is contained in:
Mateusz Rzeszutek 2022-07-07 16:51:25 +02:00 committed by GitHub
parent 646a724a38
commit 9058ad6f40
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
19 changed files with 597 additions and 71 deletions

View File

@ -14,7 +14,10 @@ muzzle {
dependencies {
library("io.micrometer:micrometer-core:1.5.0")
implementation("io.opentelemetry:opentelemetry-micrometer1-shim")
implementation("io.opentelemetry:opentelemetry-micrometer1-shim") {
// just get the instrumentation, without micrometer itself
exclude("io.micrometer", "micrometer-core")
}
}
tasks {

View File

@ -6,21 +6,27 @@ plugins {
group = "io.opentelemetry.instrumentation"
val versions: Map<String, String> by project
val springBootVersion = versions["org.springframework.boot"]
dependencies {
implementation(project(":instrumentation-api-annotation-support"))
implementation("org.springframework.boot:spring-boot-autoconfigure:${versions["org.springframework.boot"]}")
annotationProcessor("org.springframework.boot:spring-boot-autoconfigure-processor:${versions["org.springframework.boot"]}")
implementation("org.springframework.boot:spring-boot-autoconfigure:$springBootVersion")
annotationProcessor("org.springframework.boot:spring-boot-autoconfigure-processor:$springBootVersion")
implementation("javax.validation:validation-api:2.0.1.Final")
implementation(project(":instrumentation:spring:spring-web-3.1:library"))
implementation(project(":instrumentation:spring:spring-webmvc-3.1:library"))
implementation(project(":instrumentation:spring:spring-webflux-5.0:library"))
implementation("io.opentelemetry:opentelemetry-micrometer1-shim") {
// just get the instrumentation, without micrometer itself
exclude("io.micrometer", "micrometer-core")
}
compileOnly("org.springframework.boot:spring-boot-starter-aop:${versions["org.springframework.boot"]}")
compileOnly("org.springframework.boot:spring-boot-starter-web:${versions["org.springframework.boot"]}")
compileOnly("org.springframework.boot:spring-boot-starter-webflux:${versions["org.springframework.boot"]}")
compileOnly("org.springframework.boot:spring-boot-starter-actuator:$springBootVersion")
compileOnly("org.springframework.boot:spring-boot-starter-aop:$springBootVersion")
compileOnly("org.springframework.boot:spring-boot-starter-web:$springBootVersion")
compileOnly("org.springframework.boot:spring-boot-starter-webflux:$springBootVersion")
compileOnly("io.opentelemetry:opentelemetry-sdk-extension-autoconfigure-spi")
compileOnly("io.opentelemetry:opentelemetry-extension-annotations")
@ -32,10 +38,11 @@ dependencies {
compileOnly("io.opentelemetry:opentelemetry-exporter-otlp")
compileOnly("io.opentelemetry:opentelemetry-exporter-zipkin")
testImplementation("org.springframework.boot:spring-boot-starter-aop:${versions["org.springframework.boot"]}")
testImplementation("org.springframework.boot:spring-boot-starter-webflux:${versions["org.springframework.boot"]}")
testImplementation("org.springframework.boot:spring-boot-starter-web:${versions["org.springframework.boot"]}")
testImplementation("org.springframework.boot:spring-boot-starter-test:${versions["org.springframework.boot"]}") {
testImplementation("org.springframework.boot:spring-boot-starter-actuator:$springBootVersion")
testImplementation("org.springframework.boot:spring-boot-starter-aop:$springBootVersion")
testImplementation("org.springframework.boot:spring-boot-starter-webflux:$springBootVersion")
testImplementation("org.springframework.boot:spring-boot-starter-web:$springBootVersion")
testImplementation("org.springframework.boot:spring-boot-starter-test:$springBootVersion") {
exclude("org.junit.vintage", "junit-vintage-engine")
}

View File

@ -0,0 +1,25 @@
/*
* Copyright The OpenTelemetry Authors
* SPDX-License-Identifier: Apache-2.0
*/
package io.opentelemetry.instrumentation.spring.autoconfigure;
import java.time.Duration;
import javax.annotation.Nullable;
import org.springframework.boot.context.properties.ConfigurationProperties;
@ConfigurationProperties(prefix = "otel.metric.export")
public class MetricExportProperties {
@Nullable private Duration interval;
@Nullable
public Duration getInterval() {
return interval;
}
public void setInterval(@Nullable Duration interval) {
this.interval = interval;
}
}

View File

@ -12,6 +12,11 @@ import io.opentelemetry.instrumentation.spring.autoconfigure.resources.SpringRes
import io.opentelemetry.sdk.OpenTelemetrySdk;
import io.opentelemetry.sdk.autoconfigure.spi.ConfigProperties;
import io.opentelemetry.sdk.autoconfigure.spi.ResourceProvider;
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;
@ -36,7 +41,7 @@ import org.springframework.expression.spel.standard.SpelExpressionParser;
* <p>Updates the sampler probability for the configured {@link TracerProvider}.
*/
@Configuration
@EnableConfigurationProperties(SamplerProperties.class)
@EnableConfigurationProperties({MetricExportProperties.class, SamplerProperties.class})
public class OpenTelemetryAutoConfiguration {
@Configuration
@ -61,6 +66,32 @@ public class OpenTelemetryAutoConfiguration {
.build();
}
@Bean
@ConditionalOnMissingBean
public SdkMeterProvider sdkMeterProvider(
MetricExportProperties properties,
ObjectProvider<List<MetricExporter>> metricExportersProvider,
Resource otelResource) {
SdkMeterProviderBuilder meterProviderBuilder = SdkMeterProvider.builder();
metricExportersProvider.getIfAvailable(Collections::emptyList).stream()
.map(metricExporter -> createPeriodicMetricReader(properties, metricExporter))
.forEach(meterProviderBuilder::registerMetricReader);
return meterProviderBuilder.setResource(otelResource).build();
}
private static PeriodicMetricReader createPeriodicMetricReader(
MetricExportProperties properties, MetricExporter metricExporter) {
PeriodicMetricReaderBuilder metricReaderBuilder =
PeriodicMetricReader.builder(metricExporter);
if (properties.getInterval() != null) {
metricReaderBuilder.setInterval(properties.getInterval());
}
return metricReaderBuilder.build();
}
@Bean
@ConditionalOnMissingBean
public Resource otelResource(
@ -76,12 +107,15 @@ public class OpenTelemetryAutoConfiguration {
@Bean
public OpenTelemetry openTelemetry(
ObjectProvider<ContextPropagators> propagatorsProvider, SdkTracerProvider tracerProvider) {
ObjectProvider<ContextPropagators> propagatorsProvider,
SdkTracerProvider tracerProvider,
SdkMeterProvider meterProvider) {
ContextPropagators propagators = propagatorsProvider.getIfAvailable(ContextPropagators::noop);
return OpenTelemetrySdk.builder()
.setTracerProvider(tracerProvider)
.setMeterProvider(meterProvider)
.setPropagators(propagators)
.build();
}

View File

@ -0,0 +1,49 @@
/*
* Copyright The OpenTelemetry Authors
* SPDX-License-Identifier: Apache-2.0
*/
package io.opentelemetry.instrumentation.spring.autoconfigure.exporters.logging;
import org.springframework.boot.context.properties.ConfigurationProperties;
/**
* Configuration for {@link io.opentelemetry.exporter.logging.LoggingSpanExporter} and {@link
* io.opentelemetry.exporter.logging.LoggingMetricExporter}.
*/
@ConfigurationProperties(prefix = "otel.exporter.logging")
public final class LoggingExporterProperties {
private boolean enabled = true;
private final SignalProperties traces = new SignalProperties();
private final SignalProperties metrics = new SignalProperties();
public boolean isEnabled() {
return enabled;
}
public void setEnabled(boolean enabled) {
this.enabled = enabled;
}
public SignalProperties getTraces() {
return traces;
}
public SignalProperties getMetrics() {
return metrics;
}
public static class SignalProperties {
private boolean enabled = true;
public boolean isEnabled() {
return enabled;
}
public void setEnabled(boolean enabled) {
this.enabled = enabled;
}
}
}

View File

@ -0,0 +1,35 @@
/*
* 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.exporter.logging.LoggingSpanExporter;
import io.opentelemetry.instrumentation.spring.autoconfigure.OpenTelemetryAutoConfiguration;
import org.springframework.boot.autoconfigure.AutoConfigureBefore;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
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.Configuration;
/** Configures {@link LoggingSpanExporter} bean for tracing. */
@Configuration
@EnableConfigurationProperties(LoggingExporterProperties.class)
@AutoConfigureBefore(OpenTelemetryAutoConfiguration.class)
@ConditionalOnProperty(
prefix = "otel.exporter.logging",
name = {"enabled", "metrics.enabled"},
matchIfMissing = true)
@ConditionalOnClass(LoggingMetricExporter.class)
public class LoggingMetricExporterAutoConfiguration {
@Bean
@ConditionalOnMissingBean
public LoggingMetricExporter otelLoggingMetricExporter() {
return LoggingMetricExporter.create();
}
}

View File

@ -17,9 +17,12 @@ import org.springframework.context.annotation.Configuration;
/** Configures {@link LoggingSpanExporter} bean for tracing. */
@Configuration
@EnableConfigurationProperties(LoggingSpanExporterProperties.class)
@EnableConfigurationProperties(LoggingExporterProperties.class)
@AutoConfigureBefore(OpenTelemetryAutoConfiguration.class)
@ConditionalOnProperty(prefix = "otel.exporter.logging", name = "enabled", matchIfMissing = true)
@ConditionalOnProperty(
prefix = "otel.exporter.logging",
name = {"enabled", "traces.enabled"},
matchIfMissing = true)
@ConditionalOnClass(LoggingSpanExporter.class)
public class LoggingSpanExporterAutoConfiguration {

View File

@ -10,7 +10,8 @@ import javax.annotation.Nullable;
import org.springframework.boot.context.properties.ConfigurationProperties;
/**
* Configuration for {@link io.opentelemetry.exporter.otlp.trace.OtlpGrpcSpanExporter}.
* Configuration for {@link io.opentelemetry.exporter.otlp.trace.OtlpGrpcSpanExporter} and {@link
* io.opentelemetry.exporter.otlp.metrics.OtlpGrpcMetricExporter}.
*
* <p>Get Exporter Service Name
*
@ -19,11 +20,13 @@ import org.springframework.boot.context.properties.ConfigurationProperties;
* <p>Get max wait time for Collector to process Span Batches
*/
@ConfigurationProperties(prefix = "otel.exporter.otlp")
public final class OtlpGrpcSpanExporterProperties {
public final class OtlpExporterProperties {
private boolean enabled = true;
@Nullable private String endpoint;
@Nullable private Duration timeout;
private final SignalProperties traces = new SignalProperties();
private final SignalProperties metrics = new SignalProperties();
public boolean isEnabled() {
return enabled;
@ -50,4 +53,45 @@ public final class OtlpGrpcSpanExporterProperties {
public void setTimeout(Duration timeout) {
this.timeout = timeout;
}
public SignalProperties getTraces() {
return traces;
}
public SignalProperties getMetrics() {
return metrics;
}
public static class SignalProperties {
private boolean enabled = true;
@Nullable private String endpoint;
@Nullable private Duration timeout;
public boolean isEnabled() {
return enabled;
}
public void setEnabled(boolean enabled) {
this.enabled = enabled;
}
@Nullable
public String getEndpoint() {
return endpoint;
}
public void setEndpoint(@Nullable String endpoint) {
this.endpoint = endpoint;
}
@Nullable
public Duration getTimeout() {
return timeout;
}
public void setTimeout(@Nullable Duration timeout) {
this.timeout = timeout;
}
}
}

View File

@ -0,0 +1,53 @@
/*
* Copyright The OpenTelemetry Authors
* SPDX-License-Identifier: Apache-2.0
*/
package io.opentelemetry.instrumentation.spring.autoconfigure.exporters.otlp;
import io.opentelemetry.exporter.otlp.metrics.OtlpGrpcMetricExporter;
import io.opentelemetry.exporter.otlp.metrics.OtlpGrpcMetricExporterBuilder;
import io.opentelemetry.instrumentation.spring.autoconfigure.OpenTelemetryAutoConfiguration;
import java.time.Duration;
import org.springframework.boot.autoconfigure.AutoConfigureBefore;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
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.Configuration;
@Configuration
@AutoConfigureBefore(OpenTelemetryAutoConfiguration.class)
@EnableConfigurationProperties(OtlpExporterProperties.class)
@ConditionalOnProperty(
prefix = "otel.exporter.otlp",
name = {"enabled", "metrics.enabled"},
matchIfMissing = true)
@ConditionalOnClass(OtlpGrpcMetricExporter.class)
public class OtlpMetricExporterAutoConfiguration {
@Bean
@ConditionalOnMissingBean
public OtlpGrpcMetricExporter otelOtlpGrpcMetricExporter(OtlpExporterProperties properties) {
OtlpGrpcMetricExporterBuilder builder = OtlpGrpcMetricExporter.builder();
String endpoint = properties.getMetrics().getEndpoint();
if (endpoint == null) {
endpoint = properties.getEndpoint();
}
if (endpoint != null) {
builder.setEndpoint(endpoint);
}
Duration timeout = properties.getMetrics().getTimeout();
if (timeout == null) {
timeout = properties.getTimeout();
}
if (timeout != null) {
builder.setTimeout(timeout);
}
return builder.build();
}
}

View File

@ -8,6 +8,7 @@ package io.opentelemetry.instrumentation.spring.autoconfigure.exporters.otlp;
import io.opentelemetry.exporter.otlp.trace.OtlpGrpcSpanExporter;
import io.opentelemetry.exporter.otlp.trace.OtlpGrpcSpanExporterBuilder;
import io.opentelemetry.instrumentation.spring.autoconfigure.OpenTelemetryAutoConfiguration;
import java.time.Duration;
import org.springframework.boot.autoconfigure.AutoConfigureBefore;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
@ -23,22 +24,35 @@ import org.springframework.context.annotation.Configuration;
*/
@Configuration
@AutoConfigureBefore(OpenTelemetryAutoConfiguration.class)
@EnableConfigurationProperties(OtlpGrpcSpanExporterProperties.class)
@ConditionalOnProperty(prefix = "otel.exporter.otlp", name = "enabled", matchIfMissing = true)
@EnableConfigurationProperties(OtlpExporterProperties.class)
@ConditionalOnProperty(
prefix = "otel.exporter.otlp",
name = {"enabled", "traces.enabled"},
matchIfMissing = true)
@ConditionalOnClass(OtlpGrpcSpanExporter.class)
public class OtlpGrpcSpanExporterAutoConfiguration {
public class OtlpSpanExporterAutoConfiguration {
@Bean
@ConditionalOnMissingBean
public OtlpGrpcSpanExporter otelOtlpGrpcSpanExporter(OtlpGrpcSpanExporterProperties properties) {
public OtlpGrpcSpanExporter otelOtlpGrpcSpanExporter(OtlpExporterProperties properties) {
OtlpGrpcSpanExporterBuilder builder = OtlpGrpcSpanExporter.builder();
if (properties.getEndpoint() != null) {
builder.setEndpoint(properties.getEndpoint());
String endpoint = properties.getTraces().getEndpoint();
if (endpoint == null) {
endpoint = properties.getEndpoint();
}
if (properties.getTimeout() != null) {
builder.setTimeout(properties.getTimeout());
if (endpoint != null) {
builder.setEndpoint(endpoint);
}
Duration timeout = properties.getTraces().getTimeout();
if (timeout == null) {
timeout = properties.getTimeout();
}
if (timeout != null) {
builder.setTimeout(timeout);
}
return builder.build();
}
}

View File

@ -0,0 +1,36 @@
/*
* Copyright The OpenTelemetry Authors
* SPDX-License-Identifier: Apache-2.0
*/
package io.opentelemetry.instrumentation.spring.autoconfigure.metrics;
import io.micrometer.core.instrument.Clock;
import io.micrometer.core.instrument.MeterRegistry;
import io.opentelemetry.api.OpenTelemetry;
import io.opentelemetry.micrometer1shim.OpenTelemetryMeterRegistry;
import org.springframework.boot.actuate.autoconfigure.metrics.CompositeMeterRegistryAutoConfiguration;
import org.springframework.boot.actuate.autoconfigure.metrics.MetricsAutoConfiguration;
import org.springframework.boot.autoconfigure.AutoConfigureAfter;
import org.springframework.boot.autoconfigure.AutoConfigureBefore;
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
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.Configuration;
@Configuration
@EnableConfigurationProperties(MicrometerShimProperties.class)
@ConditionalOnProperty(name = "otel.springboot.micrometer.enabled", matchIfMissing = true)
@AutoConfigureAfter(MetricsAutoConfiguration.class)
@AutoConfigureBefore(CompositeMeterRegistryAutoConfiguration.class)
@ConditionalOnBean(Clock.class)
@ConditionalOnClass(MeterRegistry.class)
public class MicrometerShimAutoConfiguration {
@Bean
public MeterRegistry micrometerShim(OpenTelemetry openTelemetry, Clock micrometerClock) {
return OpenTelemetryMeterRegistry.builder(openTelemetry).setClock(micrometerClock).build();
}
}

View File

@ -3,13 +3,13 @@
* SPDX-License-Identifier: Apache-2.0
*/
package io.opentelemetry.instrumentation.spring.autoconfigure.exporters.logging;
package io.opentelemetry.instrumentation.spring.autoconfigure.metrics;
import org.springframework.boot.context.properties.ConfigurationProperties;
/** Configuration for {@link io.opentelemetry.exporter.logging.LoggingSpanExporter}. */
@ConfigurationProperties(prefix = "otel.exporter.logging")
public final class LoggingSpanExporterProperties {
@ConfigurationProperties(prefix = "otel.springboot.micrometer")
public class MicrometerShimProperties {
private boolean enabled = true;
public boolean isEnabled() {

View File

@ -1,12 +1,14 @@
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
io.opentelemetry.instrumentation.spring.autoconfigure.exporters.jaeger.JaegerSpanExporterAutoConfiguration,\
io.opentelemetry.instrumentation.spring.autoconfigure.exporters.otlp.OtlpGrpcSpanExporterAutoConfiguration,\
io.opentelemetry.instrumentation.spring.autoconfigure.exporters.zipkin.ZipkinSpanExporterAutoConfiguration,\
io.opentelemetry.instrumentation.spring.autoconfigure.exporters.logging.LoggingSpanExporterAutoConfiguration,\
io.opentelemetry.instrumentation.spring.autoconfigure.propagators.PropagationAutoConfiguration,\
io.opentelemetry.instrumentation.spring.autoconfigure.OpenTelemetryAutoConfiguration,\
io.opentelemetry.instrumentation.spring.autoconfigure.aspects.TraceAspectAutoConfiguration,\
io.opentelemetry.instrumentation.spring.autoconfigure.exporters.jaeger.JaegerSpanExporterAutoConfiguration,\
io.opentelemetry.instrumentation.spring.autoconfigure.exporters.logging.LoggingSpanExporterAutoConfiguration,\
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.httpclients.resttemplate.RestTemplateAutoConfiguration,\
io.opentelemetry.instrumentation.spring.autoconfigure.httpclients.webclient.WebClientAutoConfiguration,\
io.opentelemetry.instrumentation.spring.autoconfigure.webmvc.WebMvcFilterAutoConfiguration,\
io.opentelemetry.instrumentation.spring.autoconfigure.aspects.TraceAspectAutoConfiguration,\
io.opentelemetry.instrumentation.spring.autoconfigure.resources.OtelResourceAutoConfiguration
io.opentelemetry.instrumentation.spring.autoconfigure.metrics.MicrometerShimAutoConfiguration,\
io.opentelemetry.instrumentation.spring.autoconfigure.propagators.PropagationAutoConfiguration,\
io.opentelemetry.instrumentation.spring.autoconfigure.resources.OtelResourceAutoConfiguration,\
io.opentelemetry.instrumentation.spring.autoconfigure.webmvc.WebMvcFilterAutoConfiguration

View File

@ -11,6 +11,7 @@ import static org.assertj.core.api.Assertions.assertThat;
import io.opentelemetry.api.OpenTelemetry;
import io.opentelemetry.api.common.AttributeKey;
import io.opentelemetry.instrumentation.spring.autoconfigure.resources.OtelResourceAutoConfiguration;
import io.opentelemetry.sdk.metrics.SdkMeterProvider;
import io.opentelemetry.sdk.resources.Resource;
import io.opentelemetry.sdk.trace.SdkTracerProvider;
import org.junit.jupiter.api.DisplayName;
@ -44,34 +45,44 @@ class OpenTelemetryAutoConfigurationTest {
assertThat(context)
.hasBean("customOpenTelemetry")
.doesNotHaveBean("openTelemetry")
.doesNotHaveBean("sdkTracerProvider"));
.doesNotHaveBean("sdkTracerProvider")
.doesNotHaveBean("sdkMeterProvider"));
}
@Test
@DisplayName(
"when Application Context DOES NOT contain OpenTelemetry bean should initialize openTelemetry")
void initializeTracerProviderAndOpenTelemetry() {
void initializeProvidersAndOpenTelemetry() {
this.contextRunner
.withConfiguration(AutoConfigurations.of(OpenTelemetryAutoConfiguration.class))
.run(context -> assertThat(context).hasBean("openTelemetry").hasBean("sdkTracerProvider"));
.run(
context ->
assertThat(context)
.hasBean("openTelemetry")
.hasBean("sdkTracerProvider")
.hasBean("sdkMeterProvider"));
}
@Test
@DisplayName(
"when Application Context DOES NOT contain OpenTelemetry bean but TracerProvider should initialize openTelemetry")
void initializeOpenTelemetry() {
void initializeOpenTelemetryWithCustomProviders() {
this.contextRunner
.withBean(
"customTracerProvider",
SdkTracerProvider.class,
() -> SdkTracerProvider.builder().build())
.withBean(
"customMeterProvider", SdkMeterProvider.class, () -> SdkMeterProvider.builder().build())
.withConfiguration(AutoConfigurations.of(OpenTelemetryAutoConfiguration.class))
.run(
context ->
assertThat(context)
.hasBean("openTelemetry")
.hasBean("customTracerProvider")
.doesNotHaveBean("sdkTracerProvider"));
.doesNotHaveBean("sdkTracerProvider")
.hasBean("customMeterProvider")
.doesNotHaveBean("sdkMeterProvider"));
}
@Test

View File

@ -0,0 +1,68 @@
/*
* 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 loggingEnabled() {
runner
.withPropertyValues("otel.exporter.logging.enabled=true")
.run(
context ->
assertThat(
context.getBean("otelLoggingMetricExporter", LoggingMetricExporter.class))
.isNotNull());
}
@Test
void loggingMetricsEnabled() {
runner
.withPropertyValues("otel.exporter.logging.metrics.enabled=true")
.run(
context ->
assertThat(
context.getBean("otelLoggingMetricExporter", LoggingMetricExporter.class))
.isNotNull());
}
@Test
void loggingDisabled() {
runner
.withPropertyValues("otel.exporter.logging.enabled=false")
.run(context -> assertThat(context.containsBean("otelLoggingMetricExporter")).isFalse());
}
@Test
void loggingMetricsDisabled() {
runner
.withPropertyValues("otel.exporter.logging.metrics.enabled=false")
.run(context -> assertThat(context.containsBean("otelLoggingMetricExporter")).isFalse());
}
@Test
void noProperties() {
runner.run(
context ->
assertThat(context.getBean("otelLoggingMetricExporter", LoggingMetricExporter.class))
.isNotNull());
}
}

View File

@ -3,13 +3,12 @@
* SPDX-License-Identifier: Apache-2.0
*/
package io.opentelemetry.instrumentation.spring.autoconfigure.exporters;
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 io.opentelemetry.instrumentation.spring.autoconfigure.exporters.logging.LoggingSpanExporterAutoConfiguration;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import org.springframework.boot.autoconfigure.AutoConfigurations;
@ -27,7 +26,7 @@ class LoggingSpanExporterAutoConfigurationTest {
@Test
@DisplayName("when exporters are ENABLED should initialize LoggingSpanExporter bean")
void exportersEnabled() {
void loggingEnabled() {
this.contextRunner
.withPropertyValues("otel.exporter.logging.enabled=true")
.run(
@ -36,18 +35,36 @@ class LoggingSpanExporterAutoConfigurationTest {
.isNotNull());
}
@Test
void loggingTracesEnabled() {
this.contextRunner
.withPropertyValues("otel.exporter.logging.traces.enabled=true")
.run(
context ->
assertThat(context.getBean("otelLoggingSpanExporter", LoggingSpanExporter.class))
.isNotNull());
}
@Test
@DisplayName("when exporters are DISABLED should NOT initialize LoggingSpanExporter bean")
void disabledProperty() {
void loggingDisabled() {
this.contextRunner
.withPropertyValues("otel.exporter.logging.enabled=false")
.run(context -> assertThat(context.containsBean("otelLoggingSpanExporter")).isFalse());
}
@Test
@DisplayName("when exporters are DISABLED should NOT initialize LoggingSpanExporter bean")
void loggingTracesDisabled() {
this.contextRunner
.withPropertyValues("otel.exporter.logging.traces.enabled=false")
.run(context -> assertThat(context.containsBean("otelLoggingSpanExporter")).isFalse());
}
@Test
@DisplayName(
"when exporter enabled property is MISSING should initialize LoggingSpanExporter bean")
void noProperty() {
void exporterPresentByDefault() {
this.contextRunner.run(
context ->
assertThat(context.getBean("otelLoggingSpanExporter", LoggingSpanExporter.class))

View File

@ -0,0 +1,67 @@
/*
* 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.exporter.otlp.metrics.OtlpGrpcMetricExporter;
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 otlpEnabled() {
runner
.withPropertyValues("otel.exporter.otlp.enabled=true")
.run(
context ->
assertThat(
context.getBean("otelOtlpGrpcMetricExporter", OtlpGrpcMetricExporter.class))
.isNotNull());
}
@Test
void otlpMetricsEnabled() {
runner
.withPropertyValues("otel.exporter.otlp.metrics.enabled=true")
.run(
context ->
assertThat(
context.getBean("otelOtlpGrpcMetricExporter", OtlpGrpcMetricExporter.class))
.isNotNull());
}
@Test
void otlpDisabled() {
runner
.withPropertyValues("otel.exporter.otlp.enabled=false")
.run(context -> assertThat(context.containsBean("otelOtlpGrpcMetricExporter")).isFalse());
}
@Test
void otlpMetricsDisabled() {
runner
.withPropertyValues("otel.exporter.otlp.metrics.enabled=false")
.run(context -> assertThat(context.containsBean("otelOtlpGrpcMetricExporter")).isFalse());
}
@Test
void exporterPresentByDefault() {
runner.run(
context ->
assertThat(context.getBean("otelOtlpGrpcMetricExporter", OtlpGrpcMetricExporter.class))
.isNotNull());
}
}

View File

@ -3,32 +3,29 @@
* SPDX-License-Identifier: Apache-2.0
*/
package io.opentelemetry.instrumentation.spring.autoconfigure.exporters;
package io.opentelemetry.instrumentation.spring.autoconfigure.exporters.otlp;
import static org.assertj.core.api.Assertions.assertThat;
import io.opentelemetry.exporter.otlp.trace.OtlpGrpcSpanExporter;
import io.opentelemetry.instrumentation.spring.autoconfigure.OpenTelemetryAutoConfiguration;
import io.opentelemetry.instrumentation.spring.autoconfigure.exporters.otlp.OtlpGrpcSpanExporterAutoConfiguration;
import io.opentelemetry.instrumentation.spring.autoconfigure.exporters.otlp.OtlpGrpcSpanExporterProperties;
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 OtlpGrpcSpanExporterAutoConfiguration}. */
class OtlpGrpcSpanExporterAutoConfigurationTest {
/** Spring Boot auto configuration test for {@link OtlpSpanExporterAutoConfiguration}. */
class OtlpSpanExporterAutoConfigurationTest {
private final ApplicationContextRunner contextRunner =
new ApplicationContextRunner()
.withConfiguration(
AutoConfigurations.of(
OpenTelemetryAutoConfiguration.class,
OtlpGrpcSpanExporterAutoConfiguration.class));
OpenTelemetryAutoConfiguration.class, OtlpSpanExporterAutoConfiguration.class));
@Test
@DisplayName("when exporters are ENABLED should initialize OtlpGrpcSpanExporter bean")
void exportersEnabled() {
void otlpEnabled() {
this.contextRunner
.withPropertyValues("otel.exporter.otlp.enabled=true")
.run(
@ -38,35 +35,33 @@ class OtlpGrpcSpanExporterAutoConfigurationTest {
}
@Test
@DisplayName(
"when otel.exporter.otlp properties are set should initialize OtlpGrpcSpanExporterProperties")
void handlesProperties() {
void otlpTracesEnabled() {
this.contextRunner
.withPropertyValues(
"otel.exporter.otlp.enabled=true",
"otel.exporter.otlp.endpoint=http://localhost:8080/test",
"otel.exporter.otlp.timeout=69ms")
.withPropertyValues("otel.exporter.otlp.traces.enabled=true")
.run(
context -> {
OtlpGrpcSpanExporterProperties otlpSpanExporterProperties =
context.getBean(OtlpGrpcSpanExporterProperties.class);
assertThat(otlpSpanExporterProperties.getEndpoint())
.isEqualTo("http://localhost:8080/test");
assertThat(otlpSpanExporterProperties.getTimeout()).hasMillis(69);
});
context ->
assertThat(context.getBean("otelOtlpGrpcSpanExporter", OtlpGrpcSpanExporter.class))
.isNotNull());
}
@Test
@DisplayName("when exporters are DISABLED should NOT initialize OtlpGrpcSpanExporter bean")
void disabledProperty() {
void otlpDisabled() {
this.contextRunner
.withPropertyValues("otel.exporter.otlp.enabled=false")
.run(context -> assertThat(context.containsBean("otelOtlpGrpcSpanExporter")).isFalse());
}
@Test
void otlpTracesDisabled() {
this.contextRunner
.withPropertyValues("otel.exporter.otlp.traces.enabled=false")
.run(context -> assertThat(context.containsBean("otelOtlpGrpcSpanExporter")).isFalse());
}
@Test
@DisplayName("when otlp enabled property is MISSING should initialize OtlpGrpcSpanExporter bean")
void noProperty() {
void exporterPresentByDefault() {
this.contextRunner.run(
context ->
assertThat(context.getBean("otelOtlpGrpcSpanExporter", OtlpGrpcSpanExporter.class))

View File

@ -0,0 +1,63 @@
/*
* Copyright The OpenTelemetry Authors
* SPDX-License-Identifier: Apache-2.0
*/
package io.opentelemetry.instrumentation.spring.autoconfigure.metrics;
import static org.assertj.core.api.Assertions.assertThat;
import io.micrometer.core.instrument.MeterRegistry;
import io.opentelemetry.instrumentation.spring.autoconfigure.OpenTelemetryAutoConfiguration;
import io.opentelemetry.micrometer1shim.OpenTelemetryMeterRegistry;
import org.junit.jupiter.api.Test;
import org.springframework.boot.actuate.autoconfigure.metrics.MetricsAutoConfiguration;
import org.springframework.boot.autoconfigure.AutoConfigurations;
import org.springframework.boot.test.context.runner.ApplicationContextRunner;
class MicrometerShimAutoConfigurationTest {
private final ApplicationContextRunner runner =
new ApplicationContextRunner()
.withConfiguration(
AutoConfigurations.of(
OpenTelemetryAutoConfiguration.class, MicrometerShimAutoConfiguration.class));
@Test
void metricsEnabled() {
runner
.withConfiguration(AutoConfigurations.of(MetricsAutoConfiguration.class))
.withPropertyValues("otel.springboot.micrometer.enabled = true")
.run(
context ->
assertThat(context.getBean("micrometerShim", MeterRegistry.class))
.isNotNull()
.isInstanceOf(OpenTelemetryMeterRegistry.class));
}
@Test
void metricsEnabledByDefault() {
runner
.withConfiguration(AutoConfigurations.of(MetricsAutoConfiguration.class))
.run(
context ->
assertThat(context.getBean("micrometerShim", MeterRegistry.class))
.isNotNull()
.isInstanceOf(OpenTelemetryMeterRegistry.class));
}
@Test
void metricsDisabled() {
runner
.withConfiguration(AutoConfigurations.of(MetricsAutoConfiguration.class))
.withPropertyValues("otel.springboot.micrometer.enabled = false")
.run(context -> assertThat(context.containsBean("micrometerShim")).isFalse());
}
@Test
void noActuatorAutoConfiguration() {
runner
.withPropertyValues("otel.springboot.micrometer.enabled = true")
.run(context -> assertThat(context.containsBean("micrometerShim")).isFalse());
}
}