Associate MeterConventions for JVM and system metrics

This commit auto-configures the following beans with their corresponding
conventions, when available:

- ProcessorMetrics with JvmCpuMeterConventions
- JvmMemoryMetrics with JvmMemoryMeterConventions
- JvmThreadMetrics with JvmThreadMeterConventions
- ClassLoaderMetrics with JvmClassLoadingMeterConventions

See gh-47935

Signed-off-by: Dmytro Nosan <dimanosan@gmail.com>
This commit is contained in:
Dmytro Nosan
2025-12-19 11:48:25 +01:00
committed by Stéphane Nicoll
parent cf3c2a086d
commit 8abff71009
4 changed files with 68 additions and 8 deletions
@@ -16,6 +16,8 @@
package org.springframework.boot.micrometer.metrics.autoconfigure.jvm;
import java.util.Collections;
import io.micrometer.core.instrument.MeterRegistry;
import io.micrometer.core.instrument.binder.MeterBinder;
import io.micrometer.core.instrument.binder.jvm.ClassLoaderMetrics;
@@ -25,12 +27,16 @@ 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.JvmClassLoadingMeterConventions;
import io.micrometer.core.instrument.binder.jvm.convention.JvmMemoryMeterConventions;
import io.micrometer.core.instrument.binder.jvm.convention.JvmThreadMeterConventions;
import org.jspecify.annotations.Nullable;
import org.springframework.aot.hint.MemberCategory;
import org.springframework.aot.hint.RuntimeHints;
import org.springframework.aot.hint.RuntimeHintsRegistrar;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.ObjectProvider;
import org.springframework.boot.autoconfigure.AutoConfiguration;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
@@ -71,20 +77,26 @@ public final class JvmMetricsAutoConfiguration {
@Bean
@ConditionalOnMissingBean
JvmMemoryMetrics jvmMemoryMetrics() {
return new JvmMemoryMetrics();
JvmMemoryMetrics jvmMemoryMetrics(ObjectProvider<JvmMemoryMeterConventions> jvmMemoryMeterConventions) {
JvmMemoryMeterConventions conventions = jvmMemoryMeterConventions.getIfAvailable();
return (conventions != null) ? new JvmMemoryMetrics(Collections.emptyList(), conventions)
: new JvmMemoryMetrics();
}
@Bean
@ConditionalOnMissingBean
JvmThreadMetrics jvmThreadMetrics() {
return new JvmThreadMetrics();
JvmThreadMetrics jvmThreadMetrics(ObjectProvider<JvmThreadMeterConventions> jvmThreadMeterConventions) {
JvmThreadMeterConventions conventions = jvmThreadMeterConventions.getIfAvailable();
return (conventions != null) ? new JvmThreadMetrics(Collections.emptyList(), conventions)
: new JvmThreadMetrics();
}
@Bean
@ConditionalOnMissingBean
ClassLoaderMetrics classLoaderMetrics() {
return new ClassLoaderMetrics();
ClassLoaderMetrics classLoaderMetrics(
ObjectProvider<JvmClassLoadingMeterConventions> jvmClassLoadingMeterConventions) {
JvmClassLoadingMeterConventions conventions = jvmClassLoadingMeterConventions.getIfAvailable();
return (conventions != null) ? new ClassLoaderMetrics(conventions) : new ClassLoaderMetrics();
}
@Bean
@@ -17,14 +17,17 @@
package org.springframework.boot.micrometer.metrics.autoconfigure.system;
import java.io.File;
import java.util.Collections;
import java.util.List;
import io.micrometer.core.instrument.MeterRegistry;
import io.micrometer.core.instrument.Tags;
import io.micrometer.core.instrument.binder.jvm.convention.JvmCpuMeterConventions;
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.springframework.beans.factory.ObjectProvider;
import org.springframework.boot.autoconfigure.AutoConfiguration;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
@@ -58,8 +61,10 @@ public final class SystemMetricsAutoConfiguration {
@Bean
@ConditionalOnMissingBean
ProcessorMetrics processorMetrics() {
return new ProcessorMetrics();
ProcessorMetrics processorMetrics(ObjectProvider<JvmCpuMeterConventions> jvmCpuMeterConventions) {
JvmCpuMeterConventions conventions = jvmCpuMeterConventions.getIfAvailable();
return (conventions != null) ? new ProcessorMetrics(Collections.emptyList(), conventions)
: new ProcessorMetrics();
}
@Bean
@@ -25,10 +25,14 @@ 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.JvmClassLoadingMeterConventions;
import io.micrometer.core.instrument.binder.jvm.convention.JvmMemoryMeterConventions;
import io.micrometer.core.instrument.binder.jvm.convention.JvmThreadMeterConventions;
import io.micrometer.core.instrument.simple.SimpleMeterRegistry;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.condition.EnabledForJreRange;
import org.junit.jupiter.api.condition.JRE;
import org.mockito.Mockito;
import org.springframework.aot.hint.MemberCategory;
import org.springframework.aot.hint.RuntimeHints;
@@ -82,18 +86,46 @@ class JvmMetricsAutoConfigurationTests {
.run(assertMetricsBeans().andThen((context) -> assertThat(context).hasBean("customJvmMemoryMetrics")));
}
@Test
void allowCustomJvmMemoryMeterConventionsToBeUsed() {
JvmMemoryMeterConventions jvmMemoryMeterConventions = Mockito.mock(JvmMemoryMeterConventions.class);
this.contextRunner.withBean(JvmMemoryMeterConventions.class, () -> jvmMemoryMeterConventions)
.run((context) -> assertThat(context).hasSingleBean(JvmMemoryMetrics.class)
.getBean(JvmMemoryMetrics.class)
.hasFieldOrPropertyWithValue("conventions", jvmMemoryMeterConventions));
}
@Test
void allowsCustomJvmThreadMetricsToBeUsed() {
this.contextRunner.withUserConfiguration(CustomJvmThreadMetricsConfiguration.class)
.run(assertMetricsBeans().andThen((context) -> assertThat(context).hasBean("customJvmThreadMetrics")));
}
@Test
void allowCustomJvmThreadMeterConventionsToBeUsed() {
JvmThreadMeterConventions jvmThreadMeterConventions = Mockito.mock(JvmThreadMeterConventions.class);
this.contextRunner.withBean(JvmThreadMeterConventions.class, () -> jvmThreadMeterConventions)
.run((context) -> assertThat(context).hasSingleBean(JvmThreadMetrics.class)
.getBean(JvmThreadMetrics.class)
.hasFieldOrPropertyWithValue("conventions", jvmThreadMeterConventions));
}
@Test
void allowsCustomClassLoaderMetricsToBeUsed() {
this.contextRunner.withUserConfiguration(CustomClassLoaderMetricsConfiguration.class)
.run(assertMetricsBeans().andThen((context) -> assertThat(context).hasBean("customClassLoaderMetrics")));
}
@Test
void allowCustomJvmClassLoadingMeterConventionsToBeUsed() {
JvmClassLoadingMeterConventions jvmClassLoadingMeterConventions = Mockito
.mock(JvmClassLoadingMeterConventions.class);
this.contextRunner.withBean(JvmClassLoadingMeterConventions.class, () -> jvmClassLoadingMeterConventions)
.run((context) -> assertThat(context).hasSingleBean(ClassLoaderMetrics.class)
.getBean(ClassLoaderMetrics.class)
.hasFieldOrPropertyWithValue("conventions", jvmClassLoadingMeterConventions));
}
@Test
void allowsCustomJvmInfoMetricsToBeUsed() {
this.contextRunner.withUserConfiguration(CustomJvmInfoMetricsConfiguration.class)
@@ -21,11 +21,13 @@ import java.util.Arrays;
import java.util.Collections;
import io.micrometer.core.instrument.Tags;
import io.micrometer.core.instrument.binder.jvm.convention.JvmCpuMeterConventions;
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 io.micrometer.core.instrument.simple.SimpleMeterRegistry;
import org.junit.jupiter.api.Test;
import org.mockito.Mockito;
import org.springframework.boot.autoconfigure.AutoConfigurations;
import org.springframework.boot.micrometer.metrics.system.DiskSpaceMetricsBinder;
@@ -71,6 +73,15 @@ class SystemMetricsAutoConfigurationTests {
.hasBean("customProcessorMetrics"));
}
@Test
void allowsCustomJvmCpuMeterConventionsToBeUsed() {
JvmCpuMeterConventions jvmCpuMeterConventions = Mockito.mock(JvmCpuMeterConventions.class);
this.contextRunner.withBean(JvmCpuMeterConventions.class, () -> jvmCpuMeterConventions)
.run((context) -> assertThat(context).hasSingleBean(ProcessorMetrics.class)
.getBean(ProcessorMetrics.class)
.hasFieldOrPropertyWithValue("conventions", jvmCpuMeterConventions));
}
@Test
void autoConfiguresFileDescriptorMetrics() {
this.contextRunner.run((context) -> assertThat(context).hasSingleBean(FileDescriptorMetrics.class));