diff --git a/instrumentation/spring/spring-boot-autoconfigure/src/main/java/io/opentelemetry/instrumentation/spring/autoconfigure/internal/properties/OtelSpringProperties.java b/instrumentation/spring/spring-boot-autoconfigure/src/main/java/io/opentelemetry/instrumentation/spring/autoconfigure/internal/properties/OtelSpringProperties.java index 39add550f4ed..4f50d260f7ca 100644 --- a/instrumentation/spring/spring-boot-autoconfigure/src/main/java/io/opentelemetry/instrumentation/spring/autoconfigure/internal/properties/OtelSpringProperties.java +++ b/instrumentation/spring/spring-boot-autoconfigure/src/main/java/io/opentelemetry/instrumentation/spring/autoconfigure/internal/properties/OtelSpringProperties.java @@ -195,12 +195,138 @@ public void setResource(Resource resource) { } } + /** + * This class is internal and is hence not for public use. Its APIs are unstable and can change at + * any time. + */ + public static final class HasExporters { + private List exporter = Collections.emptyList(); + + public List getExporter() { + return exporter; + } + + public void setExporter(List exporter) { + this.exporter = exporter; + } + } + + /** + * This class is internal and is hence not for public use. Its APIs are unstable and can change at + * any time. + */ + public static final class Instrumentation { + /** + * This class is internal and is hence not for public use. Its APIs are unstable and can change + * at any time. + */ + public static final class Http { + /** + * This class is internal and is hence not for public use. Its APIs are unstable and can + * change at any time. + */ + public static final class Client { + private List captureRequestHeaders = Collections.emptyList(); + private List captureResponseHeaders = Collections.emptyList(); + + public List getCaptureRequestHeaders() { + return captureRequestHeaders; + } + + public void setCaptureRequestHeaders(List captureRequestHeaders) { + this.captureRequestHeaders = captureRequestHeaders; + } + + public List getCaptureResponseHeaders() { + return captureResponseHeaders; + } + + public void setCaptureResponseHeaders(List captureResponseHeaders) { + this.captureResponseHeaders = captureResponseHeaders; + } + } + + /** + * This class is internal and is hence not for public use. Its APIs are unstable and can + * change at any time. + */ + public static final class Server { + private List captureRequestHeaders = Collections.emptyList(); + private List captureResponseHeaders = Collections.emptyList(); + + public List getCaptureRequestHeaders() { + return captureRequestHeaders; + } + + public void setCaptureRequestHeaders(List captureRequestHeaders) { + this.captureRequestHeaders = captureRequestHeaders; + } + + public List getCaptureResponseHeaders() { + return captureResponseHeaders; + } + + public void setCaptureResponseHeaders(List captureResponseHeaders) { + this.captureResponseHeaders = captureResponseHeaders; + } + } + + private Client client = new Client(); + + private Server server = new Server(); + + private List knownMethods = Collections.emptyList(); + + public Client getClient() { + return client; + } + + public void setClient(Client client) { + this.client = client; + } + + public Server getServer() { + return server; + } + + public void setServer(Server server) { + this.server = server; + } + + public List getKnownMethods() { + return knownMethods; + } + + public void setKnownMethods(List knownMethods) { + this.knownMethods = knownMethods; + } + } + + private Http http = new Http(); + + public Http getHttp() { + return http; + } + + public void setHttp(Http http) { + this.http = http; + } + } + private List propagators = Collections.emptyList(); private Java java = new Java(); private Experimental experimental = new Experimental(); + private HasExporters logs = new HasExporters(); + + private HasExporters metrics = new HasExporters(); + + private HasExporters traces = new HasExporters(); + + private Instrumentation instrumentation = new Instrumentation(); + public List getPropagators() { return propagators; } @@ -225,6 +351,38 @@ public void setExperimental(Experimental experimental) { this.experimental = experimental; } + public HasExporters getLogs() { + return logs; + } + + public void setLogs(HasExporters logs) { + this.logs = logs; + } + + public HasExporters getMetrics() { + return metrics; + } + + public void setMetrics(HasExporters metrics) { + this.metrics = metrics; + } + + public HasExporters getTraces() { + return traces; + } + + public void setTraces(HasExporters traces) { + this.traces = traces; + } + + public Instrumentation getInstrumentation() { + return instrumentation; + } + + public void setInstrumentation(Instrumentation instrumentation) { + this.instrumentation = instrumentation; + } + public List getJavaEnabledResourceProviders() { return java.getEnabled().getResource().getProviders(); } @@ -240,4 +398,36 @@ public List getExperimentalMetricsViewConfig() { public List getExperimentalResourceDisabledKeys() { return experimental.getResource().getDisabled().getKeys(); } + + public List getLogsExporter() { + return logs.getExporter(); + } + + public List getMetricsExporter() { + return metrics.getExporter(); + } + + public List getTracesExporter() { + return traces.getExporter(); + } + + public List getHttpClientCaptureRequestHeaders() { + return instrumentation.getHttp().getClient().getCaptureRequestHeaders(); + } + + public List getHttpClientCaptureResponseHeaders() { + return instrumentation.getHttp().getClient().getCaptureResponseHeaders(); + } + + public List getHttpServerCaptureRequestHeaders() { + return instrumentation.getHttp().getServer().getCaptureRequestHeaders(); + } + + public List getHttpServerCaptureResponseHeaders() { + return instrumentation.getHttp().getServer().getCaptureResponseHeaders(); + } + + public List getHttpKnownMethods() { + return instrumentation.getHttp().getKnownMethods(); + } } diff --git a/instrumentation/spring/spring-boot-autoconfigure/src/main/java/io/opentelemetry/instrumentation/spring/autoconfigure/internal/properties/SpringConfigProperties.java b/instrumentation/spring/spring-boot-autoconfigure/src/main/java/io/opentelemetry/instrumentation/spring/autoconfigure/internal/properties/SpringConfigProperties.java index 82c400f6f362..05efa521d59a 100644 --- a/instrumentation/spring/spring-boot-autoconfigure/src/main/java/io/opentelemetry/instrumentation/spring/autoconfigure/internal/properties/SpringConfigProperties.java +++ b/instrumentation/spring/spring-boot-autoconfigure/src/main/java/io/opentelemetry/instrumentation/spring/autoconfigure/internal/properties/SpringConfigProperties.java @@ -32,7 +32,7 @@ public class SpringConfigProperties implements ConfigProperties { private final OtelResourceProperties resourceProperties; private final ConfigProperties otelSdkProperties; private final ConfigProperties customizedListProperties; - private final Map> listPropertyValues = new HashMap<>(); + private final Map> listPropertyValues; static final String DISABLED_KEY = "otel.java.disabled.resource.providers"; static final String ENABLED_KEY = "otel.java.enabled.resource.providers"; @@ -52,15 +52,46 @@ public SpringConfigProperties( this.customizedListProperties = createCustomizedListProperties(otelSdkProperties, otelSpringProperties); - listPropertyValues.put(ENABLED_KEY, otelSpringProperties.getJavaEnabledResourceProviders()); - listPropertyValues.put(DISABLED_KEY, otelSpringProperties.getJavaDisabledResourceProviders()); - listPropertyValues.put( + listPropertyValues = createListPropertyValues(otelSpringProperties); + } + + private static Map> createListPropertyValues( + OtelSpringProperties otelSpringProperties) { + Map> values = new HashMap<>(); + + // SDK + values.put(ENABLED_KEY, otelSpringProperties.getJavaEnabledResourceProviders()); + values.put(DISABLED_KEY, otelSpringProperties.getJavaDisabledResourceProviders()); + values.put( "otel.experimental.metrics.view.config", otelSpringProperties.getExperimentalMetricsViewConfig()); - listPropertyValues.put( + values.put( "otel.experimental.resource.disabled.keys", otelSpringProperties.getExperimentalResourceDisabledKeys()); - listPropertyValues.put("otel.propagators", otelSpringProperties.getPropagators()); + values.put("otel.propagators", otelSpringProperties.getPropagators()); + + // exporters + values.put("otel.logs.exporter", otelSpringProperties.getLogsExporter()); + values.put("otel.metrics.exporter", otelSpringProperties.getMetricsExporter()); + values.put("otel.traces.exporter", otelSpringProperties.getTracesExporter()); + + // instrumentations + values.put( + "otel.instrumentation.http.client.capture-request-headers", + otelSpringProperties.getHttpClientCaptureRequestHeaders()); + values.put( + "otel.instrumentation.http.client.capture-response-headers", + otelSpringProperties.getHttpClientCaptureResponseHeaders()); + values.put( + "otel.instrumentation.http.server.capture-request-headers", + otelSpringProperties.getHttpServerCaptureRequestHeaders()); + values.put( + "otel.instrumentation.http.server.capture-response-headers", + otelSpringProperties.getHttpServerCaptureResponseHeaders()); + values.put( + "otel.instrumentation.http.known-methods", otelSpringProperties.getHttpKnownMethods()); + + return values; } private static Map createMapForListProperty( @@ -174,7 +205,9 @@ public List getList(String name) { if (!c.isEmpty()) { return c; } - return list; + if (!list.isEmpty()) { + return list; + } } return or(environment.getProperty(normalizedName, List.class), otelSdkProperties.getList(name)); diff --git a/instrumentation/spring/spring-boot-autoconfigure/src/main/resources/META-INF/additional-spring-configuration-metadata.json b/instrumentation/spring/spring-boot-autoconfigure/src/main/resources/META-INF/additional-spring-configuration-metadata.json index a0b04d97f9fc..68a06350a09d 100644 --- a/instrumentation/spring/spring-boot-autoconfigure/src/main/resources/META-INF/additional-spring-configuration-metadata.json +++ b/instrumentation/spring/spring-boot-autoconfigure/src/main/resources/META-INF/additional-spring-configuration-metadata.json @@ -425,8 +425,8 @@ }, { "name": "otel.instrumentation.logback-appender.experimental.capture-mdc-attributes", - "type": "java.util.List", - "description": "MDC attributes to capture. Use the wildcard character * to capture all attributes." + "type": "java.lang.String", + "description": "MDC attributes to capture. Use the wildcard character * to capture all attributes. This is a comma-separated list of attribute names." }, { "name": "otel.instrumentation.logback-mdc.enabled", diff --git a/instrumentation/spring/spring-boot-autoconfigure/src/test/java/io/opentelemetry/instrumentation/spring/autoconfigure/internal/properties/OtlpExporterPropertiesTest.java b/instrumentation/spring/spring-boot-autoconfigure/src/test/java/io/opentelemetry/instrumentation/spring/autoconfigure/internal/properties/OtlpExporterPropertiesTest.java deleted file mode 100644 index 3cfaa03b5227..000000000000 --- a/instrumentation/spring/spring-boot-autoconfigure/src/test/java/io/opentelemetry/instrumentation/spring/autoconfigure/internal/properties/OtlpExporterPropertiesTest.java +++ /dev/null @@ -1,98 +0,0 @@ -/* - * Copyright The OpenTelemetry Authors - * SPDX-License-Identifier: Apache-2.0 - */ - -package io.opentelemetry.instrumentation.spring.autoconfigure.internal.properties; - -import static org.assertj.core.api.Assertions.assertThat; -import static org.assertj.core.api.Assertions.entry; - -import io.opentelemetry.instrumentation.spring.autoconfigure.OpenTelemetryAutoConfiguration; -import io.opentelemetry.sdk.autoconfigure.spi.ConfigProperties; -import io.opentelemetry.sdk.autoconfigure.spi.internal.DefaultConfigProperties; -import java.util.Arrays; -import java.util.Collections; -import java.util.stream.Stream; -import org.junit.jupiter.api.DisplayName; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.params.ParameterizedTest; -import org.junit.jupiter.params.provider.Arguments; -import org.junit.jupiter.params.provider.MethodSource; -import org.springframework.boot.autoconfigure.AutoConfigurations; -import org.springframework.boot.test.context.assertj.AssertableApplicationContext; -import org.springframework.boot.test.context.runner.ApplicationContextRunner; -import org.springframework.core.env.Environment; -import org.springframework.expression.spel.standard.SpelExpressionParser; - -class OtlpExporterPropertiesTest { - - private static final String[] HEADER_KEYS = { - "otel.exporter.otlp.traces.headers", - "otel.exporter.otlp.metrics.headers", - "otel.exporter.otlp.logs.headers", - "otel.exporter.otlp.headers", - }; - - private final ApplicationContextRunner contextRunner = - new ApplicationContextRunner() - .withConfiguration(AutoConfigurations.of(OpenTelemetryAutoConfiguration.class)) - .withPropertyValues( - "otel.traces.exporter=none", "otel.metrics.exporter=none", "otel.logs.exporter=none"); - - public static Stream headerKeys() { - return Arrays.stream(HEADER_KEYS).map(Arguments::of); - } - - @Test - @DisplayName("test all property types") - void allTypes() { - this.contextRunner - .withPropertyValues( - "otel.exporter.otlp.enabled=true", - "otel.exporter.otlp.timeout=1s", - "otel.exporter.otlp.compression=gzip") - .run( - context -> { - ConfigProperties config = getConfig(context); - assertThat(config.getString("otel.exporter.otlp.compression")).isEqualTo("gzip"); - assertThat(config.getBoolean("otel.exporter.otlp.enabled")).isTrue(); - assertThat(config.getDuration("otel.exporter.otlp.timeout")) - .isEqualByComparingTo(java.time.Duration.ofSeconds(1)); - }); - } - - @ParameterizedTest - @MethodSource("headerKeys") - @DisplayName("should map headers from spring properties") - void mapFlatHeaders(String key) { - this.contextRunner - .withSystemProperties(key + "=a=1,b=2") - .run( - context -> - assertThat(getConfig(context).getMap(key)) - .containsExactly(entry("a", "1"), entry("b", "2"))); - } - - @ParameterizedTest - @MethodSource("headerKeys") - @DisplayName("should map headers from spring application.yaml") - void mapObjectHeaders(String key) { - this.contextRunner - .withPropertyValues(key + ".a=1", key + ".b=2") - .run( - context -> - assertThat(getConfig(context).getMap(key)) - .containsExactly(entry("a", "1"), entry("b", "2"))); - } - - private static ConfigProperties getConfig(AssertableApplicationContext context) { - return new SpringConfigProperties( - context.getBean("environment", Environment.class), - new SpelExpressionParser(), - context.getBean(OtlpExporterProperties.class), - new OtelResourceProperties(), - new OtelSpringProperties(), - DefaultConfigProperties.createFromMap(Collections.emptyMap())); - } -} diff --git a/instrumentation/spring/spring-boot-autoconfigure/src/test/java/io/opentelemetry/instrumentation/spring/autoconfigure/internal/properties/SpringConfigPropertiesTest.java b/instrumentation/spring/spring-boot-autoconfigure/src/test/java/io/opentelemetry/instrumentation/spring/autoconfigure/internal/properties/SpringConfigPropertiesTest.java new file mode 100644 index 000000000000..8bb38dc453cf --- /dev/null +++ b/instrumentation/spring/spring-boot-autoconfigure/src/test/java/io/opentelemetry/instrumentation/spring/autoconfigure/internal/properties/SpringConfigPropertiesTest.java @@ -0,0 +1,166 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.instrumentation.spring.autoconfigure.internal.properties; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.entry; + +import io.opentelemetry.instrumentation.spring.autoconfigure.OpenTelemetryAutoConfiguration; +import io.opentelemetry.sdk.autoconfigure.spi.ConfigProperties; +import io.opentelemetry.sdk.autoconfigure.spi.internal.DefaultConfigProperties; +import java.util.Arrays; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.stream.Stream; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; +import org.springframework.boot.autoconfigure.AutoConfigurations; +import org.springframework.boot.test.context.ConfigDataApplicationContextInitializer; +import org.springframework.boot.test.context.assertj.AssertableApplicationContext; +import org.springframework.boot.test.context.runner.ApplicationContextRunner; +import org.springframework.core.env.Environment; +import org.springframework.expression.spel.standard.SpelExpressionParser; + +class SpringConfigPropertiesTest { + private final ApplicationContextRunner contextRunner = + new ApplicationContextRunner() + .withConfiguration(AutoConfigurations.of(OpenTelemetryAutoConfiguration.class)) + .withPropertyValues( + "otel.traces.exporter=none", "otel.metrics.exporter=none", "otel.logs.exporter=none"); + + public static Stream headerKeys() { + return Arrays.stream( + new String[] { + "otel.exporter.otlp.traces.headers", + "otel.exporter.otlp.metrics.headers", + "otel.exporter.otlp.logs.headers", + "otel.exporter.otlp.headers", + }) + .map(Arguments::of); + } + + @Test + @DisplayName("test all property types") + void allTypes() { + this.contextRunner + .withPropertyValues( + "otel.exporter.otlp.enabled=true", + "otel.exporter.otlp.timeout=1s", + "otel.exporter.otlp.compression=gzip") + .run( + context -> { + ConfigProperties config = getConfig(context); + assertThat(config.getString("otel.exporter.otlp.compression")).isEqualTo("gzip"); + assertThat(config.getBoolean("otel.exporter.otlp.enabled")).isTrue(); + assertThat(config.getDuration("otel.exporter.otlp.timeout")) + .isEqualByComparingTo(java.time.Duration.ofSeconds(1)); + }); + } + + @ParameterizedTest + @MethodSource("headerKeys") + @DisplayName("should map headers from spring properties") + void mapFlatHeaders(String key) { + this.contextRunner + .withSystemProperties(key + "=a=1,b=2") + .run( + context -> + assertThat(getConfig(context).getMap(key)) + .containsExactly(entry("a", "1"), entry("b", "2"))); + } + + @ParameterizedTest + @MethodSource("headerKeys") + @DisplayName("should map headers from spring application.yaml") + void mapObjectHeaders(String key) { + this.contextRunner + .withPropertyValues(key + ".a=1", key + ".b=2") + .run( + context -> + assertThat(getConfig(context).getMap(key)) + .containsExactly(entry("a", "1"), entry("b", "2"))); + } + + public static Stream listProperties() { + return Stream.of( + Arguments.of("otel.experimental.metrics.view.config", Arrays.asList("a", "b")), + Arguments.of("otel.experimental.resource.disabled.keys", Arrays.asList("a", "b")), + Arguments.of("otel.propagators", Arrays.asList("baggage", "b3")), + Arguments.of("otel.logs.exporter", Collections.singletonList("console")), + Arguments.of("otel.metrics.exporter", Collections.singletonList("console")), + Arguments.of("otel.traces.exporter", Collections.singletonList("console")), + Arguments.of( + "otel.instrumentation.http.client.capture-request-headers", Arrays.asList("a", "b")), + Arguments.of( + "otel.instrumentation.http.client.capture-response-headers", Arrays.asList("a", "b")), + Arguments.of( + "otel.instrumentation.http.server.capture-request-headers", Arrays.asList("a", "b")), + Arguments.of( + "otel.instrumentation.http.server.capture-response-headers", Arrays.asList("a", "b")), + Arguments.of("otel.instrumentation.http.known-methods", Arrays.asList("a", "b"))); + } + + @ParameterizedTest + @MethodSource("listProperties") + @DisplayName("should map list from application.yaml list") + // See the application.yaml file + void listsShouldWorkWithYaml(String key, List expected) { + new ApplicationContextRunner() + .withConfiguration(AutoConfigurations.of(OpenTelemetryAutoConfiguration.class)) + .withInitializer(new ConfigDataApplicationContextInitializer()) + .run( + context -> + assertThat(getConfig(context).getList(key)) + .containsExactlyInAnyOrderElementsOf(expected)); + } + + @Test + @DisplayName("when map is set in properties in a row it should be available in config") + void shouldInitializeAttributesByMap() { + this.contextRunner + .withPropertyValues( + "otel.resource.attributes.environment=dev", + "otel.resource.attributes.xyz=foo", + "otel.resource.attributes.service.instance.id=id-example") + .run( + context -> { + Map fallback = new HashMap<>(); + fallback.put("fallback", "fallbackVal"); + fallback.put("otel.resource.attributes", "foo=fallback"); + + SpringConfigProperties config = getConfig(context, fallback); + + assertThat(config.getMap("otel.resource.attributes")) + .contains( + entry("environment", "dev"), + entry("xyz", "foo"), + entry("service.instance.id", "id-example"), + entry("foo", "fallback")); + + assertThat(config.getString("fallback")).isEqualTo("fallbackVal"); + }); + } + + private static ConfigProperties getConfig(AssertableApplicationContext context) { + return getConfig(context, Collections.emptyMap()); + } + + private static SpringConfigProperties getConfig( + AssertableApplicationContext context, Map fallback) { + return new SpringConfigProperties( + context.getBean("environment", Environment.class), + new SpelExpressionParser(), + context.getBean(OtlpExporterProperties.class), + context.getBean(OtelResourceProperties.class), + context.getBean(OtelSpringProperties.class), + DefaultConfigProperties.createFromMap(fallback)); + } +} diff --git a/instrumentation/spring/spring-boot-autoconfigure/src/test/java/io/opentelemetry/instrumentation/spring/autoconfigure/internal/resources/SpringConfigPropertiesTest.java b/instrumentation/spring/spring-boot-autoconfigure/src/test/java/io/opentelemetry/instrumentation/spring/autoconfigure/internal/resources/SpringConfigPropertiesTest.java deleted file mode 100644 index 2646837ed789..000000000000 --- a/instrumentation/spring/spring-boot-autoconfigure/src/test/java/io/opentelemetry/instrumentation/spring/autoconfigure/internal/resources/SpringConfigPropertiesTest.java +++ /dev/null @@ -1,67 +0,0 @@ -/* - * Copyright The OpenTelemetry Authors - * SPDX-License-Identifier: Apache-2.0 - */ - -package io.opentelemetry.instrumentation.spring.autoconfigure.internal.resources; - -import static org.assertj.core.api.Assertions.assertThat; -import static org.assertj.core.api.Assertions.entry; - -import io.opentelemetry.instrumentation.spring.autoconfigure.OpenTelemetryAutoConfiguration; -import io.opentelemetry.instrumentation.spring.autoconfigure.internal.properties.OtelResourceProperties; -import io.opentelemetry.instrumentation.spring.autoconfigure.internal.properties.OtelSpringProperties; -import io.opentelemetry.instrumentation.spring.autoconfigure.internal.properties.OtlpExporterProperties; -import io.opentelemetry.instrumentation.spring.autoconfigure.internal.properties.SpringConfigProperties; -import io.opentelemetry.sdk.autoconfigure.spi.internal.DefaultConfigProperties; -import java.util.HashMap; -import java.util.Map; -import org.junit.jupiter.api.DisplayName; -import org.junit.jupiter.api.Test; -import org.springframework.boot.autoconfigure.AutoConfigurations; -import org.springframework.boot.test.context.runner.ApplicationContextRunner; -import org.springframework.core.env.Environment; -import org.springframework.expression.spel.standard.SpelExpressionParser; - -class SpringConfigPropertiesTest { - 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 - .withConfiguration(AutoConfigurations.of(OpenTelemetryAutoConfiguration.class)) - .withPropertyValues( - "otel.metrics.exporter=none", // to suppress confusing error log - "otel.logs.exporter=none", - "otel.traces.exporter=none", - "otel.resource.attributes.environment=dev", - "otel.resource.attributes.xyz=foo", - "otel.resource.attributes.service.instance.id=id-example") - .run( - context -> { - Environment env = context.getBean("environment", Environment.class); - Map fallback = new HashMap<>(); - fallback.put("fallback", "fallbackVal"); - fallback.put("otel.resource.attributes", "foo=fallback"); - - SpringConfigProperties config = - new SpringConfigProperties( - env, - new SpelExpressionParser(), - context.getBean(OtlpExporterProperties.class), - context.getBean(OtelResourceProperties.class), - context.getBean(OtelSpringProperties.class), - DefaultConfigProperties.createFromMap(fallback)); - - assertThat(config.getMap("otel.resource.attributes")) - .contains( - entry("environment", "dev"), - entry("xyz", "foo"), - entry("service.instance.id", "id-example"), - entry("foo", "fallback")); - - assertThat(config.getString("fallback")).isEqualTo("fallbackVal"); - }); - } -} diff --git a/instrumentation/spring/spring-boot-autoconfigure/src/test/resources/application.yaml b/instrumentation/spring/spring-boot-autoconfigure/src/test/resources/application.yaml new file mode 100644 index 000000000000..c9485005a6a7 --- /dev/null +++ b/instrumentation/spring/spring-boot-autoconfigure/src/test/resources/application.yaml @@ -0,0 +1,25 @@ +otel: + experimental: + metrics: + view: + config: [ a,b ] + resource: + disabled: + keys: [ a,b ] + propagators: [ baggage, b3 ] + logs: + exporter: [ console ] + metrics: + exporter: [ console ] + traces: + exporter: [ console ] + + instrumentation: + http: + known-methods: [ a,b ] + client: + capture-request-headers: [ a,b ] + capture-response-headers: [ a,b ] + server: + capture-request-headers: [ a,b ] + capture-response-headers: [ a,b ] diff --git a/smoke-tests-otel-starter/spring-boot-common/src/main/java/io/opentelemetry/spring/smoketest/AbstractOtelSpringStarterSmokeTest.java b/smoke-tests-otel-starter/spring-boot-common/src/main/java/io/opentelemetry/spring/smoketest/AbstractOtelSpringStarterSmokeTest.java index ebec55db783f..0709434bc883 100644 --- a/smoke-tests-otel-starter/spring-boot-common/src/main/java/io/opentelemetry/spring/smoketest/AbstractOtelSpringStarterSmokeTest.java +++ b/smoke-tests-otel-starter/spring-boot-common/src/main/java/io/opentelemetry/spring/smoketest/AbstractOtelSpringStarterSmokeTest.java @@ -28,6 +28,7 @@ import io.opentelemetry.semconv.incubating.CodeIncubatingAttributes; import io.opentelemetry.semconv.incubating.DbIncubatingAttributes; import io.opentelemetry.semconv.incubating.ServiceIncubatingAttributes; +import java.net.URI; import java.util.Collections; import java.util.List; import org.assertj.core.api.AbstractCharSequenceAssert; @@ -46,6 +47,9 @@ import org.springframework.context.event.EventListener; import org.springframework.core.annotation.Order; import org.springframework.core.env.Environment; +import org.springframework.http.HttpHeaders; +import org.springframework.http.HttpMethod; +import org.springframework.http.RequestEntity; import org.springframework.jdbc.core.JdbcTemplate; import org.springframework.web.client.RestTemplate; @@ -142,7 +146,13 @@ void propertyConversion() { @Test @org.junit.jupiter.api.Order(1) void shouldSendTelemetry() { - testRestTemplate.getForObject(OtelSpringStarterSmokeTestController.PING, String.class); + HttpHeaders headers = new HttpHeaders(); + headers.add("key", "value"); + + testRestTemplate.exchange( + new RequestEntity<>( + null, headers, HttpMethod.GET, URI.create(OtelSpringStarterSmokeTestController.PING)), + String.class); // Span testing.waitAndAssertTraces( @@ -186,6 +196,9 @@ void shouldSendTelemetry() { equalTo(HttpAttributes.HTTP_ROUTE, "/ping"), equalTo(ServerAttributes.SERVER_ADDRESS, "localhost"), equalTo(ClientAttributes.CLIENT_ADDRESS, "127.0.0.1"), + equalTo( + AttributeKey.stringArrayKey("http.request.header.key"), + Collections.singletonList("value")), satisfies( ServerAttributes.SERVER_PORT, integerAssert -> integerAssert.isNotZero())), diff --git a/smoke-tests-otel-starter/spring-boot-common/src/main/resources/application.yaml b/smoke-tests-otel-starter/spring-boot-common/src/main/resources/application.yaml index b8aec4b09f6d..4da76f769a0d 100644 --- a/smoke-tests-otel-starter/spring-boot-common/src/main/resources/application.yaml +++ b/smoke-tests-otel-starter/spring-boot-common/src/main/resources/application.yaml @@ -13,6 +13,7 @@ otel: emit-experimental-telemetry: true server: emit-experimental-telemetry: true + capture-request-headers: [key] propagators: - b3 resource: