From 53678f215141218ab30e883847bffb64d8e68118 Mon Sep 17 00:00:00 2001 From: Andrei Chugunov Date: Fri, 11 Feb 2022 14:00:10 +0300 Subject: [PATCH 1/2] Spring Boot Starter service-name is constant Pattern-based resource configuration --- .../spring-boot-autoconfigure/README.md | 20 +++++ .../build.gradle.kts | 2 + .../OpenTelemetryAutoConfiguration.java | 31 ++++++- .../OtelResourceAutoConfiguration.java | 72 ++++++++++++++++ .../autoconfigure/OtelResourceProperties.java | 23 ++++++ .../main/resources/META-INF/spring.factories | 3 +- .../OpenTelemetryAutoConfigurationTest.java | 31 +++++++ .../OtelResourceAutoConfigurationTest.java | 82 +++++++++++++++++++ .../OtelResourcePropertiesTest.java | 53 ++++++++++++ 9 files changed, 315 insertions(+), 2 deletions(-) create mode 100644 instrumentation/spring/spring-boot-autoconfigure/src/main/java/io/opentelemetry/instrumentation/spring/autoconfigure/OtelResourceAutoConfiguration.java create mode 100644 instrumentation/spring/spring-boot-autoconfigure/src/main/java/io/opentelemetry/instrumentation/spring/autoconfigure/OtelResourceProperties.java create mode 100644 instrumentation/spring/spring-boot-autoconfigure/src/test/java/io/opentelemetry/instrumentation/spring/autoconfigure/OtelResourceAutoConfigurationTest.java create mode 100644 instrumentation/spring/spring-boot-autoconfigure/src/test/java/io/opentelemetry/instrumentation/spring/autoconfigure/OtelResourcePropertiesTest.java diff --git a/instrumentation/spring/spring-boot-autoconfigure/README.md b/instrumentation/spring/spring-boot-autoconfigure/README.md index becaf67a8153..ca0fe4e5ec50 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 520259fa00fa..14898ee39a74 100644 --- a/instrumentation/spring/spring-boot-autoconfigure/build.gradle.kts +++ b/instrumentation/spring/spring-boot-autoconfigure/build.gradle.kts @@ -25,6 +25,7 @@ dependencies { 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 +41,7 @@ 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-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 ab39fb2adcaf..5d96059a51b9 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 @@ -6,21 +6,26 @@ package io.opentelemetry.instrumentation.spring.autoconfigure; import io.opentelemetry.api.OpenTelemetry; +import io.opentelemetry.api.common.Attributes; import io.opentelemetry.api.trace.TracerProvider; import io.opentelemetry.context.propagation.ContextPropagators; import io.opentelemetry.sdk.OpenTelemetrySdk; +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 io.opentelemetry.semconv.resource.attributes.ResourceAttributes; import java.util.Collections; import java.util.List; +import java.util.function.Supplier; import org.springframework.beans.factory.ObjectProvider; 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; /** * Create {@link io.opentelemetry.api.trace.Tracer} bean if bean is missing. @@ -41,7 +46,8 @@ public static class OpenTelemetryBeanConfig { @ConditionalOnMissingBean public SdkTracerProvider sdkTracerProvider( SamplerProperties samplerProperties, - ObjectProvider> spanExportersProvider) { + ObjectProvider> spanExportersProvider, + Resource otelResource) { SdkTracerProviderBuilder tracerProviderBuilder = SdkTracerProvider.builder(); spanExportersProvider.getIfAvailable(Collections::emptyList).stream() @@ -49,10 +55,33 @@ public SdkTracerProvider sdkTracerProvider( .forEach(tracerProviderBuilder::addSpanProcessor); return tracerProviderBuilder + .setResource(otelResource) .setSampler(Sampler.traceIdRatioBased(samplerProperties.getProbability())) .build(); } + @Bean + @ConditionalOnMissingBean + public Resource otelResource( + Environment env, ObjectProvider>> resourceProviders) { + String applicationName = env.getProperty("spring.application.name"); + Resource resource = defaultResource(applicationName); + List> resourceCustomizers = + resourceProviders.getIfAvailable(Collections::emptyList); + for (Supplier resourceCustomizer : resourceCustomizers) { + resource = resource.merge(resourceCustomizer.get()); + } + return resource; + } + + private static Resource defaultResource(String applicationName) { + if (applicationName == null) { + return Resource.getDefault(); + } + return Resource.getDefault() + .merge(Resource.create(Attributes.of(ResourceAttributes.SERVICE_NAME, applicationName))); + } + @Bean public OpenTelemetry openTelemetry( ObjectProvider propagatorsProvider, SdkTracerProvider tracerProvider) { diff --git a/instrumentation/spring/spring-boot-autoconfigure/src/main/java/io/opentelemetry/instrumentation/spring/autoconfigure/OtelResourceAutoConfiguration.java b/instrumentation/spring/spring-boot-autoconfigure/src/main/java/io/opentelemetry/instrumentation/spring/autoconfigure/OtelResourceAutoConfiguration.java new file mode 100644 index 000000000000..9c17bc1aa758 --- /dev/null +++ b/instrumentation/spring/spring-boot-autoconfigure/src/main/java/io/opentelemetry/instrumentation/spring/autoconfigure/OtelResourceAutoConfiguration.java @@ -0,0 +1,72 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.instrumentation.spring.autoconfigure; + +import io.opentelemetry.api.common.Attributes; +import io.opentelemetry.api.common.AttributesBuilder; +import io.opentelemetry.sdk.extension.resources.ContainerResource; +import io.opentelemetry.sdk.extension.resources.HostResource; +import io.opentelemetry.sdk.extension.resources.OsResource; +import io.opentelemetry.sdk.extension.resources.ProcessResource; +import io.opentelemetry.sdk.extension.resources.ProcessRuntimeResource; +import io.opentelemetry.sdk.resources.Resource; +import java.util.Map; +import java.util.function.Supplier; +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 Supplier otelResourceProvider(OtelResourceProperties otelResourceProperties) { + return () -> { + AttributesBuilder attributesBuilder = Attributes.builder(); + for (Map.Entry entry : otelResourceProperties.getAttributes().entrySet()) { + attributesBuilder.put(entry.getKey(), entry.getValue()); + } + Attributes attributes = attributesBuilder.build(); + return Resource.create(attributes); + }; + } + + @Bean + @ConditionalOnClass(OsResource.class) + public Supplier otelOsResourceProvider() { + return OsResource::get; + } + + @Bean + @ConditionalOnClass(ProcessResource.class) + public Supplier otelProcessResourceProvider() { + return ProcessResource::get; + } + + @Bean + @ConditionalOnClass(ProcessRuntimeResource.class) + public Supplier otelProcessRuntimeResourceProvider() { + return ProcessRuntimeResource::get; + } + + @Bean + @ConditionalOnClass(HostResource.class) + public Supplier otelHostResourceProvider() { + return HostResource::get; + } + + @Bean + @ConditionalOnClass(ContainerResource.class) + public Supplier otelContainerResource() { + return ContainerResource::get; + } +} diff --git a/instrumentation/spring/spring-boot-autoconfigure/src/main/java/io/opentelemetry/instrumentation/spring/autoconfigure/OtelResourceProperties.java b/instrumentation/spring/spring-boot-autoconfigure/src/main/java/io/opentelemetry/instrumentation/spring/autoconfigure/OtelResourceProperties.java new file mode 100644 index 000000000000..192c92e83656 --- /dev/null +++ b/instrumentation/spring/spring-boot-autoconfigure/src/main/java/io/opentelemetry/instrumentation/spring/autoconfigure/OtelResourceProperties.java @@ -0,0 +1,23 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.instrumentation.spring.autoconfigure; + +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/resources/META-INF/spring.factories b/instrumentation/spring/spring-boot-autoconfigure/src/main/resources/META-INF/spring.factories index 3a0d956a402d..2f9311698c1c 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.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 5bbb9515a5fb..812c0f87ce18 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,11 @@ 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.sdk.resources.Resource; import io.opentelemetry.sdk.trace.SdkTracerProvider; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; @@ -69,4 +71,33 @@ void initializeOpenTelemetry() { .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(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(OpenTelemetryAutoConfiguration.class)) + .run( + context -> { + Resource otelResource = context.getBean("otelResource", Resource.class); + + assertThat(otelResource.getAttribute(SERVICE_NAME)).isEqualTo("unknown_service:java"); + }); + } } diff --git a/instrumentation/spring/spring-boot-autoconfigure/src/test/java/io/opentelemetry/instrumentation/spring/autoconfigure/OtelResourceAutoConfigurationTest.java b/instrumentation/spring/spring-boot-autoconfigure/src/test/java/io/opentelemetry/instrumentation/spring/autoconfigure/OtelResourceAutoConfigurationTest.java new file mode 100644 index 000000000000..9f982127d810 --- /dev/null +++ b/instrumentation/spring/spring-boot-autoconfigure/src/test/java/io/opentelemetry/instrumentation/spring/autoconfigure/OtelResourceAutoConfigurationTest.java @@ -0,0 +1,82 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +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.common.AttributeKey; +import io.opentelemetry.sdk.resources.Resource; +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 service name is set it should be set as service name attribute") + void shouldDetermineServiceNameByOtelServiceName() { + this.contextRunner + .withPropertyValues( + "otel.springboot.resource.attributes.service.name=otel-name-backend", + "otel.springboot.resource.enabled=true") + .run( + context -> { + Resource otelResource = context.getBean("otelResource", Resource.class); + + assertThat(otelResource.getAttribute(SERVICE_NAME)).isEqualTo("otel-name-backend"); + }); + } + + @Test + @DisplayName( + "when otel.springboot.resource.enabled is not specified configuration should be initialized") + void shouldInitAutoConfigurationByDefault() { + this.contextRunner + .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.springboot.resource.enabled is set to false configuration should NOT be initialized") + void shouldNotInitAutoConfiguration() { + this.contextRunner + .withPropertyValues( + "otel.springboot.resource.attributes.service.name=otel-name-backend", + "otel.springboot.resource.enabled=false") + .run(context -> assertThat(context.containsBean("otelResourceProvider")).isFalse()); + } + + @Test + @DisplayName("when otel attributes are set in properties they should be put in resource") + void shouldInitializeAttributes() { + this.contextRunner + .withPropertyValues( + "otel.springboot.resource.attributes.xyz=foo", + "otel.springboot.resource.attributes.environment=dev", + "otel.springboot.resource.enabled=true") + .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"); + }); + } +} diff --git a/instrumentation/spring/spring-boot-autoconfigure/src/test/java/io/opentelemetry/instrumentation/spring/autoconfigure/OtelResourcePropertiesTest.java b/instrumentation/spring/spring-boot-autoconfigure/src/test/java/io/opentelemetry/instrumentation/spring/autoconfigure/OtelResourcePropertiesTest.java new file mode 100644 index 000000000000..ed583120cf84 --- /dev/null +++ b/instrumentation/spring/spring-boot-autoconfigure/src/test/java/io/opentelemetry/instrumentation/spring/autoconfigure/OtelResourcePropertiesTest.java @@ -0,0 +1,53 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.instrumentation.spring.autoconfigure; + +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()); + } +} From 393e0b9ff6159d6ce396b20adc42265146e7987f Mon Sep 17 00:00:00 2001 From: Andrei Chugunov Date: Tue, 29 Mar 2022 10:19:51 +0300 Subject: [PATCH 2/2] Add ResourceProvider beans for spring with ConfigProperties --- .../build.gradle.kts | 2 + .../OpenTelemetryAutoConfiguration.java | 28 +++---- .../OtelResourceAutoConfiguration.java | 45 +++++----- .../OtelResourceProperties.java | 2 +- .../SpringResourceConfigProperties.java | 75 +++++++++++++++++ .../resources/SpringResourceProvider.java | 40 +++++++++ .../main/resources/META-INF/spring.factories | 2 +- .../OpenTelemetryAutoConfigurationTest.java | 49 ++++++++++- .../OtelResourceAutoConfigurationTest.java | 82 ------------------- .../OtelResourceAutoConfigurationTest.java | 48 +++++++++++ .../OtelResourcePropertiesTest.java | 2 +- .../SpringResourceConfigPropertiesTest.java | 39 +++++++++ 12 files changed, 284 insertions(+), 130 deletions(-) rename instrumentation/spring/spring-boot-autoconfigure/src/main/java/io/opentelemetry/instrumentation/spring/autoconfigure/{ => resources}/OtelResourceAutoConfiguration.java (53%) rename instrumentation/spring/spring-boot-autoconfigure/src/main/java/io/opentelemetry/instrumentation/spring/autoconfigure/{ => resources}/OtelResourceProperties.java (88%) 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 delete mode 100644 instrumentation/spring/spring-boot-autoconfigure/src/test/java/io/opentelemetry/instrumentation/spring/autoconfigure/OtelResourceAutoConfigurationTest.java create mode 100644 instrumentation/spring/spring-boot-autoconfigure/src/test/java/io/opentelemetry/instrumentation/spring/autoconfigure/resources/OtelResourceAutoConfigurationTest.java rename instrumentation/spring/spring-boot-autoconfigure/src/test/java/io/opentelemetry/instrumentation/spring/autoconfigure/{ => resources}/OtelResourcePropertiesTest.java (96%) 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/build.gradle.kts b/instrumentation/spring/spring-boot-autoconfigure/build.gradle.kts index 14898ee39a74..4d368ed7183b 100644 --- a/instrumentation/spring/spring-boot-autoconfigure/build.gradle.kts +++ b/instrumentation/spring/spring-boot-autoconfigure/build.gradle.kts @@ -22,6 +22,7 @@ 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") @@ -42,6 +43,7 @@ dependencies { 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 5d96059a51b9..cd72b7560e0c 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 @@ -6,26 +6,27 @@ package io.opentelemetry.instrumentation.spring.autoconfigure; import io.opentelemetry.api.OpenTelemetry; -import io.opentelemetry.api.common.Attributes; 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; import io.opentelemetry.sdk.trace.export.SpanExporter; import io.opentelemetry.sdk.trace.samplers.Sampler; -import io.opentelemetry.semconv.resource.attributes.ResourceAttributes; import java.util.Collections; import java.util.List; -import java.util.function.Supplier; import org.springframework.beans.factory.ObjectProvider; 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. @@ -63,25 +64,16 @@ public SdkTracerProvider sdkTracerProvider( @Bean @ConditionalOnMissingBean public Resource otelResource( - Environment env, ObjectProvider>> resourceProviders) { - String applicationName = env.getProperty("spring.application.name"); - Resource resource = defaultResource(applicationName); - List> resourceCustomizers = - resourceProviders.getIfAvailable(Collections::emptyList); - for (Supplier resourceCustomizer : resourceCustomizers) { - resource = resource.merge(resourceCustomizer.get()); + 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; } - private static Resource defaultResource(String applicationName) { - if (applicationName == null) { - return Resource.getDefault(); - } - return Resource.getDefault() - .merge(Resource.create(Attributes.of(ResourceAttributes.SERVICE_NAME, applicationName))); - } - @Bean public OpenTelemetry openTelemetry( ObjectProvider propagatorsProvider, SdkTracerProvider tracerProvider) { diff --git a/instrumentation/spring/spring-boot-autoconfigure/src/main/java/io/opentelemetry/instrumentation/spring/autoconfigure/OtelResourceAutoConfiguration.java b/instrumentation/spring/spring-boot-autoconfigure/src/main/java/io/opentelemetry/instrumentation/spring/autoconfigure/resources/OtelResourceAutoConfiguration.java similarity index 53% rename from instrumentation/spring/spring-boot-autoconfigure/src/main/java/io/opentelemetry/instrumentation/spring/autoconfigure/OtelResourceAutoConfiguration.java rename to instrumentation/spring/spring-boot-autoconfigure/src/main/java/io/opentelemetry/instrumentation/spring/autoconfigure/resources/OtelResourceAutoConfiguration.java index 9c17bc1aa758..aa5bf5b63fd3 100644 --- a/instrumentation/spring/spring-boot-autoconfigure/src/main/java/io/opentelemetry/instrumentation/spring/autoconfigure/OtelResourceAutoConfiguration.java +++ b/instrumentation/spring/spring-boot-autoconfigure/src/main/java/io/opentelemetry/instrumentation/spring/autoconfigure/resources/OtelResourceAutoConfiguration.java @@ -3,18 +3,20 @@ * SPDX-License-Identifier: Apache-2.0 */ -package io.opentelemetry.instrumentation.spring.autoconfigure; +package io.opentelemetry.instrumentation.spring.autoconfigure.resources; -import io.opentelemetry.api.common.Attributes; -import io.opentelemetry.api.common.AttributesBuilder; +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.resources.Resource; -import java.util.Map; -import java.util.function.Supplier; +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; @@ -29,44 +31,37 @@ public class OtelResourceAutoConfiguration { @Bean - public Supplier otelResourceProvider(OtelResourceProperties otelResourceProperties) { - return () -> { - AttributesBuilder attributesBuilder = Attributes.builder(); - for (Map.Entry entry : otelResourceProperties.getAttributes().entrySet()) { - attributesBuilder.put(entry.getKey(), entry.getValue()); - } - Attributes attributes = attributesBuilder.build(); - return Resource.create(attributes); - }; + public ResourceProvider otelResourceProvider(OtelResourceProperties otelResourceProperties) { + return new SpringResourceProvider(otelResourceProperties); } @Bean @ConditionalOnClass(OsResource.class) - public Supplier otelOsResourceProvider() { - return OsResource::get; + public ResourceProvider otelOsResourceProvider() { + return new OsResourceProvider(); } @Bean @ConditionalOnClass(ProcessResource.class) - public Supplier otelProcessResourceProvider() { - return ProcessResource::get; + public ResourceProvider otelProcessResourceProvider() { + return new ProcessResourceProvider(); } @Bean @ConditionalOnClass(ProcessRuntimeResource.class) - public Supplier otelProcessRuntimeResourceProvider() { - return ProcessRuntimeResource::get; + public ResourceProvider otelProcessRuntimeResourceProvider() { + return new ProcessRuntimeResourceProvider(); } @Bean @ConditionalOnClass(HostResource.class) - public Supplier otelHostResourceProvider() { - return HostResource::get; + public ResourceProvider otelHostResourceProvider() { + return new HostResourceProvider(); } @Bean @ConditionalOnClass(ContainerResource.class) - public Supplier otelContainerResource() { - return ContainerResource::get; + public ResourceProvider otelContainerResourceProvider() { + return new ContainerResourceProvider(); } } diff --git a/instrumentation/spring/spring-boot-autoconfigure/src/main/java/io/opentelemetry/instrumentation/spring/autoconfigure/OtelResourceProperties.java b/instrumentation/spring/spring-boot-autoconfigure/src/main/java/io/opentelemetry/instrumentation/spring/autoconfigure/resources/OtelResourceProperties.java similarity index 88% rename from instrumentation/spring/spring-boot-autoconfigure/src/main/java/io/opentelemetry/instrumentation/spring/autoconfigure/OtelResourceProperties.java rename to instrumentation/spring/spring-boot-autoconfigure/src/main/java/io/opentelemetry/instrumentation/spring/autoconfigure/resources/OtelResourceProperties.java index 192c92e83656..36169f4f8ec3 100644 --- a/instrumentation/spring/spring-boot-autoconfigure/src/main/java/io/opentelemetry/instrumentation/spring/autoconfigure/OtelResourceProperties.java +++ b/instrumentation/spring/spring-boot-autoconfigure/src/main/java/io/opentelemetry/instrumentation/spring/autoconfigure/resources/OtelResourceProperties.java @@ -3,7 +3,7 @@ * SPDX-License-Identifier: Apache-2.0 */ -package io.opentelemetry.instrumentation.spring.autoconfigure; +package io.opentelemetry.instrumentation.spring.autoconfigure.resources; import java.util.Collections; import java.util.Map; 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 000000000000..4ed9190ac45c --- /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 000000000000..18dcb6576752 --- /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 2f9311698c1c..daa1cfb52ce8 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 @@ -9,4 +9,4 @@ io.opentelemetry.instrumentation.spring.autoconfigure.httpclients.resttemplate.R 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.OtelResourceAutoConfiguration +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 812c0f87ce18..ff205a1627db 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 @@ -9,6 +9,8 @@ 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; @@ -78,7 +80,9 @@ void initializeOpenTelemetry() { void shouldDetermineServiceNameBySpringApplicationName() { this.contextRunner .withPropertyValues("spring.application.name=myapp-backend") - .withConfiguration(AutoConfigurations.of(OpenTelemetryAutoConfiguration.class)) + .withConfiguration( + AutoConfigurations.of( + OtelResourceAutoConfiguration.class, OpenTelemetryAutoConfiguration.class)) .run( context -> { Resource otelResource = context.getBean("otelResource", Resource.class); @@ -92,7 +96,9 @@ void shouldDetermineServiceNameBySpringApplicationName() { "when spring application name and otel service name are not set service name should be default") void hasDefaultServiceName() { this.contextRunner - .withConfiguration(AutoConfigurations.of(OpenTelemetryAutoConfiguration.class)) + .withConfiguration( + AutoConfigurations.of( + OtelResourceAutoConfiguration.class, OpenTelemetryAutoConfiguration.class)) .run( context -> { Resource otelResource = context.getBean("otelResource", Resource.class); @@ -100,4 +106,43 @@ void hasDefaultServiceName() { 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/OtelResourceAutoConfigurationTest.java b/instrumentation/spring/spring-boot-autoconfigure/src/test/java/io/opentelemetry/instrumentation/spring/autoconfigure/OtelResourceAutoConfigurationTest.java deleted file mode 100644 index 9f982127d810..000000000000 --- a/instrumentation/spring/spring-boot-autoconfigure/src/test/java/io/opentelemetry/instrumentation/spring/autoconfigure/OtelResourceAutoConfigurationTest.java +++ /dev/null @@ -1,82 +0,0 @@ -/* - * Copyright The OpenTelemetry Authors - * SPDX-License-Identifier: Apache-2.0 - */ - -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.common.AttributeKey; -import io.opentelemetry.sdk.resources.Resource; -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 service name is set it should be set as service name attribute") - void shouldDetermineServiceNameByOtelServiceName() { - this.contextRunner - .withPropertyValues( - "otel.springboot.resource.attributes.service.name=otel-name-backend", - "otel.springboot.resource.enabled=true") - .run( - context -> { - Resource otelResource = context.getBean("otelResource", Resource.class); - - assertThat(otelResource.getAttribute(SERVICE_NAME)).isEqualTo("otel-name-backend"); - }); - } - - @Test - @DisplayName( - "when otel.springboot.resource.enabled is not specified configuration should be initialized") - void shouldInitAutoConfigurationByDefault() { - this.contextRunner - .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.springboot.resource.enabled is set to false configuration should NOT be initialized") - void shouldNotInitAutoConfiguration() { - this.contextRunner - .withPropertyValues( - "otel.springboot.resource.attributes.service.name=otel-name-backend", - "otel.springboot.resource.enabled=false") - .run(context -> assertThat(context.containsBean("otelResourceProvider")).isFalse()); - } - - @Test - @DisplayName("when otel attributes are set in properties they should be put in resource") - void shouldInitializeAttributes() { - this.contextRunner - .withPropertyValues( - "otel.springboot.resource.attributes.xyz=foo", - "otel.springboot.resource.attributes.environment=dev", - "otel.springboot.resource.enabled=true") - .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"); - }); - } -} 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 000000000000..17506fffe3ed --- /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/OtelResourcePropertiesTest.java b/instrumentation/spring/spring-boot-autoconfigure/src/test/java/io/opentelemetry/instrumentation/spring/autoconfigure/resources/OtelResourcePropertiesTest.java similarity index 96% rename from instrumentation/spring/spring-boot-autoconfigure/src/test/java/io/opentelemetry/instrumentation/spring/autoconfigure/OtelResourcePropertiesTest.java rename to instrumentation/spring/spring-boot-autoconfigure/src/test/java/io/opentelemetry/instrumentation/spring/autoconfigure/resources/OtelResourcePropertiesTest.java index ed583120cf84..2b882b5cf7ee 100644 --- a/instrumentation/spring/spring-boot-autoconfigure/src/test/java/io/opentelemetry/instrumentation/spring/autoconfigure/OtelResourcePropertiesTest.java +++ b/instrumentation/spring/spring-boot-autoconfigure/src/test/java/io/opentelemetry/instrumentation/spring/autoconfigure/resources/OtelResourcePropertiesTest.java @@ -3,7 +3,7 @@ * SPDX-License-Identifier: Apache-2.0 */ -package io.opentelemetry.instrumentation.spring.autoconfigure; +package io.opentelemetry.instrumentation.spring.autoconfigure.resources; import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.entry; 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 000000000000..93756ae1c4ed --- /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")); + }); + } +}