From c5f677e962ce8c629b75e2c7c26952f91d816a75 Mon Sep 17 00:00:00 2001 From: Andrei Chugunov Date: Tue, 29 Mar 2022 13:34:43 +0300 Subject: [PATCH] Spring Boot Starter service-name is constant (#5359) * Spring Boot Starter service-name is constant Pattern-based resource configuration * Add ResourceProvider beans for spring with ConfigProperties --- .../spring-boot-autoconfigure/README.md | 20 +++++ .../build.gradle.kts | 4 + .../OpenTelemetryAutoConfiguration.java | 23 +++++- .../OtelResourceAutoConfiguration.java | 67 ++++++++++++++++ .../resources/OtelResourceProperties.java | 23 ++++++ .../SpringResourceConfigProperties.java | 75 ++++++++++++++++++ .../resources/SpringResourceProvider.java | 40 ++++++++++ .../main/resources/META-INF/spring.factories | 3 +- .../OpenTelemetryAutoConfigurationTest.java | 76 +++++++++++++++++++ .../OtelResourceAutoConfigurationTest.java | 48 ++++++++++++ .../resources/OtelResourcePropertiesTest.java | 53 +++++++++++++ .../SpringResourceConfigPropertiesTest.java | 39 ++++++++++ 12 files changed, 469 insertions(+), 2 deletions(-) create mode 100644 instrumentation/spring/spring-boot-autoconfigure/src/main/java/io/opentelemetry/instrumentation/spring/autoconfigure/resources/OtelResourceAutoConfiguration.java create mode 100644 instrumentation/spring/spring-boot-autoconfigure/src/main/java/io/opentelemetry/instrumentation/spring/autoconfigure/resources/OtelResourceProperties.java create mode 100644 instrumentation/spring/spring-boot-autoconfigure/src/main/java/io/opentelemetry/instrumentation/spring/autoconfigure/resources/SpringResourceConfigProperties.java create mode 100644 instrumentation/spring/spring-boot-autoconfigure/src/main/java/io/opentelemetry/instrumentation/spring/autoconfigure/resources/SpringResourceProvider.java create mode 100644 instrumentation/spring/spring-boot-autoconfigure/src/test/java/io/opentelemetry/instrumentation/spring/autoconfigure/resources/OtelResourceAutoConfigurationTest.java create mode 100644 instrumentation/spring/spring-boot-autoconfigure/src/test/java/io/opentelemetry/instrumentation/spring/autoconfigure/resources/OtelResourcePropertiesTest.java create mode 100644 instrumentation/spring/spring-boot-autoconfigure/src/test/java/io/opentelemetry/instrumentation/spring/autoconfigure/resources/SpringResourceConfigPropertiesTest.java diff --git a/instrumentation/spring/spring-boot-autoconfigure/README.md b/instrumentation/spring/spring-boot-autoconfigure/README.md index becaf67a81..ca0fe4e5ec 100644 --- a/instrumentation/spring/spring-boot-autoconfigure/README.md +++ b/instrumentation/spring/spring-boot-autoconfigure/README.md @@ -392,6 +392,26 @@ If an exporter is present in the classpath during runtime and a spring bean of t +##### Resource Properties + +| Feature | Property | Default Value | +|----------|--------------------------------------------------|------------------------| +| Resource | otel.springboot.resource.enabled | `true` | +| | otel.springboot.resource.attributes.service.name | `unknown_service:java` | +| | otel.springboot.resource.attributes | `empty map` | + +`unknown_service:java` will be used as the service-name if no value has been specified to the +property `spring.application.name` or `otel.springboot.resource.attributes.service.name` (which has +the highest priority) + +`otel.springboot.resource.attributes` supports a pattern-based resource configuration in the +application.properties like this: + +``` +otel.springboot.resource.attributes.environment=dev +otel.springboot.resource.attributes.xyz=foo +``` + ##### Exporter Properties | Feature | Property | Default Value | diff --git a/instrumentation/spring/spring-boot-autoconfigure/build.gradle.kts b/instrumentation/spring/spring-boot-autoconfigure/build.gradle.kts index 520259fa00..4d368ed718 100644 --- a/instrumentation/spring/spring-boot-autoconfigure/build.gradle.kts +++ b/instrumentation/spring/spring-boot-autoconfigure/build.gradle.kts @@ -22,9 +22,11 @@ dependencies { 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("io.opentelemetry:opentelemetry-sdk-extension-autoconfigure-spi") compileOnly("io.opentelemetry:opentelemetry-extension-annotations") compileOnly("io.opentelemetry:opentelemetry-extension-trace-propagators") compileOnly("io.opentelemetry:opentelemetry-extension-aws") + compileOnly("io.opentelemetry:opentelemetry-sdk-extension-resources") compileOnly("io.opentelemetry:opentelemetry-exporter-logging") compileOnly("io.opentelemetry:opentelemetry-exporter-jaeger") compileOnly("io.opentelemetry:opentelemetry-exporter-otlp") @@ -40,6 +42,8 @@ dependencies { testImplementation(project(":testing-common")) testImplementation("io.opentelemetry:opentelemetry-sdk") testImplementation("io.opentelemetry:opentelemetry-sdk-testing") + testImplementation("io.opentelemetry:opentelemetry-sdk-extension-resources") + testImplementation("io.opentelemetry:opentelemetry-sdk-extension-autoconfigure-spi") testImplementation("io.opentelemetry:opentelemetry-extension-annotations") testImplementation("io.opentelemetry:opentelemetry-extension-trace-propagators") testImplementation("io.opentelemetry:opentelemetry-extension-aws") diff --git a/instrumentation/spring/spring-boot-autoconfigure/src/main/java/io/opentelemetry/instrumentation/spring/autoconfigure/OpenTelemetryAutoConfiguration.java b/instrumentation/spring/spring-boot-autoconfigure/src/main/java/io/opentelemetry/instrumentation/spring/autoconfigure/OpenTelemetryAutoConfiguration.java index ab39fb2adc..cd72b7560e 100644 --- a/instrumentation/spring/spring-boot-autoconfigure/src/main/java/io/opentelemetry/instrumentation/spring/autoconfigure/OpenTelemetryAutoConfiguration.java +++ b/instrumentation/spring/spring-boot-autoconfigure/src/main/java/io/opentelemetry/instrumentation/spring/autoconfigure/OpenTelemetryAutoConfiguration.java @@ -8,7 +8,11 @@ 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.resources.SpringResourceConfigProperties; import io.opentelemetry.sdk.OpenTelemetrySdk; +import io.opentelemetry.sdk.autoconfigure.spi.ConfigProperties; +import io.opentelemetry.sdk.autoconfigure.spi.ResourceProvider; +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; @@ -21,6 +25,8 @@ 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.Configuration; +import org.springframework.core.env.Environment; +import org.springframework.expression.spel.standard.SpelExpressionParser; /** * Create {@link io.opentelemetry.api.trace.Tracer} bean if bean is missing. @@ -41,7 +47,8 @@ public class OpenTelemetryAutoConfiguration { @ConditionalOnMissingBean public SdkTracerProvider sdkTracerProvider( SamplerProperties samplerProperties, - ObjectProvider> spanExportersProvider) { + ObjectProvider> spanExportersProvider, + Resource otelResource) { SdkTracerProviderBuilder tracerProviderBuilder = SdkTracerProvider.builder(); spanExportersProvider.getIfAvailable(Collections::emptyList).stream() @@ -49,10 +56,24 @@ public class OpenTelemetryAutoConfiguration { .forEach(tracerProviderBuilder::addSpanProcessor); return tracerProviderBuilder + .setResource(otelResource) .setSampler(Sampler.traceIdRatioBased(samplerProperties.getProbability())) .build(); } + @Bean + @ConditionalOnMissingBean + public Resource otelResource( + Environment env, ObjectProvider> resourceProviders) { + ConfigProperties config = new SpringResourceConfigProperties(env, new SpelExpressionParser()); + Resource resource = Resource.getDefault(); + for (ResourceProvider resourceProvider : + resourceProviders.getIfAvailable(Collections::emptyList)) { + resource = resource.merge(resourceProvider.createResource(config)); + } + return resource; + } + @Bean public OpenTelemetry openTelemetry( ObjectProvider propagatorsProvider, SdkTracerProvider tracerProvider) { diff --git a/instrumentation/spring/spring-boot-autoconfigure/src/main/java/io/opentelemetry/instrumentation/spring/autoconfigure/resources/OtelResourceAutoConfiguration.java b/instrumentation/spring/spring-boot-autoconfigure/src/main/java/io/opentelemetry/instrumentation/spring/autoconfigure/resources/OtelResourceAutoConfiguration.java new file mode 100644 index 0000000000..aa5bf5b63f --- /dev/null +++ b/instrumentation/spring/spring-boot-autoconfigure/src/main/java/io/opentelemetry/instrumentation/spring/autoconfigure/resources/OtelResourceAutoConfiguration.java @@ -0,0 +1,67 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.instrumentation.spring.autoconfigure.resources; + +import io.opentelemetry.instrumentation.spring.autoconfigure.OpenTelemetryAutoConfiguration; +import io.opentelemetry.sdk.autoconfigure.spi.ResourceProvider; +import io.opentelemetry.sdk.extension.resources.ContainerResource; +import io.opentelemetry.sdk.extension.resources.ContainerResourceProvider; +import io.opentelemetry.sdk.extension.resources.HostResource; +import io.opentelemetry.sdk.extension.resources.HostResourceProvider; +import io.opentelemetry.sdk.extension.resources.OsResource; +import io.opentelemetry.sdk.extension.resources.OsResourceProvider; +import io.opentelemetry.sdk.extension.resources.ProcessResource; +import io.opentelemetry.sdk.extension.resources.ProcessResourceProvider; +import io.opentelemetry.sdk.extension.resources.ProcessRuntimeResource; +import io.opentelemetry.sdk.extension.resources.ProcessRuntimeResourceProvider; +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.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +@Configuration +@EnableConfigurationProperties(OtelResourceProperties.class) +@AutoConfigureBefore(OpenTelemetryAutoConfiguration.class) +@ConditionalOnProperty(prefix = "otel.springboot.resource", name = "enabled", matchIfMissing = true) +public class OtelResourceAutoConfiguration { + + @Bean + public ResourceProvider otelResourceProvider(OtelResourceProperties otelResourceProperties) { + return new SpringResourceProvider(otelResourceProperties); + } + + @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(); + } +} diff --git a/instrumentation/spring/spring-boot-autoconfigure/src/main/java/io/opentelemetry/instrumentation/spring/autoconfigure/resources/OtelResourceProperties.java b/instrumentation/spring/spring-boot-autoconfigure/src/main/java/io/opentelemetry/instrumentation/spring/autoconfigure/resources/OtelResourceProperties.java new file mode 100644 index 0000000000..36169f4f8e --- /dev/null +++ b/instrumentation/spring/spring-boot-autoconfigure/src/main/java/io/opentelemetry/instrumentation/spring/autoconfigure/resources/OtelResourceProperties.java @@ -0,0 +1,23 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.instrumentation.spring.autoconfigure.resources; + +import java.util.Collections; +import java.util.Map; +import org.springframework.boot.context.properties.ConfigurationProperties; + +@ConfigurationProperties(prefix = "otel.springboot.resource") +public class OtelResourceProperties { + private Map attributes = Collections.emptyMap(); + + public Map getAttributes() { + return attributes; + } + + public void setAttributes(Map attributes) { + this.attributes = attributes; + } +} diff --git a/instrumentation/spring/spring-boot-autoconfigure/src/main/java/io/opentelemetry/instrumentation/spring/autoconfigure/resources/SpringResourceConfigProperties.java b/instrumentation/spring/spring-boot-autoconfigure/src/main/java/io/opentelemetry/instrumentation/spring/autoconfigure/resources/SpringResourceConfigProperties.java new file mode 100644 index 0000000000..4ed9190ac4 --- /dev/null +++ b/instrumentation/spring/spring-boot-autoconfigure/src/main/java/io/opentelemetry/instrumentation/spring/autoconfigure/resources/SpringResourceConfigProperties.java @@ -0,0 +1,75 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.instrumentation.spring.autoconfigure.resources; + +import io.opentelemetry.sdk.autoconfigure.spi.ConfigProperties; +import java.time.Duration; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import javax.annotation.Nullable; +import org.springframework.core.env.Environment; +import org.springframework.expression.ExpressionParser; + +public class SpringResourceConfigProperties implements ConfigProperties { + private final Environment environment; + + private final ExpressionParser parser; + + public SpringResourceConfigProperties(Environment environment, ExpressionParser parser) { + this.environment = environment; + this.parser = parser; + } + + @Nullable + @Override + public String getString(String name) { + return environment.getProperty(name, String.class); + } + + @Nullable + @Override + public Boolean getBoolean(String name) { + return environment.getProperty(name, Boolean.class); + } + + @Nullable + @Override + public Integer getInt(String name) { + return environment.getProperty(name, Integer.class); + } + + @Nullable + @Override + public Long getLong(String name) { + return environment.getProperty(name, Long.class); + } + + @Nullable + @Override + public Double getDouble(String name) { + return environment.getProperty(name, Double.class); + } + + @Nullable + @Override + public Duration getDuration(String name) { + return environment.getProperty(name, Duration.class); + } + + @SuppressWarnings("unchecked") + @Override + public List getList(String name) { + return (List) environment.getProperty(name, List.class); + } + + @SuppressWarnings("unchecked") + @Override + public Map getMap(String name) { + String value = environment.getProperty(name); + return (Map) parser.parseExpression(Objects.requireNonNull(value)).getValue(); + } +} diff --git a/instrumentation/spring/spring-boot-autoconfigure/src/main/java/io/opentelemetry/instrumentation/spring/autoconfigure/resources/SpringResourceProvider.java b/instrumentation/spring/spring-boot-autoconfigure/src/main/java/io/opentelemetry/instrumentation/spring/autoconfigure/resources/SpringResourceProvider.java new file mode 100644 index 0000000000..18dcb65767 --- /dev/null +++ b/instrumentation/spring/spring-boot-autoconfigure/src/main/java/io/opentelemetry/instrumentation/spring/autoconfigure/resources/SpringResourceProvider.java @@ -0,0 +1,40 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.instrumentation.spring.autoconfigure.resources; + +import io.opentelemetry.api.common.Attributes; +import io.opentelemetry.api.common.AttributesBuilder; +import io.opentelemetry.sdk.autoconfigure.spi.ConfigProperties; +import io.opentelemetry.sdk.autoconfigure.spi.ResourceProvider; +import io.opentelemetry.sdk.resources.Resource; +import io.opentelemetry.semconv.resource.attributes.ResourceAttributes; +import java.util.Map; + +public class SpringResourceProvider implements ResourceProvider { + + private final OtelResourceProperties otelResourceProperties; + + public SpringResourceProvider(OtelResourceProperties otelResourceProperties) { + this.otelResourceProperties = otelResourceProperties; + } + + @Override + public Resource createResource(ConfigProperties configProperties) { + String applicationName = configProperties.getString("spring.application.name"); + Map attributes = otelResourceProperties.getAttributes(); + AttributesBuilder attributesBuilder = Attributes.builder(); + attributes.forEach(attributesBuilder::put); + return defaultResource(applicationName).merge(Resource.create(attributesBuilder.build())); + } + + private static Resource defaultResource(String applicationName) { + if (applicationName == null) { + return Resource.getDefault(); + } + return Resource.getDefault() + .merge(Resource.create(Attributes.of(ResourceAttributes.SERVICE_NAME, applicationName))); + } +} diff --git a/instrumentation/spring/spring-boot-autoconfigure/src/main/resources/META-INF/spring.factories b/instrumentation/spring/spring-boot-autoconfigure/src/main/resources/META-INF/spring.factories index 3a0d956a40..daa1cfb52c 100644 --- a/instrumentation/spring/spring-boot-autoconfigure/src/main/resources/META-INF/spring.factories +++ b/instrumentation/spring/spring-boot-autoconfigure/src/main/resources/META-INF/spring.factories @@ -8,4 +8,5 @@ io.opentelemetry.instrumentation.spring.autoconfigure.OpenTelemetryAutoConfigura 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.aspects.TraceAspectAutoConfiguration,\ +io.opentelemetry.instrumentation.spring.autoconfigure.resources.OtelResourceAutoConfiguration diff --git a/instrumentation/spring/spring-boot-autoconfigure/src/test/java/io/opentelemetry/instrumentation/spring/autoconfigure/OpenTelemetryAutoConfigurationTest.java b/instrumentation/spring/spring-boot-autoconfigure/src/test/java/io/opentelemetry/instrumentation/spring/autoconfigure/OpenTelemetryAutoConfigurationTest.java index 5bbb9515a5..ff205a1627 100644 --- a/instrumentation/spring/spring-boot-autoconfigure/src/test/java/io/opentelemetry/instrumentation/spring/autoconfigure/OpenTelemetryAutoConfigurationTest.java +++ b/instrumentation/spring/spring-boot-autoconfigure/src/test/java/io/opentelemetry/instrumentation/spring/autoconfigure/OpenTelemetryAutoConfigurationTest.java @@ -5,9 +5,13 @@ package io.opentelemetry.instrumentation.spring.autoconfigure; +import static io.opentelemetry.semconv.resource.attributes.ResourceAttributes.SERVICE_NAME; 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.resources.Resource; import io.opentelemetry.sdk.trace.SdkTracerProvider; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; @@ -69,4 +73,76 @@ class OpenTelemetryAutoConfigurationTest { .hasBean("customTracerProvider") .doesNotHaveBean("sdkTracerProvider")); } + + @Test + @DisplayName( + "when spring.application.name is set value should be passed to service name attribute") + 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"); + }); + } + + @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); + + 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.springboot.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"); + }); + } + + @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.springboot.resource.attributes.xyz=foo", + "otel.springboot.resource.attributes.environment=dev", + "otel.springboot.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"); + }); + } } diff --git a/instrumentation/spring/spring-boot-autoconfigure/src/test/java/io/opentelemetry/instrumentation/spring/autoconfigure/resources/OtelResourceAutoConfigurationTest.java b/instrumentation/spring/spring-boot-autoconfigure/src/test/java/io/opentelemetry/instrumentation/spring/autoconfigure/resources/OtelResourceAutoConfigurationTest.java new file mode 100644 index 0000000000..17506fffe3 --- /dev/null +++ b/instrumentation/spring/spring-boot-autoconfigure/src/test/java/io/opentelemetry/instrumentation/spring/autoconfigure/resources/OtelResourceAutoConfigurationTest.java @@ -0,0 +1,48 @@ +/* + * 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("otelResourceProvider")).isTrue()); + } + + @Test + @DisplayName( + "when otel.springboot.resource.enabled is not specified configuration should be initialized") + void shouldInitAutoConfigurationByDefault() { + this.contextRunner.run( + context -> assertThat(context.containsBean("otelResourceProvider")).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("otelResourceProvider")).isFalse()); + } +} diff --git a/instrumentation/spring/spring-boot-autoconfigure/src/test/java/io/opentelemetry/instrumentation/spring/autoconfigure/resources/OtelResourcePropertiesTest.java b/instrumentation/spring/spring-boot-autoconfigure/src/test/java/io/opentelemetry/instrumentation/spring/autoconfigure/resources/OtelResourcePropertiesTest.java new file mode 100644 index 0000000000..2b882b5cf7 --- /dev/null +++ b/instrumentation/spring/spring-boot-autoconfigure/src/test/java/io/opentelemetry/instrumentation/spring/autoconfigure/resources/OtelResourcePropertiesTest.java @@ -0,0 +1,53 @@ +/* + * 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 static org.assertj.core.api.Assertions.entry; + +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 OtelResourcePropertiesTest { + private final ApplicationContextRunner contextRunner = + new ApplicationContextRunner() + .withPropertyValues("otel.springboot.resource.enabled=true") + .withConfiguration(AutoConfigurations.of(OtelResourceAutoConfiguration.class)); + + @Test + @DisplayName("when attributes are SET should set OtelResourceProperties with given attributes") + void hasAttributes() { + + this.contextRunner + .withPropertyValues( + "otel.springboot.resource.attributes.environment=dev", + "otel.springboot.resource.attributes.xyz=foo", + "otel.springboot.resource.attributes.service.name=backend-name", + "otel.springboot.resource.attributes.service.instance.id=id-example") + .run( + context -> { + OtelResourceProperties propertiesBean = context.getBean(OtelResourceProperties.class); + + assertThat(propertiesBean.getAttributes()) + .contains( + entry("environment", "dev"), + entry("xyz", "foo"), + entry("service.name", "backend-name"), + entry("service.instance.id", "id-example")); + }); + } + + @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()); + } +} diff --git a/instrumentation/spring/spring-boot-autoconfigure/src/test/java/io/opentelemetry/instrumentation/spring/autoconfigure/resources/SpringResourceConfigPropertiesTest.java b/instrumentation/spring/spring-boot-autoconfigure/src/test/java/io/opentelemetry/instrumentation/spring/autoconfigure/resources/SpringResourceConfigPropertiesTest.java new file mode 100644 index 0000000000..93756ae1c4 --- /dev/null +++ b/instrumentation/spring/spring-boot-autoconfigure/src/test/java/io/opentelemetry/instrumentation/spring/autoconfigure/resources/SpringResourceConfigPropertiesTest.java @@ -0,0 +1,39 @@ +/* + * 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 static org.assertj.core.api.Assertions.entry; + +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.springframework.boot.test.context.runner.ApplicationContextRunner; +import org.springframework.core.env.Environment; +import org.springframework.expression.spel.standard.SpelExpressionParser; + +class SpringResourceConfigPropertiesTest { + private final ApplicationContextRunner contextRunner = new ApplicationContextRunner(); + + @Test + @DisplayName("when map is set in properties in a row it should be available in config") + void shouldInitializeAttributesByMapInArow() { + this.contextRunner + .withPropertyValues( + "otel.springboot.test.map={'environment':'dev','xyz':'foo','service.instance.id':'id-example'}") + .run( + context -> { + Environment env = context.getBean("environment", Environment.class); + SpringResourceConfigProperties config = + new SpringResourceConfigProperties(env, new SpelExpressionParser()); + + assertThat(config.getMap("otel.springboot.test.map")) + .contains( + entry("environment", "dev"), + entry("xyz", "foo"), + entry("service.instance.id", "id-example")); + }); + } +}