diff --git a/documentation/spring-boot-docs/src/docs/antora/modules/reference/pages/actuator/metrics.adoc b/documentation/spring-boot-docs/src/docs/antora/modules/reference/pages/actuator/metrics.adoc index 7d1a609e968..81156d6af0d 100644 --- a/documentation/spring-boot-docs/src/docs/antora/modules/reference/pages/actuator/metrics.adoc +++ b/documentation/spring-boot-docs/src/docs/antora/modules/reference/pages/actuator/metrics.adoc @@ -731,7 +731,8 @@ NOTE: javadoc:org.springframework.jms.core.JmsClient[] and javadoc:org.springfra Auto-configuration enables the instrumentation of all requests handled by Spring MVC controllers and functional handlers. By default, metrics are generated with the name, `http.server.requests`. -You can customize the name by setting the configprop:management.observations.http.server.requests.name[] property. +If you are xref:actuator/observability.adoc#actuator.observability.semantic-conventions[using Micrometer's semantic conventions], set the configprop:management.observations.http.server.requests.name[] property to customize the name. +If you are using OpenTelemtry's semantic conventions, the name cannot be customized. See the {url-spring-framework-docs}/integration/observability.html#observability.http-server.servlet[Spring Framework reference documentation for more information on produced observations]. @@ -751,7 +752,8 @@ To customize the filter, provide a javadoc:org.springframework.context.annotatio Auto-configuration enables the instrumentation of all requests handled by Spring WebFlux controllers and functional handlers. By default, metrics are generated with the name, `http.server.requests`. -You can customize the name by setting the configprop:management.observations.http.server.requests.name[] property. +If you are xref:actuator/observability.adoc#actuator.observability.semantic-conventions[using Micrometer's semantic conventions], set the configprop:management.observations.http.server.requests.name[] property to customize the name. +If you are using OpenTelemtry's semantic conventions, the name cannot be customized. See the {url-spring-framework-docs}/integration/observability.html#observability.http-server.reactive[Spring Framework reference documentation for more information on produced observations]. diff --git a/documentation/spring-boot-docs/src/docs/antora/modules/reference/pages/actuator/observability.adoc b/documentation/spring-boot-docs/src/docs/antora/modules/reference/pages/actuator/observability.adoc index b8f5364825c..4211e0d3e2c 100644 --- a/documentation/spring-boot-docs/src/docs/antora/modules/reference/pages/actuator/observability.adoc +++ b/documentation/spring-boot-docs/src/docs/antora/modules/reference/pages/actuator/observability.adoc @@ -101,14 +101,26 @@ In that case you can either disable the automatic instrumentation using xref:ref +[[actuator.observability.semantic-conventions]] +== Semantic Conventions + +Semantic conventions govern things like metric names and tag names and values. +By default, the conventions defined by Micrometer and the various Spring projects are used. +To switch to OpenTelemetry's conventions, set configprop:management.observations.conventions[] to `open-telemetry`. +OpenTelemetry conventions are limited to those that are stable. +When using OpenTelemetry's conventions, note that certain properties for customizing meter names and the like will no longer take effect. + + + [[actuator.observability.opentelemetry]] == OpenTelemetry Support NOTE: There are several ways to support https://opentelemetry.io/[OpenTelemetry] in your application. You can use the https://opentelemetry.io/docs/zero-code/java/agent/[OpenTelemetry Java Agent] or the https://opentelemetry.io/docs/zero-code/java/spring-boot-starter/[OpenTelemetry Spring Boot Starter], -which are supported by the OTel community; the metrics and traces use the semantic conventions defined by OTel libraries. -This documentation describes OpenTelemetry as officially supported by the Spring team, using Micrometer and the OTLP exporter; -the metrics and traces use the semantic conventions described in the Spring projects documentation, such as {url-spring-framework-docs}/integration/observability.html[Spring Framework]. +which are supported by the OTel community. +In this case, the metrics and traces always use the semantic conventions defined by OTel libraries. +This documentation describes OpenTelemetry as officially supported by the Spring team, using Micrometer and the OTLP exporter. +In this case, the metrics and traces use the semantic conventions described in the Spring projects documentation, such as {url-spring-framework-docs}/integration/observability.html[Spring Framework], but can be <> to use OpenTelemetry's stable conventions. Spring Boot's actuator module includes basic support for OpenTelemetry. diff --git a/module/spring-boot-micrometer-metrics/src/main/java/org/springframework/boot/micrometer/metrics/autoconfigure/jvm/JvmMetricsAutoConfiguration.java b/module/spring-boot-micrometer-metrics/src/main/java/org/springframework/boot/micrometer/metrics/autoconfigure/jvm/JvmMetricsAutoConfiguration.java index 48b3e9cdd99..93589f4c290 100644 --- a/module/spring-boot-micrometer-metrics/src/main/java/org/springframework/boot/micrometer/metrics/autoconfigure/jvm/JvmMetricsAutoConfiguration.java +++ b/module/spring-boot-micrometer-metrics/src/main/java/org/springframework/boot/micrometer/metrics/autoconfigure/jvm/JvmMetricsAutoConfiguration.java @@ -55,7 +55,7 @@ import org.springframework.boot.context.properties.PropertyMapper; import org.springframework.boot.micrometer.metrics.autoconfigure.CompositeMeterRegistryAutoConfiguration; import org.springframework.boot.micrometer.metrics.autoconfigure.MetricsAutoConfiguration; import org.springframework.boot.micrometer.observation.autoconfigure.ObservationProperties; -import org.springframework.boot.micrometer.observation.autoconfigure.ObservationProperties.ConventionsVariant; +import org.springframework.boot.micrometer.observation.autoconfigure.condition.SemanticConventions; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.ImportRuntimeHints; @@ -126,7 +126,7 @@ public final class JvmMetricsAutoConfiguration { return new JvmThreadMetrics(Collections.emptyList(), deprecatedConventions); } JvmThreadMetrics.Builder builder = JvmThreadMetrics.builder(); - if (observationProperties.getConventions() == ConventionsVariant.OPENTELEMETRY) { + if (observationProperties.getConventions() == SemanticConventions.OPEN_TELEMETRY) { builder.openTelemetryConventions(); } PropertyMapper map = PropertyMapper.get(); @@ -192,7 +192,7 @@ public final class JvmMetricsAutoConfiguration { JvmMemoryMetrics create(ObservationProperties observationProperties) { JvmMemoryMetrics.Builder builder = JvmMemoryMetrics.builder(); - if (observationProperties.getConventions() == ConventionsVariant.OPENTELEMETRY) { + if (observationProperties.getConventions() == SemanticConventions.OPEN_TELEMETRY) { builder.openTelemetryConventions(); } PropertyMapper map = PropertyMapper.get(); @@ -216,7 +216,7 @@ public final class JvmMetricsAutoConfiguration { ClassLoaderMetrics create(ObservationProperties observationProperties) { ClassLoaderMetrics.Builder builder = ClassLoaderMetrics.builder(); - if (observationProperties.getConventions() == ConventionsVariant.OPENTELEMETRY) { + if (observationProperties.getConventions() == SemanticConventions.OPEN_TELEMETRY) { builder.openTelemetryConventions(); } PropertyMapper map = PropertyMapper.get(); diff --git a/module/spring-boot-micrometer-metrics/src/main/java/org/springframework/boot/micrometer/metrics/autoconfigure/system/SystemMetricsAutoConfiguration.java b/module/spring-boot-micrometer-metrics/src/main/java/org/springframework/boot/micrometer/metrics/autoconfigure/system/SystemMetricsAutoConfiguration.java index d3077638f53..11679c0223d 100644 --- a/module/spring-boot-micrometer-metrics/src/main/java/org/springframework/boot/micrometer/metrics/autoconfigure/system/SystemMetricsAutoConfiguration.java +++ b/module/spring-boot-micrometer-metrics/src/main/java/org/springframework/boot/micrometer/metrics/autoconfigure/system/SystemMetricsAutoConfiguration.java @@ -44,7 +44,7 @@ import org.springframework.boot.micrometer.metrics.autoconfigure.MetricsAutoConf import org.springframework.boot.micrometer.metrics.autoconfigure.MetricsProperties; import org.springframework.boot.micrometer.metrics.system.DiskSpaceMetricsBinder; import org.springframework.boot.micrometer.observation.autoconfigure.ObservationProperties; -import org.springframework.boot.micrometer.observation.autoconfigure.ObservationProperties.ConventionsVariant; +import org.springframework.boot.micrometer.observation.autoconfigure.condition.SemanticConventions; import org.springframework.context.annotation.Bean; /** @@ -108,7 +108,7 @@ public final class SystemMetricsAutoConfiguration { ProcessorMetrics create(ObservationProperties observationProperties) { ProcessorMetrics.Builder builder = ProcessorMetrics.builder(); - if (observationProperties.getConventions() == ConventionsVariant.OPENTELEMETRY) { + if (observationProperties.getConventions() == SemanticConventions.OPEN_TELEMETRY) { builder.openTelemetryConventions(); } PropertyMapper map = PropertyMapper.get(); diff --git a/module/spring-boot-micrometer-observation/src/main/java/org/springframework/boot/micrometer/observation/autoconfigure/ObservationProperties.java b/module/spring-boot-micrometer-observation/src/main/java/org/springframework/boot/micrometer/observation/autoconfigure/ObservationProperties.java index 167dea29510..df275e42bd1 100644 --- a/module/spring-boot-micrometer-observation/src/main/java/org/springframework/boot/micrometer/observation/autoconfigure/ObservationProperties.java +++ b/module/spring-boot-micrometer-observation/src/main/java/org/springframework/boot/micrometer/observation/autoconfigure/ObservationProperties.java @@ -20,6 +20,7 @@ import java.util.LinkedHashMap; import java.util.Map; import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.boot.micrometer.observation.autoconfigure.condition.SemanticConventions; /** * {@link ConfigurationProperties @ConfigurationProperties} for configuring Micrometer @@ -46,9 +47,9 @@ public class ObservationProperties { private Map enable = new LinkedHashMap<>(); /** - * Conventions variant to use when configuring observations and metrics. + * Semantic conventions to use when configuring observations and metrics. */ - private ConventionsVariant conventions = ConventionsVariant.MICROMETER; + private SemanticConventions conventions = SemanticConventions.MICROMETER; public Map getEnable() { return this.enable; @@ -70,20 +71,14 @@ public class ObservationProperties { this.keyValues = keyValues; } - public ConventionsVariant getConventions() { + public SemanticConventions getConventions() { return this.conventions; } - public void setConventions(ConventionsVariant conventions) { + public void setConventions(SemanticConventions conventions) { this.conventions = conventions; } - public enum ConventionsVariant { - - OPENTELEMETRY, MICROMETER, - - } - public static class Http { private final Client client = new Client(); diff --git a/module/spring-boot-micrometer-observation/src/main/java/org/springframework/boot/micrometer/observation/autoconfigure/condition/ConditionalOnSemanticConventions.java b/module/spring-boot-micrometer-observation/src/main/java/org/springframework/boot/micrometer/observation/autoconfigure/condition/ConditionalOnSemanticConventions.java new file mode 100644 index 00000000000..d83e3a29dea --- /dev/null +++ b/module/spring-boot-micrometer-observation/src/main/java/org/springframework/boot/micrometer/observation/autoconfigure/condition/ConditionalOnSemanticConventions.java @@ -0,0 +1,46 @@ +/* + * Copyright 2012-present the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.boot.micrometer.observation.autoconfigure.condition; + +import java.lang.annotation.Documented; +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +import org.springframework.context.annotation.Conditional; + +/** + * {@link Conditional @Conditional} that matches when the specified semantic conventions + * are enabled. + * + * @author Andy Wilkinson + * @since 4.1.0 + */ +@Target({ ElementType.TYPE, ElementType.METHOD }) +@Retention(RetentionPolicy.RUNTIME) +@Documented +@Conditional(OnSemanticConventionsCondition.class) +public @interface ConditionalOnSemanticConventions { + + /** + * The semantic conventions that must be enabled for the condition to match. + * @return the conventions + */ + SemanticConventions value(); + +} diff --git a/module/spring-boot-micrometer-observation/src/main/java/org/springframework/boot/micrometer/observation/autoconfigure/condition/OnSemanticConventionsCondition.java b/module/spring-boot-micrometer-observation/src/main/java/org/springframework/boot/micrometer/observation/autoconfigure/condition/OnSemanticConventionsCondition.java new file mode 100644 index 00000000000..74fbee6f5cf --- /dev/null +++ b/module/spring-boot-micrometer-observation/src/main/java/org/springframework/boot/micrometer/observation/autoconfigure/condition/OnSemanticConventionsCondition.java @@ -0,0 +1,59 @@ +/* + * Copyright 2012-present the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.boot.micrometer.observation.autoconfigure.condition; + +import java.util.Map; + +import org.jspecify.annotations.Nullable; + +import org.springframework.boot.autoconfigure.condition.ConditionMessage; +import org.springframework.boot.autoconfigure.condition.ConditionOutcome; +import org.springframework.boot.autoconfigure.condition.SpringBootCondition; +import org.springframework.context.annotation.Condition; +import org.springframework.context.annotation.ConditionContext; +import org.springframework.core.env.Environment; +import org.springframework.core.type.AnnotatedTypeMetadata; +import org.springframework.util.Assert; + +/** + * {@link Condition} that checks for particular {@link SemanticConventions}. + * + * @author Andy Wilkinson + * @see ConditionalOnSemanticConventions + */ +class OnSemanticConventionsCondition extends SpringBootCondition { + + @Override + public ConditionOutcome getMatchOutcome(ConditionContext context, AnnotatedTypeMetadata metadata) { + Map attributes = metadata + .getAnnotationAttributes(ConditionalOnSemanticConventions.class.getName()); + Assert.state(attributes != null, "'attributes' must not be null"); + SemanticConventions semanticConvention = (SemanticConventions) attributes.get("value"); + Assert.state(semanticConvention != null, "'semanticConvention' must not be null"); + return getMatchOutcome(context.getEnvironment(), semanticConvention); + } + + private ConditionOutcome getMatchOutcome(Environment environment, SemanticConventions semanticConvention) { + String name = semanticConvention.name(); + ConditionMessage.Builder message = ConditionMessage.forCondition(ConditionalOnSemanticConventions.class); + if (semanticConvention.isActive(environment)) { + return ConditionOutcome.match(message.foundExactly(name)); + } + return ConditionOutcome.noMatch(message.didNotFind(name).atAll()); + } + +} diff --git a/module/spring-boot-micrometer-observation/src/main/java/org/springframework/boot/micrometer/observation/autoconfigure/condition/SemanticConventions.java b/module/spring-boot-micrometer-observation/src/main/java/org/springframework/boot/micrometer/observation/autoconfigure/condition/SemanticConventions.java new file mode 100644 index 00000000000..b95fea6c8d9 --- /dev/null +++ b/module/spring-boot-micrometer-observation/src/main/java/org/springframework/boot/micrometer/observation/autoconfigure/condition/SemanticConventions.java @@ -0,0 +1,70 @@ +/* + * Copyright 2012-present the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.boot.micrometer.observation.autoconfigure.condition; + +import org.springframework.boot.context.properties.bind.BindResult; +import org.springframework.boot.context.properties.bind.Binder; +import org.springframework.core.env.Environment; + +/** + * Enumeration of supported semantic conventions. + * + * @author Andy Wilkinson + * @since 4.2.0 + */ +public enum SemanticConventions { + + /** + * Micrometer semantic conventions. + */ + MICROMETER(true), + + /** + * OpenTelemetry semantic conventions. + */ + OPEN_TELEMETRY; + + private final boolean matchIfMissing; + + SemanticConventions() { + this(false); + } + + SemanticConventions(boolean matchIfMissing) { + this.matchIfMissing = matchIfMissing; + } + + boolean isActive(Environment environment) { + BindResult result = Binder.get(environment, null) + .bind("management.observations.conventions", String.class); + if (!result.isBound()) { + return this.matchIfMissing; + } + return name().equalsIgnoreCase(result.get()) || getCanonicalName().equalsIgnoreCase(result.get()); + } + + private String getCanonicalName() { + String name = name(); + StringBuilder canonicalName = new StringBuilder(name.length()); + name.chars() + .filter(Character::isLetterOrDigit) + .map(Character::toLowerCase) + .forEach((c) -> canonicalName.append((char) c)); + return canonicalName.toString(); + } + +} diff --git a/module/spring-boot-micrometer-observation/src/main/java/org/springframework/boot/micrometer/observation/autoconfigure/condition/package-info.java b/module/spring-boot-micrometer-observation/src/main/java/org/springframework/boot/micrometer/observation/autoconfigure/condition/package-info.java new file mode 100644 index 00000000000..b5d213bd6bd --- /dev/null +++ b/module/spring-boot-micrometer-observation/src/main/java/org/springframework/boot/micrometer/observation/autoconfigure/condition/package-info.java @@ -0,0 +1,23 @@ +/* + * Copyright 2012-present the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * Conditions related to auto-configuration for Micrometer Observation. + */ +@NullMarked +package org.springframework.boot.micrometer.observation.autoconfigure.condition; + +import org.jspecify.annotations.NullMarked; diff --git a/module/spring-boot-micrometer-observation/src/test/java/org/springframework/boot/micrometer/observation/autoconfigure/condition/ConditionalOnSemanticConventionsTests.java b/module/spring-boot-micrometer-observation/src/test/java/org/springframework/boot/micrometer/observation/autoconfigure/condition/ConditionalOnSemanticConventionsTests.java new file mode 100644 index 00000000000..bec9bc69cfe --- /dev/null +++ b/module/spring-boot-micrometer-observation/src/test/java/org/springframework/boot/micrometer/observation/autoconfigure/condition/ConditionalOnSemanticConventionsTests.java @@ -0,0 +1,66 @@ +/* + * Copyright 2012-present the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.boot.micrometer.observation.autoconfigure.condition; + +import org.junit.jupiter.api.Test; + +import org.springframework.boot.test.context.runner.ApplicationContextRunner; +import org.springframework.context.annotation.Configuration; + +import static org.assertj.core.api.Assertions.assertThat; + +/** + * Tests for {@link ConditionalOnSemanticConventions}. + * + * @author Andy Wilkinson + */ +class ConditionalOnSemanticConventionsTests { + + private final ApplicationContextRunner contextRunner = new ApplicationContextRunner() + .withUserConfiguration(Micrometer.class, Otel.class); + + @Test + void whenPropertyIsNotSetOnlyMicrometerIsActive() { + this.contextRunner + .run((context) -> assertThat(context).hasSingleBean(Micrometer.class).doesNotHaveBean(Otel.class)); + } + + @Test + void whenPropertyIsSetToOpenTelemetryOnlyOpenTelementryIsActive() { + this.contextRunner.withPropertyValues("management.observations.conventions=opentelemetry") + .run((context) -> assertThat(context).hasSingleBean(Otel.class).doesNotHaveBean(Micrometer.class)); + } + + @Test + void whenPropertyIsSetToMicrometerOnlyMicrometerIsActive() { + this.contextRunner.withPropertyValues("management.observations.conventions=micrometer") + .run((context) -> assertThat(context).hasSingleBean(Micrometer.class).doesNotHaveBean(Otel.class)); + } + + @Configuration(proxyBeanMethods = false) + @ConditionalOnSemanticConventions(SemanticConventions.MICROMETER) + static class Micrometer { + + } + + @Configuration(proxyBeanMethods = false) + @ConditionalOnSemanticConventions(SemanticConventions.OPEN_TELEMETRY) + static class Otel { + + } + +} diff --git a/module/spring-boot-micrometer-observation/src/test/java/org/springframework/boot/micrometer/observation/autoconfigure/condition/SemanticConventionsTests.java b/module/spring-boot-micrometer-observation/src/test/java/org/springframework/boot/micrometer/observation/autoconfigure/condition/SemanticConventionsTests.java new file mode 100644 index 00000000000..55a7195d7ca --- /dev/null +++ b/module/spring-boot-micrometer-observation/src/test/java/org/springframework/boot/micrometer/observation/autoconfigure/condition/SemanticConventionsTests.java @@ -0,0 +1,57 @@ +/* + * Copyright 2012-present the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.boot.micrometer.observation.autoconfigure.condition; + +import org.junit.jupiter.api.Test; + +import org.springframework.boot.test.util.TestPropertyValues; +import org.springframework.mock.env.MockEnvironment; + +import static org.assertj.core.api.Assertions.assertThat; + +/** + * Tests for {@link SemanticConventions}. + * + * @author Andy Wilkinson + */ +class SemanticConventionsTests { + + @Test + void exactMatch() { + MockEnvironment environment = new MockEnvironment(); + TestPropertyValues.of("management.observations.conventions=MICROMETER").applyTo(environment); + assertThat(SemanticConventions.MICROMETER.isActive(environment)).isTrue(); + assertThat(SemanticConventions.OPEN_TELEMETRY.isActive(environment)).isFalse(); + } + + @Test + void caseInsensitiveMatch() { + MockEnvironment environment = new MockEnvironment(); + TestPropertyValues.of("management.observations.conventions=open_telemetry").applyTo(environment); + assertThat(SemanticConventions.MICROMETER.isActive(environment)).isFalse(); + assertThat(SemanticConventions.OPEN_TELEMETRY.isActive(environment)).isTrue(); + } + + @Test + void ignoresUnderscoreMatch() { + MockEnvironment environment = new MockEnvironment(); + TestPropertyValues.of("management.observations.conventions=opentelemetry").applyTo(environment); + assertThat(SemanticConventions.MICROMETER.isActive(environment)).isFalse(); + assertThat(SemanticConventions.OPEN_TELEMETRY.isActive(environment)).isTrue(); + } + +} diff --git a/module/spring-boot-webflux/src/main/java/org/springframework/boot/webflux/autoconfigure/WebFluxObservationAutoConfiguration.java b/module/spring-boot-webflux/src/main/java/org/springframework/boot/webflux/autoconfigure/WebFluxObservationAutoConfiguration.java index 8fb93657a35..08ea70e0040 100644 --- a/module/spring-boot-webflux/src/main/java/org/springframework/boot/webflux/autoconfigure/WebFluxObservationAutoConfiguration.java +++ b/module/spring-boot-webflux/src/main/java/org/springframework/boot/webflux/autoconfigure/WebFluxObservationAutoConfiguration.java @@ -25,13 +25,14 @@ import org.springframework.boot.autoconfigure.EnableAutoConfiguration; import org.springframework.boot.autoconfigure.condition.ConditionalOnBean; import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; -import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication; import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication.Type; import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.boot.micrometer.metrics.MaximumAllowableTagsMeterFilter; import org.springframework.boot.micrometer.metrics.autoconfigure.MetricsProperties; import org.springframework.boot.micrometer.observation.autoconfigure.ObservationProperties; +import org.springframework.boot.micrometer.observation.autoconfigure.condition.ConditionalOnSemanticConventions; +import org.springframework.boot.micrometer.observation.autoconfigure.condition.SemanticConventions; import org.springframework.context.annotation.Bean; import org.springframework.core.annotation.Order; import org.springframework.http.server.reactive.observation.DefaultServerRequestObservationConvention; @@ -71,20 +72,23 @@ public final class WebFluxObservationAutoConfiguration { return new MaximumAllowableTagsMeterFilter(meterNamePrefix, "uri", maxUriTags); } - @Bean @ConditionalOnMissingBean(ServerRequestObservationConvention.class) - @ConditionalOnProperty(name = "management.observations.conventions", havingValue = "micrometer", - matchIfMissing = true) - DefaultServerRequestObservationConvention micrometerServerRequestObservationConvention() { - return new DefaultServerRequestObservationConvention( - this.observationProperties.getHttp().getServer().getRequests().getName()); - } + static class ServerRequestObservationConventionConfiguration { + + @Bean + @ConditionalOnSemanticConventions(SemanticConventions.MICROMETER) + DefaultServerRequestObservationConvention micrometerServerRequestObservationConvention( + ObservationProperties observationProperties) { + return new DefaultServerRequestObservationConvention( + observationProperties.getHttp().getServer().getRequests().getName()); + } + + @Bean + @ConditionalOnSemanticConventions(SemanticConventions.OPEN_TELEMETRY) + OpenTelemetryServerRequestObservationConvention openTelemetryServerRequestObservationConvention() { + return new OpenTelemetryServerRequestObservationConvention(); + } - @Bean - @ConditionalOnMissingBean(ServerRequestObservationConvention.class) - @ConditionalOnProperty(name = "management.observations.conventions", havingValue = "opentelemetry") - OpenTelemetryServerRequestObservationConvention openTelemetryServerRequestObservationConvention() { - return new OpenTelemetryServerRequestObservationConvention(); } } diff --git a/module/spring-boot-webmvc/src/main/java/org/springframework/boot/webmvc/autoconfigure/WebMvcObservationAutoConfiguration.java b/module/spring-boot-webmvc/src/main/java/org/springframework/boot/webmvc/autoconfigure/WebMvcObservationAutoConfiguration.java index 1e9101896ab..6b665b9da31 100644 --- a/module/spring-boot-webmvc/src/main/java/org/springframework/boot/webmvc/autoconfigure/WebMvcObservationAutoConfiguration.java +++ b/module/spring-boot-webmvc/src/main/java/org/springframework/boot/webmvc/autoconfigure/WebMvcObservationAutoConfiguration.java @@ -27,13 +27,14 @@ import org.springframework.boot.autoconfigure.condition.ConditionalOnBean; import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingFilterBean; -import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication; import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication.Type; import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.boot.micrometer.metrics.MaximumAllowableTagsMeterFilter; import org.springframework.boot.micrometer.metrics.autoconfigure.MetricsProperties; import org.springframework.boot.micrometer.observation.autoconfigure.ObservationProperties; +import org.springframework.boot.micrometer.observation.autoconfigure.condition.ConditionalOnSemanticConventions; +import org.springframework.boot.micrometer.observation.autoconfigure.condition.SemanticConventions; import org.springframework.boot.web.servlet.FilterRegistrationBean; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; @@ -65,23 +66,6 @@ import org.springframework.web.servlet.DispatcherServlet; @EnableConfigurationProperties(ObservationProperties.class) public final class WebMvcObservationAutoConfiguration { - @Bean - @ConditionalOnMissingBean(ServerRequestObservationConvention.class) - @ConditionalOnProperty(name = "management.observations.conventions", havingValue = "micrometer", - matchIfMissing = true) - DefaultServerRequestObservationConvention micrometerServerRequestObservationConvention( - ObservationProperties observationProperties) { - String name = observationProperties.getHttp().getServer().getRequests().getName(); - return new DefaultServerRequestObservationConvention(name); - } - - @Bean - @ConditionalOnMissingBean(ServerRequestObservationConvention.class) - @ConditionalOnProperty(name = "management.observations.conventions", havingValue = "opentelemetry") - OpenTelemetryServerRequestObservationConvention openTelemetryServerRequestObservationConvention() { - return new OpenTelemetryServerRequestObservationConvention(); - } - @Bean @ConditionalOnMissingFilterBean FilterRegistrationBean webMvcObservationFilter(ObservationRegistry registry, @@ -93,6 +77,25 @@ public final class WebMvcObservationAutoConfiguration { return registration; } + @ConditionalOnMissingBean(ServerRequestObservationConvention.class) + static class ServerRequestObservationConventionConfiguration { + + @Bean + @ConditionalOnSemanticConventions(SemanticConventions.MICROMETER) + DefaultServerRequestObservationConvention micrometerServerRequestObservationConvention( + ObservationProperties observationProperties) { + String name = observationProperties.getHttp().getServer().getRequests().getName(); + return new DefaultServerRequestObservationConvention(name); + } + + @Bean + @ConditionalOnSemanticConventions(SemanticConventions.OPEN_TELEMETRY) + OpenTelemetryServerRequestObservationConvention openTelemetryServerRequestObservationConvention() { + return new OpenTelemetryServerRequestObservationConvention(); + } + + } + @Configuration(proxyBeanMethods = false) @ConditionalOnClass({ MeterRegistry.class, MetricsProperties.class }) @ConditionalOnBean(MeterRegistry.class)