Merge pull request #43852 from nosan
* pr/43852: Auto-configure VirtualThreadMetrics Closes gh-43852
This commit is contained in:
commit
ec94e07dc9
|
|
@ -29,6 +29,7 @@ dependencies {
|
|||
optional("io.lettuce:lettuce-core")
|
||||
optional("io.micrometer:micrometer-observation")
|
||||
optional("io.micrometer:micrometer-jakarta9")
|
||||
optional("io.micrometer:micrometer-java21")
|
||||
optional("io.micrometer:micrometer-tracing")
|
||||
optional("io.micrometer:micrometer-tracing-bridge-brave")
|
||||
optional("io.micrometer:micrometer-tracing-bridge-otel")
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2012-2022 the original author or authors.
|
||||
* Copyright 2012-2025 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.
|
||||
|
|
@ -16,6 +16,8 @@
|
|||
|
||||
package org.springframework.boot.actuate.autoconfigure.metrics;
|
||||
|
||||
import java.io.Closeable;
|
||||
|
||||
import io.micrometer.core.instrument.MeterRegistry;
|
||||
import io.micrometer.core.instrument.binder.jvm.ClassLoaderMetrics;
|
||||
import io.micrometer.core.instrument.binder.jvm.JvmCompilationMetrics;
|
||||
|
|
@ -25,12 +27,21 @@ 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 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.BeanClassLoaderAware;
|
||||
import org.springframework.beans.factory.DisposableBean;
|
||||
import org.springframework.beans.factory.FactoryBean;
|
||||
import org.springframework.boot.autoconfigure.AutoConfiguration;
|
||||
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.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.ImportRuntimeHints;
|
||||
import org.springframework.util.ClassUtils;
|
||||
|
||||
/**
|
||||
* {@link EnableAutoConfiguration Auto-configuration} for JVM metrics.
|
||||
|
|
@ -44,6 +55,8 @@ import org.springframework.context.annotation.Bean;
|
|||
@ConditionalOnBean(MeterRegistry.class)
|
||||
public class JvmMetricsAutoConfiguration {
|
||||
|
||||
private static final String VIRTUAL_THREAD_METRICS_CLASS = "io.micrometer.java21.instrument.binder.jdk.VirtualThreadMetrics";
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean
|
||||
public JvmGcMetrics jvmGcMetrics() {
|
||||
|
|
@ -86,4 +99,62 @@ public class JvmMetricsAutoConfiguration {
|
|||
return new JvmCompilationMetrics();
|
||||
}
|
||||
|
||||
@Bean
|
||||
@ConditionalOnClass(name = VIRTUAL_THREAD_METRICS_CLASS)
|
||||
@ConditionalOnMissingBean(type = VIRTUAL_THREAD_METRICS_CLASS)
|
||||
@ImportRuntimeHints(VirtualThreadMetricsRuntimeHintsRegistrar.class)
|
||||
VirtualThreadMetricsFactoryBean virtualThreadMetrics() {
|
||||
return new VirtualThreadMetricsFactoryBean();
|
||||
}
|
||||
|
||||
static final class VirtualThreadMetricsFactoryBean
|
||||
implements FactoryBean<Object>, BeanClassLoaderAware, DisposableBean {
|
||||
|
||||
private ClassLoader classLoader;
|
||||
|
||||
private Class<?> instanceType;
|
||||
|
||||
private Object instance;
|
||||
|
||||
@Override
|
||||
public void setBeanClassLoader(ClassLoader classLoader) {
|
||||
this.classLoader = classLoader;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getObject() {
|
||||
if (this.instance == null) {
|
||||
this.instance = BeanUtils.instantiateClass(getObjectType());
|
||||
}
|
||||
return this.instance;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<?> getObjectType() {
|
||||
if (this.instanceType == null) {
|
||||
this.instanceType = ClassUtils.resolveClassName(VIRTUAL_THREAD_METRICS_CLASS, this.classLoader);
|
||||
}
|
||||
return this.instanceType;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void destroy() throws Exception {
|
||||
if (this.instance instanceof Closeable closeable) {
|
||||
closeable.close();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static final class VirtualThreadMetricsRuntimeHintsRegistrar implements RuntimeHintsRegistrar {
|
||||
|
||||
@Override
|
||||
public void registerHints(RuntimeHints hints, ClassLoader classLoader) {
|
||||
hints.reflection()
|
||||
.registerTypeIfPresent(classLoader, VIRTUAL_THREAD_METRICS_CLASS,
|
||||
MemberCategory.INVOKE_PUBLIC_CONSTRUCTORS);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2012-2023 the original author or authors.
|
||||
* Copyright 2012-2025 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.
|
||||
|
|
@ -16,6 +16,7 @@
|
|||
|
||||
package org.springframework.boot.actuate.autoconfigure.metrics;
|
||||
|
||||
import io.micrometer.core.instrument.binder.MeterBinder;
|
||||
import io.micrometer.core.instrument.binder.jvm.ClassLoaderMetrics;
|
||||
import io.micrometer.core.instrument.binder.jvm.JvmCompilationMetrics;
|
||||
import io.micrometer.core.instrument.binder.jvm.JvmGcMetrics;
|
||||
|
|
@ -24,7 +25,14 @@ 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 org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.condition.EnabledForJreRange;
|
||||
import org.junit.jupiter.api.condition.JRE;
|
||||
|
||||
import org.springframework.aot.hint.MemberCategory;
|
||||
import org.springframework.aot.hint.RuntimeHints;
|
||||
import org.springframework.aot.hint.TypeReference;
|
||||
import org.springframework.aot.hint.predicate.RuntimeHintsPredicates;
|
||||
import org.springframework.beans.BeanUtils;
|
||||
import org.springframework.boot.actuate.autoconfigure.metrics.test.MetricsRun;
|
||||
import org.springframework.boot.autoconfigure.AutoConfigurations;
|
||||
import org.springframework.boot.test.context.assertj.AssertableApplicationContext;
|
||||
|
|
@ -32,6 +40,7 @@ import org.springframework.boot.test.context.runner.ApplicationContextRunner;
|
|||
import org.springframework.boot.test.context.runner.ContextConsumer;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.util.ClassUtils;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
|
|
@ -95,6 +104,36 @@ class JvmMetricsAutoConfigurationTests {
|
|||
.run(assertMetricsBeans().andThen((context) -> assertThat(context).hasBean("customJvmCompilationMetrics")));
|
||||
}
|
||||
|
||||
@Test
|
||||
@EnabledForJreRange(min = JRE.JAVA_21)
|
||||
void autoConfiguresJvmMetricsWithVirtualThreadsMetrics() {
|
||||
this.contextRunner.run(assertMetricsBeans()
|
||||
.andThen((context) -> assertThat(context).hasSingleBean(getVirtualThreadMetricsClass())));
|
||||
}
|
||||
|
||||
@Test
|
||||
@EnabledForJreRange(min = JRE.JAVA_21)
|
||||
void allowCustomVirtualThreadMetricsToBeUsed() {
|
||||
Class<MeterBinder> virtualThreadMetricsClass = getVirtualThreadMetricsClass();
|
||||
this.contextRunner
|
||||
.withBean("customVirtualThreadMetrics", virtualThreadMetricsClass,
|
||||
() -> BeanUtils.instantiateClass(virtualThreadMetricsClass))
|
||||
.run(assertMetricsBeans()
|
||||
.andThen((context) -> assertThat(context).hasSingleBean(getVirtualThreadMetricsClass())
|
||||
.hasBean("customVirtualThreadMetrics")));
|
||||
}
|
||||
|
||||
@Test
|
||||
@EnabledForJreRange(min = JRE.JAVA_21)
|
||||
void shouldRegisterVirtualThreadMetricsRuntimeHints() {
|
||||
RuntimeHints hints = new RuntimeHints();
|
||||
new JvmMetricsAutoConfiguration.VirtualThreadMetricsRuntimeHintsRegistrar().registerHints(hints,
|
||||
getClass().getClassLoader());
|
||||
assertThat(RuntimeHintsPredicates.reflection()
|
||||
.onType(TypeReference.of(getVirtualThreadMetricsClass()))
|
||||
.withMemberCategories(MemberCategory.INVOKE_PUBLIC_CONSTRUCTORS)).accepts(hints);
|
||||
}
|
||||
|
||||
private ContextConsumer<AssertableApplicationContext> assertMetricsBeans() {
|
||||
return (context) -> assertThat(context).hasSingleBean(JvmGcMetrics.class)
|
||||
.hasSingleBean(JvmHeapPressureMetrics.class)
|
||||
|
|
@ -105,6 +144,12 @@ class JvmMetricsAutoConfigurationTests {
|
|||
.hasSingleBean(JvmCompilationMetrics.class);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private static Class<MeterBinder> getVirtualThreadMetricsClass() {
|
||||
return (Class<MeterBinder>) ClassUtils
|
||||
.resolveClassName("io.micrometer.java21.instrument.binder.jdk.VirtualThreadMetrics", null);
|
||||
}
|
||||
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
static class CustomJvmGcMetricsConfiguration {
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue