diff --git a/instrumentation/spring/spring-boot-autoconfigure/build.gradle.kts b/instrumentation/spring/spring-boot-autoconfigure/build.gradle.kts index 5752ad25d42f..8ce5e4f8cfdb 100644 --- a/instrumentation/spring/spring-boot-autoconfigure/build.gradle.kts +++ b/instrumentation/spring/spring-boot-autoconfigure/build.gradle.kts @@ -180,6 +180,7 @@ testing { dependencies { implementation(project()) implementation("io.opentelemetry:opentelemetry-sdk") + implementation("io.opentelemetry:opentelemetry-exporter-otlp") implementation("org.springframework.boot:spring-boot-starter-test:$springBootVersion") { exclude("org.junit.vintage", "junit-vintage-engine") } diff --git a/instrumentation/spring/spring-boot-autoconfigure/src/main/java/io/opentelemetry/instrumentation/spring/autoconfigure/EmbeddedConfigFile.java b/instrumentation/spring/spring-boot-autoconfigure/src/main/java/io/opentelemetry/instrumentation/spring/autoconfigure/EmbeddedConfigFile.java index ffbb11b6b9c6..b2222baf489f 100644 --- a/instrumentation/spring/spring-boot-autoconfigure/src/main/java/io/opentelemetry/instrumentation/spring/autoconfigure/EmbeddedConfigFile.java +++ b/instrumentation/spring/spring-boot-autoconfigure/src/main/java/io/opentelemetry/instrumentation/spring/autoconfigure/EmbeddedConfigFile.java @@ -11,6 +11,7 @@ import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.OpenTelemetryConfigurationModel; import java.util.ArrayList; import java.util.HashMap; +import java.util.Locale; import java.util.Map; import java.util.Objects; import java.util.regex.Matcher; @@ -62,6 +63,24 @@ private static Map extractSpringProperties(ConfigurableEnvironme if (Objects.equals(property, "")) { property = null; // spring returns empty string for yaml null } + if (propertyName.contains("[")) { + // fix override via env var or system property + // see + // https://docs.spring.io/spring-boot/reference/features/external-config.html#features.external-config.typesafe-configuration-properties.relaxed-binding + // For example, the configuration property my.service[0].other would use an + // environment variable named MY_SERVICE_0_OTHER. + String envVarName = + propertyName + .replace("[", "_") + .replace("]", "") + .replace(".", "_") + .toUpperCase(Locale.ROOT); + String envVarValue = environment.getProperty(envVarName); + if (envVarValue != null) { + property = envVarValue; + } + } + props.put(propertyName.substring("otel.".length()), property); } } 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 0be0df45ca60..bbb40a59a2cb 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 @@ -39,7 +39,6 @@ import io.opentelemetry.sdk.extension.incubator.fileconfig.DeclarativeConfiguration; import io.opentelemetry.sdk.extension.incubator.fileconfig.DeclarativeConfigurationCustomizerProvider; import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.OpenTelemetryConfigurationModel; -import java.io.IOException; import java.util.Collections; import java.util.List; import java.util.Optional; @@ -157,7 +156,7 @@ static class EmbeddedConfigFileConfig { @Bean public OpenTelemetryConfigurationModel openTelemetryConfigurationModel( - ConfigurableEnvironment environment) throws IOException { + ConfigurableEnvironment environment) { return EmbeddedConfigFile.extractModel(environment); } diff --git a/instrumentation/spring/spring-boot-autoconfigure/src/testDeclarativeConfig/java/io/opentelemetry/instrumentation/spring/autoconfigure/DeclarativeConfigTest.java b/instrumentation/spring/spring-boot-autoconfigure/src/testDeclarativeConfig/java/io/opentelemetry/instrumentation/spring/autoconfigure/DeclarativeConfigTest.java index d15468a17944..7bb5b53f5832 100644 --- a/instrumentation/spring/spring-boot-autoconfigure/src/testDeclarativeConfig/java/io/opentelemetry/instrumentation/spring/autoconfigure/DeclarativeConfigTest.java +++ b/instrumentation/spring/spring-boot-autoconfigure/src/testDeclarativeConfig/java/io/opentelemetry/instrumentation/spring/autoconfigure/DeclarativeConfigTest.java @@ -131,4 +131,39 @@ void shouldNotLoadInstrumentationWhenExplicitlyDisabled() { "otel.instrumentation/development.java.spring_web.enabled=false") .run(context -> assertThat(context).doesNotHaveBean("otelRestTemplateBeanPostProcessor")); } + + @Test + void envVarOverrideSpringStyle() { + this.contextRunner + // this is typically set via env var + .withSystemProperties( + "OTEL_TRACER_PROVIDER_PROCESSORS_0_BATCH_EXPORTER_OTLP_HTTP_ENDPOINT=http://custom:4318/v1/traces") + .run( + context -> + assertThat(context) + .getBean(OpenTelemetry.class) + .isNotNull() + .satisfies( + c -> + assertThat(c.toString()) + .contains( + "OtlpHttpSpanExporter{endpoint=http://custom:4318/v1/traces"))); + } + + @Test + void envVarOverrideOtelStyle() { + this.contextRunner + // this is typically set via env var + .withSystemProperties("OTEL_EXPORTER_OTLP_ENDPOINT=http://custom:4318") + .run( + context -> + assertThat(context) + .getBean(OpenTelemetry.class) + .isNotNull() + .satisfies( + c -> + assertThat(c.toString()) + .contains( + "OtlpHttpSpanExporter{endpoint=http://custom:4318/v1/traces"))); + } } diff --git a/instrumentation/spring/spring-boot-autoconfigure/src/testDeclarativeConfig/resources/application.yaml b/instrumentation/spring/spring-boot-autoconfigure/src/testDeclarativeConfig/resources/application.yaml index 8f263bc8ff50..455ea6b8d568 100644 --- a/instrumentation/spring/spring-boot-autoconfigure/src/testDeclarativeConfig/resources/application.yaml +++ b/instrumentation/spring/spring-boot-autoconfigure/src/testDeclarativeConfig/resources/application.yaml @@ -2,6 +2,13 @@ otel: # "file_format" serves as opt-in to the new file format file_format: "1.0-rc.1" + tracer_provider: + processors: + - batch: + exporter: + otlp_http: + endpoint: ${OTEL_EXPORTER_OTLP_ENDPOINT:http://localhost:4318}/v1/traces # to test that we can use env vars in declarative config + # very lightweight test to make sure the declarative config is loaded # the full config is tested in smoke-tests-otel-starter/spring-boot-2/src/testDeclarativeConfig instrumentation/development: