diff --git a/module/spring-boot-jersey/src/test/java/org/springframework/boot/jersey/autoconfigure/metrics/JerseyServerMetricsAutoConfigurationTests.java b/module/spring-boot-jersey/src/test/java/org/springframework/boot/jersey/autoconfigure/metrics/JerseyServerMetricsAutoConfigurationTests.java index e632b6978ee..735c70477f8 100644 --- a/module/spring-boot-jersey/src/test/java/org/springframework/boot/jersey/autoconfigure/metrics/JerseyServerMetricsAutoConfigurationTests.java +++ b/module/spring-boot-jersey/src/test/java/org/springframework/boot/jersey/autoconfigure/metrics/JerseyServerMetricsAutoConfigurationTests.java @@ -142,7 +142,7 @@ class JerseyServerMetricsAutoConfigurationTests { @Bean MeterObservationHandler meterObservationHandler(MeterRegistry registry) { - return new DefaultMeterObservationHandler(registry); + return DefaultMeterObservationHandler.builder(registry).build(); } } diff --git a/module/spring-boot-micrometer-metrics/src/main/java/org/springframework/boot/micrometer/metrics/autoconfigure/MetricsAutoConfiguration.java b/module/spring-boot-micrometer-metrics/src/main/java/org/springframework/boot/micrometer/metrics/autoconfigure/MetricsAutoConfiguration.java index 9f8ee142a05..0c6c546e91a 100644 --- a/module/spring-boot-micrometer-metrics/src/main/java/org/springframework/boot/micrometer/metrics/autoconfigure/MetricsAutoConfiguration.java +++ b/module/spring-boot-micrometer-metrics/src/main/java/org/springframework/boot/micrometer/metrics/autoconfigure/MetricsAutoConfiguration.java @@ -23,7 +23,6 @@ import io.micrometer.core.instrument.binder.MeterBinder; import io.micrometer.core.instrument.composite.CompositeMeterRegistry; import io.micrometer.core.instrument.config.MeterFilter; import io.micrometer.core.instrument.observation.DefaultMeterObservationHandler; -import io.micrometer.core.instrument.observation.DefaultMeterObservationHandler.IgnoredMeters; import io.micrometer.core.instrument.observation.MeterObservationHandler; import org.springframework.beans.factory.ObjectProvider; @@ -88,8 +87,9 @@ public final class MetricsAutoConfiguration { DefaultMeterObservationHandler defaultMeterObservationHandler(ObjectProvider meterRegistryProvider, Clock clock, MetricsProperties properties) { MeterRegistry meterRegistry = meterRegistryProvider.getIfAvailable(() -> new CompositeMeterRegistry(clock)); - return new DefaultMeterObservationHandler(meterRegistry, - properties.getObservations().getIgnoredMeters().toArray(IgnoredMeters[]::new)); + return DefaultMeterObservationHandler.builder(meterRegistry) + .includeActiveObservationLongTaskTimer(properties.getObservations().isIncludeActiveLongTaskTimer()) + .build(); } } diff --git a/module/spring-boot-micrometer-metrics/src/main/java/org/springframework/boot/micrometer/metrics/autoconfigure/MetricsProperties.java b/module/spring-boot-micrometer-metrics/src/main/java/org/springframework/boot/micrometer/metrics/autoconfigure/MetricsProperties.java index e5b4017723f..5fab2af98b7 100644 --- a/module/spring-boot-micrometer-metrics/src/main/java/org/springframework/boot/micrometer/metrics/autoconfigure/MetricsProperties.java +++ b/module/spring-boot-micrometer-metrics/src/main/java/org/springframework/boot/micrometer/metrics/autoconfigure/MetricsProperties.java @@ -21,12 +21,8 @@ import java.time.Duration; import java.util.ArrayList; import java.util.Collections; import java.util.LinkedHashMap; -import java.util.LinkedHashSet; import java.util.List; import java.util.Map; -import java.util.Set; - -import io.micrometer.core.instrument.observation.DefaultMeterObservationHandler.IgnoredMeters; import org.springframework.boot.context.properties.ConfigurationProperties; @@ -273,16 +269,16 @@ public class MetricsProperties { public static class Observations { /** - * Meters that should be ignored when recoding observations. + * Whether to create the active observation LongTaskTimer. */ - private Set ignoredMeters = new LinkedHashSet<>(); + private boolean includeActiveLongTaskTimer; - public Set getIgnoredMeters() { - return this.ignoredMeters; + public boolean isIncludeActiveLongTaskTimer() { + return this.includeActiveLongTaskTimer; } - public void setIgnoredMeters(Set ignoredMeters) { - this.ignoredMeters = ignoredMeters; + public void setIncludeActiveLongTaskTimer(boolean includeActiveLongTaskTimer) { + this.includeActiveLongTaskTimer = includeActiveLongTaskTimer; } } 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 10e4e8b6ce1..35f5a69c023 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 @@ -27,8 +27,15 @@ import io.micrometer.core.instrument.binder.jvm.JvmHeapPressureMetrics; import io.micrometer.core.instrument.binder.jvm.JvmInfoMetrics; import io.micrometer.core.instrument.binder.jvm.JvmMemoryMetrics; import io.micrometer.core.instrument.binder.jvm.JvmThreadMetrics; +import io.micrometer.core.instrument.binder.jvm.convention.JvmClassCountMeterConvention; +import io.micrometer.core.instrument.binder.jvm.convention.JvmClassLoadedMeterConvention; import io.micrometer.core.instrument.binder.jvm.convention.JvmClassLoadingMeterConventions; +import io.micrometer.core.instrument.binder.jvm.convention.JvmClassUnloadedMeterConvention; +import io.micrometer.core.instrument.binder.jvm.convention.JvmMemoryCommittedMeterConvention; +import io.micrometer.core.instrument.binder.jvm.convention.JvmMemoryMaxMeterConvention; import io.micrometer.core.instrument.binder.jvm.convention.JvmMemoryMeterConventions; +import io.micrometer.core.instrument.binder.jvm.convention.JvmMemoryUsedMeterConvention; +import io.micrometer.core.instrument.binder.jvm.convention.JvmThreadCountMeterConvention; import io.micrometer.core.instrument.binder.jvm.convention.JvmThreadMeterConventions; import org.jspecify.annotations.Nullable; @@ -42,6 +49,7 @@ 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.context.properties.PropertyMapper; import org.springframework.boot.micrometer.metrics.autoconfigure.CompositeMeterRegistryAutoConfiguration; import org.springframework.boot.micrometer.metrics.autoconfigure.MetricsAutoConfiguration; import org.springframework.context.annotation.Bean; @@ -77,26 +85,58 @@ public final class JvmMetricsAutoConfiguration { @Bean @ConditionalOnMissingBean - JvmMemoryMetrics jvmMemoryMetrics(ObjectProvider jvmMemoryMeterConventions) { - JvmMemoryMeterConventions conventions = jvmMemoryMeterConventions.getIfAvailable(); - return (conventions != null) ? new JvmMemoryMetrics(Collections.emptyList(), conventions) - : new JvmMemoryMetrics(); + @SuppressWarnings("deprecation") + JvmMemoryMetrics jvmMemoryMetrics(ObjectProvider jvmMemoryMeterConventions, + ObjectProvider jvmMemoryUsedMeterConvention, + ObjectProvider jvmMemoryCommittedMeterConvention, + ObjectProvider jvmMemoryMaxMeterConvention) { + JvmMemoryMetricsFactory factory = new JvmMemoryMetricsFactory(jvmMemoryUsedMeterConvention.getIfAvailable(), + jvmMemoryCommittedMeterConvention.getIfAvailable(), jvmMemoryMaxMeterConvention.getIfAvailable()); + JvmMemoryMeterConventions deprecatedConventions = jvmMemoryMeterConventions.getIfAvailable(); + if (deprecatedConventions != null && factory.hasConvention()) { + throw new IllegalStateException("Either %s or the interfaces that supersede it should be set" + .formatted(JvmMemoryMeterConventions.class.getSimpleName())); + } + return (deprecatedConventions != null) ? new JvmMemoryMetrics(Collections.emptyList(), deprecatedConventions) + : factory.create(); + } @Bean @ConditionalOnMissingBean - JvmThreadMetrics jvmThreadMetrics(ObjectProvider jvmThreadMeterConventions) { - JvmThreadMeterConventions conventions = jvmThreadMeterConventions.getIfAvailable(); - return (conventions != null) ? new JvmThreadMetrics(Collections.emptyList(), conventions) + @SuppressWarnings("deprecation") + JvmThreadMetrics jvmThreadMetrics(ObjectProvider jvmThreadMeterConventions, + ObjectProvider jvmThreadCountMeterConvention) { + JvmThreadMeterConventions deprecatedConventions = jvmThreadMeterConventions.getIfAvailable(); + JvmThreadCountMeterConvention convention = jvmThreadCountMeterConvention.getIfAvailable(); + if (deprecatedConventions != null && convention != null) { + throw new IllegalStateException( + "Either %s or %s should be set".formatted(JvmMemoryMeterConventions.class.getSimpleName(), + JvmThreadCountMeterConvention.class.getSimpleName())); + } + if (deprecatedConventions != null) { + return new JvmThreadMetrics(Collections.emptyList(), deprecatedConventions); + } + return (convention != null) ? JvmThreadMetrics.builder().threadCountConvention(convention).build() : new JvmThreadMetrics(); } @Bean @ConditionalOnMissingBean + @SuppressWarnings("deprecation") ClassLoaderMetrics classLoaderMetrics( - ObjectProvider jvmClassLoadingMeterConventions) { - JvmClassLoadingMeterConventions conventions = jvmClassLoadingMeterConventions.getIfAvailable(); - return (conventions != null) ? new ClassLoaderMetrics(conventions) : new ClassLoaderMetrics(); + ObjectProvider jvmClassLoadingMeterConventions, + ObjectProvider jvmClassCountMeterConvention, + ObjectProvider jvmClassLoadedMeterConvention, + ObjectProvider jvmClassUnloadedMeterConvention) { + ClassLoaderMetricsFactory factory = new ClassLoaderMetricsFactory(jvmClassCountMeterConvention.getIfAvailable(), + jvmClassLoadedMeterConvention.getIfAvailable(), jvmClassUnloadedMeterConvention.getIfAvailable()); + JvmClassLoadingMeterConventions deprecatedConventions = jvmClassLoadingMeterConventions.getIfAvailable(); + if (deprecatedConventions != null && factory.hasConvention()) { + throw new IllegalStateException("Either %s or the interfaces that supersede it should be set" + .formatted(JvmClassLoadingMeterConventions.class.getSimpleName())); + } + return (deprecatedConventions != null) ? new ClassLoaderMetrics(deprecatedConventions) : factory.create(); } @Bean @@ -126,6 +166,46 @@ public final class JvmMetricsAutoConfiguration { } + private record JvmMemoryMetricsFactory(@Nullable JvmMemoryUsedMeterConvention memoryUsedConvention, + @Nullable JvmMemoryCommittedMeterConvention memoryCommittedConvention, + @Nullable JvmMemoryMaxMeterConvention memoryMaxConvention) { + + boolean hasConvention() { + return this.memoryUsedConvention != null || this.memoryCommittedConvention != null + || this.memoryMaxConvention != null; + } + + JvmMemoryMetrics create() { + JvmMemoryMetrics.Builder builder = JvmMemoryMetrics.builder(); + PropertyMapper map = PropertyMapper.get(); + map.from(this.memoryUsedConvention).to(builder::memoryUsedConvention); + map.from(this.memoryCommittedConvention).to(builder::memoryCommittedConvention); + map.from(this.memoryMaxConvention).to(builder::memoryMaxConvention); + return builder.build(); + } + + } + + private record ClassLoaderMetricsFactory(@Nullable JvmClassCountMeterConvention classCountConvention, + @Nullable JvmClassLoadedMeterConvention classLoadedConvention, + @Nullable JvmClassUnloadedMeterConvention classUnloadedConvention) { + + boolean hasConvention() { + return this.classCountConvention != null || this.classLoadedConvention != null + || this.classUnloadedConvention != null; + } + + ClassLoaderMetrics create() { + ClassLoaderMetrics.Builder builder = ClassLoaderMetrics.builder(); + PropertyMapper map = PropertyMapper.get(); + map.from(this.classCountConvention).to(builder::classCountConvention); + map.from(this.classLoadedConvention).to(builder::classLoadedConvention); + map.from(this.classUnloadedConvention).to(builder::classUnloadedConvention); + return builder.build(); + } + + } + static final class VirtualThreadMetricsRuntimeHintsRegistrar implements RuntimeHintsRegistrar { @Override 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 ef3e1dab5ca..e61cb4156dc 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 @@ -22,10 +22,14 @@ import java.util.List; import io.micrometer.core.instrument.MeterRegistry; import io.micrometer.core.instrument.Tags; +import io.micrometer.core.instrument.binder.jvm.convention.JvmCpuCountMeterConvention; +import io.micrometer.core.instrument.binder.jvm.convention.JvmCpuLoadMeterConvention; import io.micrometer.core.instrument.binder.jvm.convention.JvmCpuMeterConventions; +import io.micrometer.core.instrument.binder.jvm.convention.JvmCpuTimeMeterConvention; import io.micrometer.core.instrument.binder.system.FileDescriptorMetrics; import io.micrometer.core.instrument.binder.system.ProcessorMetrics; import io.micrometer.core.instrument.binder.system.UptimeMetrics; +import org.jspecify.annotations.Nullable; import org.springframework.beans.factory.ObjectProvider; import org.springframework.boot.autoconfigure.AutoConfiguration; @@ -34,6 +38,7 @@ 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.context.properties.EnableConfigurationProperties; +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.metrics.autoconfigure.MetricsProperties; @@ -61,10 +66,20 @@ public final class SystemMetricsAutoConfiguration { @Bean @ConditionalOnMissingBean - ProcessorMetrics processorMetrics(ObjectProvider jvmCpuMeterConventions) { - JvmCpuMeterConventions conventions = jvmCpuMeterConventions.getIfAvailable(); - return (conventions != null) ? new ProcessorMetrics(Collections.emptyList(), conventions) - : new ProcessorMetrics(); + @SuppressWarnings("deprecation") + ProcessorMetrics processorMetrics(ObjectProvider jvmCpuMeterConventions, + ObjectProvider jvmCpuTimeMeterConvention, + ObjectProvider jvmCpuCountMeterConvention, + ObjectProvider jvmCpuLoadMeterConvention) { + JvmCpuMeterConventions deprecatedConventions = jvmCpuMeterConventions.getIfAvailable(); + ProcessorMetricsFactory factory = new ProcessorMetricsFactory(jvmCpuTimeMeterConvention.getIfAvailable(), + jvmCpuCountMeterConvention.getIfAvailable(), jvmCpuLoadMeterConvention.getIfAvailable()); + if (deprecatedConventions != null && factory.hasConvention()) { + throw new IllegalStateException("Either %s or the interfaces that supersede it should be set" + .formatted(JvmCpuMeterConventions.class.getSimpleName())); + } + return (deprecatedConventions != null) ? new ProcessorMetrics(Collections.emptyList(), deprecatedConventions) + : factory.create(); } @Bean @@ -80,4 +95,23 @@ public final class SystemMetricsAutoConfiguration { return new DiskSpaceMetricsBinder(paths, Tags.empty()); } + private record ProcessorMetricsFactory(@Nullable JvmCpuTimeMeterConvention cpuTimeConvention, + @Nullable JvmCpuCountMeterConvention cpuCountConvention, + @Nullable JvmCpuLoadMeterConvention cpuLoadConvention) { + + boolean hasConvention() { + return this.cpuTimeConvention != null || this.cpuCountConvention != null || this.cpuLoadConvention != null; + } + + ProcessorMetrics create() { + PropertyMapper map = PropertyMapper.get(); + ProcessorMetrics.Builder builder = ProcessorMetrics.builder(); + map.from(this.cpuTimeConvention).to(builder::cpuTimeConvention); + map.from(this.cpuCountConvention).to(builder::cpuCountConvention); + map.from(this.cpuLoadConvention).to(builder::cpuLoadConvention); + return builder.build(); + } + + } + } diff --git a/module/spring-boot-micrometer-metrics/src/main/resources/META-INF/additional-spring-configuration-metadata.json b/module/spring-boot-micrometer-metrics/src/main/resources/META-INF/additional-spring-configuration-metadata.json index f5f16db1f0d..5a2df5475b4 100644 --- a/module/spring-boot-micrometer-metrics/src/main/resources/META-INF/additional-spring-configuration-metadata.json +++ b/module/spring-boot-micrometer-metrics/src/main/resources/META-INF/additional-spring-configuration-metadata.json @@ -1702,6 +1702,14 @@ "since": "3.0.0" } }, + { + "name": "management.metrics.observations.ignored-meters", + "deprecation": { + "level": "error", + "replacement": "management.metrics.observations.include-active-long-task-timer", + "since": "4.2.0" + } + }, { "name": "management.metrics.system.diskspace.paths", "type": "java.util.List", diff --git a/module/spring-boot-micrometer-metrics/src/test/java/org/springframework/boot/micrometer/metrics/autoconfigure/MetricsAutoConfigurationTests.java b/module/spring-boot-micrometer-metrics/src/test/java/org/springframework/boot/micrometer/metrics/autoconfigure/MetricsAutoConfigurationTests.java index 03d42a8657f..0fbfbeacbc6 100644 --- a/module/spring-boot-micrometer-metrics/src/test/java/org/springframework/boot/micrometer/metrics/autoconfigure/MetricsAutoConfigurationTests.java +++ b/module/spring-boot-micrometer-metrics/src/test/java/org/springframework/boot/micrometer/metrics/autoconfigure/MetricsAutoConfigurationTests.java @@ -153,19 +153,19 @@ class MetricsAutoConfigurationTests { } @Test - void shouldEnableLongTaskTimerByDefault() { + void shouldDisableLongTaskTimerByDefault() { this.contextRunner.run((context) -> { DefaultMeterObservationHandler handler = context.getBean(DefaultMeterObservationHandler.class); - assertThat(handler).hasFieldOrPropertyWithValue("shouldCreateLongTaskTimer", true); + assertThat(handler).hasFieldOrPropertyWithValue("includeActiveObservationLongTaskTimer", false); }); } @Test - void shouldDisableLongTaskTimerIfPropertyIsSet() { - this.contextRunner.withPropertyValues("management.metrics.observations.ignored-meters=long-task-timer") + void shouldEnableLongTaskTimerIfPropertyIsSet() { + this.contextRunner.withPropertyValues("management.metrics.observations.include-active-long-task-timer=true") .run((context) -> { DefaultMeterObservationHandler handler = context.getBean(DefaultMeterObservationHandler.class); - assertThat(handler).hasFieldOrPropertyWithValue("shouldCreateLongTaskTimer", false); + assertThat(handler).hasFieldOrPropertyWithValue("includeActiveObservationLongTaskTimer", true); }); } diff --git a/module/spring-boot-micrometer-metrics/src/test/java/org/springframework/boot/micrometer/metrics/autoconfigure/jvm/JvmMetricsAutoConfigurationTests.java b/module/spring-boot-micrometer-metrics/src/test/java/org/springframework/boot/micrometer/metrics/autoconfigure/jvm/JvmMetricsAutoConfigurationTests.java index ebd88951ef9..252b946a5c7 100644 --- a/module/spring-boot-micrometer-metrics/src/test/java/org/springframework/boot/micrometer/metrics/autoconfigure/jvm/JvmMetricsAutoConfigurationTests.java +++ b/module/spring-boot-micrometer-metrics/src/test/java/org/springframework/boot/micrometer/metrics/autoconfigure/jvm/JvmMetricsAutoConfigurationTests.java @@ -17,6 +17,7 @@ package org.springframework.boot.micrometer.metrics.autoconfigure.jvm; import io.micrometer.core.instrument.MeterRegistry; +import io.micrometer.core.instrument.Tags; import io.micrometer.core.instrument.binder.MeterBinder; import io.micrometer.core.instrument.binder.jvm.ClassLoaderMetrics; import io.micrometer.core.instrument.binder.jvm.JvmCompilationMetrics; @@ -25,9 +26,19 @@ import io.micrometer.core.instrument.binder.jvm.JvmHeapPressureMetrics; import io.micrometer.core.instrument.binder.jvm.JvmInfoMetrics; import io.micrometer.core.instrument.binder.jvm.JvmMemoryMetrics; import io.micrometer.core.instrument.binder.jvm.JvmThreadMetrics; +import io.micrometer.core.instrument.binder.jvm.convention.JvmClassCountMeterConvention; +import io.micrometer.core.instrument.binder.jvm.convention.JvmClassLoadedMeterConvention; import io.micrometer.core.instrument.binder.jvm.convention.JvmClassLoadingMeterConventions; +import io.micrometer.core.instrument.binder.jvm.convention.JvmClassUnloadedMeterConvention; +import io.micrometer.core.instrument.binder.jvm.convention.JvmMemoryCommittedMeterConvention; +import io.micrometer.core.instrument.binder.jvm.convention.JvmMemoryMaxMeterConvention; import io.micrometer.core.instrument.binder.jvm.convention.JvmMemoryMeterConventions; +import io.micrometer.core.instrument.binder.jvm.convention.JvmMemoryUsedMeterConvention; +import io.micrometer.core.instrument.binder.jvm.convention.JvmThreadCountMeterConvention; import io.micrometer.core.instrument.binder.jvm.convention.JvmThreadMeterConventions; +import io.micrometer.core.instrument.binder.jvm.convention.micrometer.MicrometerJvmClassLoadingMeterConventions; +import io.micrometer.core.instrument.binder.jvm.convention.micrometer.MicrometerJvmMemoryMeterConventions; +import io.micrometer.core.instrument.binder.jvm.convention.micrometer.MicrometerJvmThreadMeterConventions; import io.micrometer.core.instrument.simple.SimpleMeterRegistry; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.condition.EnabledForJreRange; @@ -47,7 +58,9 @@ import org.springframework.context.annotation.Configuration; import org.springframework.util.ClassUtils; import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.BDDMockito.then; import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.spy; /** * Tests for {@link JvmMetricsAutoConfiguration}. @@ -59,7 +72,7 @@ import static org.mockito.Mockito.mock; class JvmMetricsAutoConfigurationTests { private final ApplicationContextRunner contextRunner = new ApplicationContextRunner() - .withBean(MeterRegistry.class, () -> new SimpleMeterRegistry()) + .withBean(MeterRegistry.class, SimpleMeterRegistry::new) .withConfiguration(AutoConfigurations.of(JvmMetricsAutoConfiguration.class)); @Test @@ -87,12 +100,75 @@ class JvmMetricsAutoConfigurationTests { } @Test + @Deprecated(since = "4.2.0", forRemoval = true) void allowCustomJvmMemoryMeterConventionsToBeUsed() { - JvmMemoryMeterConventions jvmMemoryMeterConventions = mock(JvmMemoryMeterConventions.class); - this.contextRunner.withBean(JvmMemoryMeterConventions.class, () -> jvmMemoryMeterConventions) + JvmMemoryMeterConventions conventions = spy(new MicrometerJvmMemoryMeterConventions()); + this.contextRunner.withBean(JvmMemoryMeterConventions.class, () -> conventions).run((context) -> { + assertThat(context).hasSingleBean(JvmMemoryMetrics.class); + then(conventions).should().getMemoryUsedConvention(); + then(conventions).should().getMemoryCommittedConvention(); + then(conventions).should().getMemoryMaxConvention(); + }); + } + + @Test + @Deprecated(since = "4.2.0", forRemoval = true) + void shouldFailIfBothJvmMemoryMeterConventionsAndJvmMemoryUsedMeterConventionAreSet() { + this.contextRunner.withBean(JvmMemoryMeterConventions.class, () -> mock(JvmMemoryMeterConventions.class)) + .withBean(JvmMemoryUsedMeterConvention.class, () -> mock(JvmMemoryUsedMeterConvention.class)) + .run((context) -> assertThat(context).hasFailed() + .getFailure() + .hasMessageContaining( + "Either JvmMemoryMeterConventions or the interfaces that supersede it should be set")); + } + + @Test + @Deprecated(since = "4.2.0", forRemoval = true) + void shouldFailIfBothJvmMemoryMeterConventionsAndJvmMemoryCommittedMeterConventionAreSet() { + this.contextRunner.withBean(JvmMemoryMeterConventions.class, () -> mock(JvmMemoryMeterConventions.class)) + .withBean(JvmMemoryCommittedMeterConvention.class, () -> mock(JvmMemoryCommittedMeterConvention.class)) + .run((context) -> assertThat(context).hasFailed() + .getFailure() + .hasMessageContaining( + "Either JvmMemoryMeterConventions or the interfaces that supersede it should be set")); + } + + @Test + @Deprecated(since = "4.2.0", forRemoval = true) + void shouldFailIfBothJvmMemoryMeterConventionsAndJvmMemoryMaxMeterConventionAreSet() { + this.contextRunner.withBean(JvmMemoryMeterConventions.class, () -> mock(JvmMemoryMeterConventions.class)) + .withBean(JvmMemoryMaxMeterConvention.class, () -> mock(JvmMemoryMaxMeterConvention.class)) + .run((context) -> assertThat(context).hasFailed() + .getFailure() + .hasMessageContaining( + "Either JvmMemoryMeterConventions or the interfaces that supersede it should be set")); + } + + @Test + void allowCustomJvmMemoryUsedMeterConventionToBeUsed() { + JvmMemoryUsedMeterConvention memoryUsedConvention = mock(JvmMemoryUsedMeterConvention.class); + this.contextRunner.withBean(JvmMemoryUsedMeterConvention.class, () -> memoryUsedConvention) .run((context) -> assertThat(context).hasSingleBean(JvmMemoryMetrics.class) .getBean(JvmMemoryMetrics.class) - .hasFieldOrPropertyWithValue("conventions", jvmMemoryMeterConventions)); + .hasFieldOrPropertyWithValue("memoryUsedConvention", memoryUsedConvention)); + } + + @Test + void allowCustomJvmMemoryCommittedMeterConventionToBeUsed() { + JvmMemoryCommittedMeterConvention memoryCommittedConvention = mock(JvmMemoryCommittedMeterConvention.class); + this.contextRunner.withBean(JvmMemoryCommittedMeterConvention.class, () -> memoryCommittedConvention) + .run((context) -> assertThat(context).hasSingleBean(JvmMemoryMetrics.class) + .getBean(JvmMemoryMetrics.class) + .hasFieldOrPropertyWithValue("memoryCommittedConvention", memoryCommittedConvention)); + } + + @Test + void allowCustomJvmMemoryMaxMeterConventionToBeUsed() { + JvmMemoryMaxMeterConvention memoryMaxConvention = mock(JvmMemoryMaxMeterConvention.class); + this.contextRunner.withBean(JvmMemoryMaxMeterConvention.class, () -> memoryMaxConvention) + .run((context) -> assertThat(context).hasSingleBean(JvmMemoryMetrics.class) + .getBean(JvmMemoryMetrics.class) + .hasFieldOrPropertyWithValue("memoryMaxConvention", memoryMaxConvention)); } @Test @@ -102,12 +178,33 @@ class JvmMetricsAutoConfigurationTests { } @Test + @Deprecated(since = "4.2.0", forRemoval = true) void allowCustomJvmThreadMeterConventionsToBeUsed() { - JvmThreadMeterConventions jvmThreadMeterConventions = mock(JvmThreadMeterConventions.class); - this.contextRunner.withBean(JvmThreadMeterConventions.class, () -> jvmThreadMeterConventions) + JvmThreadMeterConventions conventions = spy(new MicrometerJvmThreadMeterConventions(Tags.empty())); + this.contextRunner.withBean(JvmThreadMeterConventions.class, () -> conventions).run((context) -> { + assertThat(context).hasSingleBean(JvmThreadMetrics.class); + then(conventions).should().threadCountConvention(); + }); + } + + @Test + @Deprecated(since = "4.2.0", forRemoval = true) + void shouldFailIfBothJvmThreadMeterConventionsAndJvmThreadCountMeterConventionAreSet() { + this.contextRunner.withBean(JvmThreadMeterConventions.class, () -> mock(JvmThreadMeterConventions.class)) + .withBean(JvmThreadCountMeterConvention.class, () -> mock(JvmThreadCountMeterConvention.class)) + .run((context) -> assertThat(context).hasFailed() + .getFailure() + .hasMessageContaining( + "Either JvmMemoryMeterConventions or JvmThreadCountMeterConvention should be set")); + } + + @Test + void allowCustomJJvmThreadCountMeterConventionToBeUsed() { + JvmThreadCountMeterConvention threadCountConvention = mock(JvmThreadCountMeterConvention.class); + this.contextRunner.withBean(JvmThreadCountMeterConvention.class, () -> threadCountConvention) .run((context) -> assertThat(context).hasSingleBean(JvmThreadMetrics.class) .getBean(JvmThreadMetrics.class) - .hasFieldOrPropertyWithValue("conventions", jvmThreadMeterConventions)); + .hasFieldOrPropertyWithValue("threadCountConvention", threadCountConvention)); } @Test @@ -117,12 +214,78 @@ class JvmMetricsAutoConfigurationTests { } @Test + @Deprecated(since = "4.2.0", forRemoval = true) void allowCustomJvmClassLoadingMeterConventionsToBeUsed() { - JvmClassLoadingMeterConventions jvmClassLoadingMeterConventions = mock(JvmClassLoadingMeterConventions.class); - this.contextRunner.withBean(JvmClassLoadingMeterConventions.class, () -> jvmClassLoadingMeterConventions) + JvmClassLoadingMeterConventions conventions = spy(new MicrometerJvmClassLoadingMeterConventions()); + this.contextRunner.withBean(JvmClassLoadingMeterConventions.class, () -> conventions).run((context) -> { + assertThat(context).hasSingleBean(ClassLoaderMetrics.class); + then(conventions).should().currentClassCountConvention(); + then(conventions).should().loadedConvention(); + then(conventions).should().unloadedConvention(); + }); + } + + @Test + @Deprecated(since = "4.2.0", forRemoval = true) + void shouldFailIfBothJvmClassLoadingMeterConventionsAndJvmClassCountMeterConventionAreSet() { + this.contextRunner + .withBean(JvmClassLoadingMeterConventions.class, () -> mock(JvmClassLoadingMeterConventions.class)) + .withBean(JvmClassCountMeterConvention.class, () -> mock(JvmClassCountMeterConvention.class)) + .run((context) -> assertThat(context).hasFailed() + .getFailure() + .hasMessageContaining( + "Either JvmClassLoadingMeterConventions or the interfaces that supersede it should be set")); + } + + @Test + @Deprecated(since = "4.2.0", forRemoval = true) + void shouldFailIfBothJvmClassLoadingMeterConventionsAndJvmClassLoadedMeterConventionAreSet() { + this.contextRunner + .withBean(JvmClassLoadingMeterConventions.class, () -> mock(JvmClassLoadingMeterConventions.class)) + .withBean(JvmClassLoadedMeterConvention.class, () -> mock(JvmClassLoadedMeterConvention.class)) + .run((context) -> assertThat(context).hasFailed() + .getFailure() + .hasMessageContaining( + "Either JvmClassLoadingMeterConventions or the interfaces that supersede it should be set")); + } + + @Test + @Deprecated(since = "4.2.0", forRemoval = true) + void shouldFailIfBothJvmClassLoadingMeterConventionsAndJvmClassUnloadedMeterConventionAreSet() { + this.contextRunner + .withBean(JvmClassLoadingMeterConventions.class, () -> mock(JvmClassLoadingMeterConventions.class)) + .withBean(JvmClassUnloadedMeterConvention.class, () -> mock(JvmClassUnloadedMeterConvention.class)) + .run((context) -> assertThat(context).hasFailed() + .getFailure() + .hasMessageContaining( + "Either JvmClassLoadingMeterConventions or the interfaces that supersede it should be set")); + } + + @Test + void allowCustomJvmClassCountMeterConventionToBeUsed() { + JvmClassCountMeterConvention classCountConvention = mock(JvmClassCountMeterConvention.class); + this.contextRunner.withBean(JvmClassCountMeterConvention.class, () -> classCountConvention) .run((context) -> assertThat(context).hasSingleBean(ClassLoaderMetrics.class) .getBean(ClassLoaderMetrics.class) - .hasFieldOrPropertyWithValue("conventions", jvmClassLoadingMeterConventions)); + .hasFieldOrPropertyWithValue("classCountConvention", classCountConvention)); + } + + @Test + void allowCustomJvmClassLoadedMeterConventionToBeUsed() { + JvmClassLoadedMeterConvention classLoadedConvention = mock(JvmClassLoadedMeterConvention.class); + this.contextRunner.withBean(JvmClassLoadedMeterConvention.class, () -> classLoadedConvention) + .run((context) -> assertThat(context).hasSingleBean(ClassLoaderMetrics.class) + .getBean(ClassLoaderMetrics.class) + .hasFieldOrPropertyWithValue("classLoadedConvention", classLoadedConvention)); + } + + @Test + void allowCustomJvmClassUnloadedMeterConventionToBeUsed() { + JvmClassUnloadedMeterConvention classUnloadedConvention = mock(JvmClassUnloadedMeterConvention.class); + this.contextRunner.withBean(JvmClassUnloadedMeterConvention.class, () -> classUnloadedConvention) + .run((context) -> assertThat(context).hasSingleBean(ClassLoaderMetrics.class) + .getBean(ClassLoaderMetrics.class) + .hasFieldOrPropertyWithValue("classUnloadedConvention", classUnloadedConvention)); } @Test diff --git a/module/spring-boot-micrometer-metrics/src/test/java/org/springframework/boot/micrometer/metrics/autoconfigure/system/SystemMetricsAutoConfigurationTests.java b/module/spring-boot-micrometer-metrics/src/test/java/org/springframework/boot/micrometer/metrics/autoconfigure/system/SystemMetricsAutoConfigurationTests.java index 58c876518bf..5ed14518d88 100644 --- a/module/spring-boot-micrometer-metrics/src/test/java/org/springframework/boot/micrometer/metrics/autoconfigure/system/SystemMetricsAutoConfigurationTests.java +++ b/module/spring-boot-micrometer-metrics/src/test/java/org/springframework/boot/micrometer/metrics/autoconfigure/system/SystemMetricsAutoConfigurationTests.java @@ -21,7 +21,11 @@ import java.util.Arrays; import java.util.Collections; import io.micrometer.core.instrument.Tags; +import io.micrometer.core.instrument.binder.jvm.convention.JvmCpuCountMeterConvention; +import io.micrometer.core.instrument.binder.jvm.convention.JvmCpuLoadMeterConvention; import io.micrometer.core.instrument.binder.jvm.convention.JvmCpuMeterConventions; +import io.micrometer.core.instrument.binder.jvm.convention.JvmCpuTimeMeterConvention; +import io.micrometer.core.instrument.binder.jvm.convention.micrometer.MicrometerJvmCpuMeterConventions; import io.micrometer.core.instrument.binder.system.FileDescriptorMetrics; import io.micrometer.core.instrument.binder.system.ProcessorMetrics; import io.micrometer.core.instrument.binder.system.UptimeMetrics; @@ -35,7 +39,10 @@ import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.BDDMockito.then; +import static org.mockito.Mockito.atLeast; import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.spy; /** * Tests for {@link SystemMetricsAutoConfiguration}. @@ -74,12 +81,75 @@ class SystemMetricsAutoConfigurationTests { } @Test + @Deprecated(since = "4.2.0", forRemoval = true) void allowsCustomJvmCpuMeterConventionsToBeUsed() { - JvmCpuMeterConventions jvmCpuMeterConventions = mock(JvmCpuMeterConventions.class); - this.contextRunner.withBean(JvmCpuMeterConventions.class, () -> jvmCpuMeterConventions) + JvmCpuMeterConventions conventions = spy(new MicrometerJvmCpuMeterConventions(Tags.empty())); + this.contextRunner.withBean(JvmCpuMeterConventions.class, () -> conventions).run((context) -> { + assertThat(context).hasSingleBean(ProcessorMetrics.class); + then(conventions).should(atLeast(1)).cpuTimeConvention(); + then(conventions).should(atLeast(1)).cpuCountConvention(); + then(conventions).should(atLeast(1)).processCpuLoadConvention(); + }); + } + + @Test + @Deprecated(since = "4.2.0", forRemoval = true) + void shouldFailIfBothJvmCpuMeterConventionsAndJvmCpuTimeMeterConventionAreSet() { + this.contextRunner.withBean(JvmCpuMeterConventions.class, () -> mock(JvmCpuMeterConventions.class)) + .withBean(JvmCpuTimeMeterConvention.class, () -> mock(JvmCpuTimeMeterConvention.class)) + .run((context) -> assertThat(context).hasFailed() + .getFailure() + .hasMessageContaining( + "Either JvmCpuMeterConventions or the interfaces that supersede it should be set")); + } + + @Test + @Deprecated(since = "4.2.0", forRemoval = true) + void shouldFailIfBothJvmCpuMeterConventionsAndJvmCpuCountMeterConventionAreSet() { + this.contextRunner.withBean(JvmCpuMeterConventions.class, () -> mock(JvmCpuMeterConventions.class)) + .withBean(JvmCpuCountMeterConvention.class, () -> mock(JvmCpuCountMeterConvention.class)) + .run((context) -> assertThat(context).hasFailed() + .getFailure() + .hasMessageContaining( + "Either JvmCpuMeterConventions or the interfaces that supersede it should be set")); + } + + @Test + @Deprecated(since = "4.2.0", forRemoval = true) + void shouldFailIfBothJvmCpuMeterConventionsAndJvmCpuLoadMeterConventionAreSet() { + this.contextRunner.withBean(JvmCpuMeterConventions.class, () -> mock(JvmCpuMeterConventions.class)) + .withBean(JvmCpuLoadMeterConvention.class, () -> mock(JvmCpuLoadMeterConvention.class)) + .run((context) -> assertThat(context).hasFailed() + .getFailure() + .hasMessageContaining( + "Either JvmCpuMeterConventions or the interfaces that supersede it should be set")); + } + + @Test + void allowsCustomJvmCpuTimeMeterConventionToBeUsed() { + JvmCpuTimeMeterConvention cpuTimeConvention = mock(JvmCpuTimeMeterConvention.class); + this.contextRunner.withBean(JvmCpuTimeMeterConvention.class, () -> cpuTimeConvention) .run((context) -> assertThat(context).hasSingleBean(ProcessorMetrics.class) .getBean(ProcessorMetrics.class) - .hasFieldOrPropertyWithValue("conventions", jvmCpuMeterConventions)); + .hasFieldOrPropertyWithValue("cpuTimeConvention", cpuTimeConvention)); + } + + @Test + void allowsCustomJvmCpuCountMeterConventionToBeUsed() { + JvmCpuCountMeterConvention cpuCountConvention = mock(JvmCpuCountMeterConvention.class); + this.contextRunner.withBean(JvmCpuCountMeterConvention.class, () -> cpuCountConvention) + .run((context) -> assertThat(context).hasSingleBean(ProcessorMetrics.class) + .getBean(ProcessorMetrics.class) + .hasFieldOrPropertyWithValue("cpuCountConvention", cpuCountConvention)); + } + + @Test + void allowsCustomJvmCpuLoadMeterConventionToBeUsed() { + JvmCpuLoadMeterConvention cpuLoadConvention = mock(JvmCpuLoadMeterConvention.class); + this.contextRunner.withBean(JvmCpuLoadMeterConvention.class, () -> cpuLoadConvention) + .run((context) -> assertThat(context).hasSingleBean(ProcessorMetrics.class) + .getBean(ProcessorMetrics.class) + .hasFieldOrPropertyWithValue("cpuLoadConvention", cpuLoadConvention)); } @Test diff --git a/module/spring-boot-micrometer-tracing-brave/src/test/java/org/springframework/boot/micrometer/tracing/brave/autoconfigure/OtlpExemplarsAutoConfigurationTests.java b/module/spring-boot-micrometer-tracing-brave/src/test/java/org/springframework/boot/micrometer/tracing/brave/autoconfigure/OtlpExemplarsAutoConfigurationTests.java index 705d028527a..d30e0059b11 100644 --- a/module/spring-boot-micrometer-tracing-brave/src/test/java/org/springframework/boot/micrometer/tracing/brave/autoconfigure/OtlpExemplarsAutoConfigurationTests.java +++ b/module/spring-boot-micrometer-tracing-brave/src/test/java/org/springframework/boot/micrometer/tracing/brave/autoconfigure/OtlpExemplarsAutoConfigurationTests.java @@ -149,7 +149,7 @@ class OtlpExemplarsAutoConfigurationTests { @Bean TracingAwareMeterObservationHandler tracingAwareMeterObservationHandler(MeterRegistry meterRegistry, Tracer tracer) { - DefaultMeterObservationHandler delegate = new DefaultMeterObservationHandler(meterRegistry); + DefaultMeterObservationHandler delegate = DefaultMeterObservationHandler.builder(meterRegistry).build(); return new TracingAwareMeterObservationHandler<>(delegate, tracer); } diff --git a/module/spring-boot-micrometer-tracing-brave/src/test/java/org/springframework/boot/micrometer/tracing/brave/autoconfigure/PrometheusExemplarsAutoConfigurationTests.java b/module/spring-boot-micrometer-tracing-brave/src/test/java/org/springframework/boot/micrometer/tracing/brave/autoconfigure/PrometheusExemplarsAutoConfigurationTests.java index 6d16bcfe1df..a16d4eecaa2 100644 --- a/module/spring-boot-micrometer-tracing-brave/src/test/java/org/springframework/boot/micrometer/tracing/brave/autoconfigure/PrometheusExemplarsAutoConfigurationTests.java +++ b/module/spring-boot-micrometer-tracing-brave/src/test/java/org/springframework/boot/micrometer/tracing/brave/autoconfigure/PrometheusExemplarsAutoConfigurationTests.java @@ -189,7 +189,7 @@ class PrometheusExemplarsAutoConfigurationTests { @Bean TracingAwareMeterObservationHandler tracingAwareMeterObservationHandler( MeterRegistry meterRegistry, Tracer tracer) { - DefaultMeterObservationHandler delegate = new DefaultMeterObservationHandler(meterRegistry); + DefaultMeterObservationHandler delegate = DefaultMeterObservationHandler.builder(meterRegistry).build(); return new TracingAwareMeterObservationHandler<>(delegate, tracer); } diff --git a/module/spring-boot-restclient/src/test/java/org/springframework/boot/restclient/autoconfigure/RestClientObservationAutoConfigurationTests.java b/module/spring-boot-restclient/src/test/java/org/springframework/boot/restclient/autoconfigure/RestClientObservationAutoConfigurationTests.java index 100b5e5c4a1..4d19323f293 100644 --- a/module/spring-boot-restclient/src/test/java/org/springframework/boot/restclient/autoconfigure/RestClientObservationAutoConfigurationTests.java +++ b/module/spring-boot-restclient/src/test/java/org/springframework/boot/restclient/autoconfigure/RestClientObservationAutoConfigurationTests.java @@ -148,7 +148,7 @@ class RestClientObservationAutoConfigurationTests { @Bean MeterObservationHandler meterObservationHandler(MeterRegistry registry) { - return new DefaultMeterObservationHandler(registry); + return DefaultMeterObservationHandler.builder(registry).build(); } } diff --git a/module/spring-boot-webclient/src/test/java/org/springframework/boot/webclient/autoconfigure/WebClientObservationAutoConfigurationTests.java b/module/spring-boot-webclient/src/test/java/org/springframework/boot/webclient/autoconfigure/WebClientObservationAutoConfigurationTests.java index 179060e37ec..f09e4e77dbc 100644 --- a/module/spring-boot-webclient/src/test/java/org/springframework/boot/webclient/autoconfigure/WebClientObservationAutoConfigurationTests.java +++ b/module/spring-boot-webclient/src/test/java/org/springframework/boot/webclient/autoconfigure/WebClientObservationAutoConfigurationTests.java @@ -137,7 +137,7 @@ class WebClientObservationAutoConfigurationTests { @Bean MeterObservationHandler meterObservationHandler(MeterRegistry registry) { - return new DefaultMeterObservationHandler(registry); + return DefaultMeterObservationHandler.builder(registry).build(); } } diff --git a/module/spring-boot-webmvc/src/test/java/org/springframework/boot/webmvc/autoconfigure/WebMvcObservationAutoConfigurationTests.java b/module/spring-boot-webmvc/src/test/java/org/springframework/boot/webmvc/autoconfigure/WebMvcObservationAutoConfigurationTests.java index 2648e2f7449..0a9989e960a 100644 --- a/module/spring-boot-webmvc/src/test/java/org/springframework/boot/webmvc/autoconfigure/WebMvcObservationAutoConfigurationTests.java +++ b/module/spring-boot-webmvc/src/test/java/org/springframework/boot/webmvc/autoconfigure/WebMvcObservationAutoConfigurationTests.java @@ -20,7 +20,6 @@ import java.util.EnumSet; import io.micrometer.core.instrument.MeterRegistry; import io.micrometer.core.instrument.observation.DefaultMeterObservationHandler; -import io.micrometer.core.instrument.observation.DefaultMeterObservationHandler.IgnoredMeters; import io.micrometer.core.instrument.observation.MeterObservationHandler; import io.micrometer.core.instrument.simple.SimpleMeterRegistry; import io.micrometer.observation.Observation.Context; @@ -263,7 +262,7 @@ class WebMvcObservationAutoConfigurationTests { @Bean MeterObservationHandler meterObservationHandler(MeterRegistry registry) { - return new DefaultMeterObservationHandler(registry, IgnoredMeters.LONG_TASK_TIMER); + return DefaultMeterObservationHandler.builder(registry).build(); } } diff --git a/platform/spring-boot-dependencies/build.gradle b/platform/spring-boot-dependencies/build.gradle index 483e1f0a939..7c21409f1df 100644 --- a/platform/spring-boot-dependencies/build.gradle +++ b/platform/spring-boot-dependencies/build.gradle @@ -1675,7 +1675,7 @@ bom { releaseNotes("https://github.com/apache/maven-war-plugin/releases/tag/maven-war-plugin-{version}") } } - library("Micrometer", "1.18.0-M1") { + library("Micrometer", "1.18.0-SNAPSHOT") { firstParty() group("io.micrometer") { modules = [