Merge pull request #42407 from mturbe
* pr/42407: Polish "Add support for virtual threads in OtlpMetricRegistry configuration" Add support for virtual threads in OtlpMetricRegistry configuration Closes gh-42407
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2012-2023 the original author or authors.
|
||||
* Copyright 2012-2024 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.
|
||||
@@ -30,9 +30,12 @@ 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.ConditionalOnThreading;
|
||||
import org.springframework.boot.autoconfigure.thread.Threading;
|
||||
import org.springframework.boot.context.properties.EnableConfigurationProperties;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.core.env.Environment;
|
||||
import org.springframework.core.task.VirtualThreadTaskExecutor;
|
||||
|
||||
/**
|
||||
* {@link EnableAutoConfiguration Auto-configuration} for exporting metrics to OTLP.
|
||||
@@ -72,10 +75,19 @@ public class OtlpMetricsExportAutoConfiguration {
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean
|
||||
@ConditionalOnThreading(Threading.PLATFORM)
|
||||
public OtlpMeterRegistry otlpMeterRegistry(OtlpConfig otlpConfig, Clock clock) {
|
||||
return new OtlpMeterRegistry(otlpConfig, clock);
|
||||
}
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean
|
||||
@ConditionalOnThreading(Threading.VIRTUAL)
|
||||
public OtlpMeterRegistry otlpMeterRegistryVirtualThreads(OtlpConfig otlpConfig, Clock clock) {
|
||||
VirtualThreadTaskExecutor taskExecutor = new VirtualThreadTaskExecutor("otlp-meter-registry-");
|
||||
return new OtlpMeterRegistry(otlpConfig, clock, taskExecutor.getVirtualThreadFactory());
|
||||
}
|
||||
|
||||
/**
|
||||
* Adapts {@link OtlpProperties} to {@link OtlpMetricsConnectionDetails}.
|
||||
*/
|
||||
|
||||
@@ -16,14 +16,19 @@
|
||||
|
||||
package org.springframework.boot.actuate.autoconfigure.metrics.export.otlp;
|
||||
|
||||
import java.util.concurrent.ScheduledExecutorService;
|
||||
|
||||
import io.micrometer.core.instrument.Clock;
|
||||
import io.micrometer.registry.otlp.OtlpConfig;
|
||||
import io.micrometer.registry.otlp.OtlpMeterRegistry;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.condition.EnabledForJreRange;
|
||||
import org.junit.jupiter.api.condition.JRE;
|
||||
|
||||
import org.springframework.boot.actuate.autoconfigure.metrics.export.otlp.OtlpMetricsExportAutoConfiguration.PropertiesOtlpMetricsConnectionDetails;
|
||||
import org.springframework.boot.autoconfigure.AutoConfigurations;
|
||||
import org.springframework.boot.test.context.runner.ApplicationContextRunner;
|
||||
import org.springframework.boot.testsupport.assertj.ScheduledExecutorServiceAssert;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.annotation.Import;
|
||||
@@ -76,6 +81,32 @@ class OtlpMetricsExportAutoConfigurationTests {
|
||||
.hasBean("customConfig"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void allowsPlatformThreadsToBeUsed() {
|
||||
this.contextRunner.withUserConfiguration(BaseConfiguration.class).run((context) -> {
|
||||
assertThat(context).hasSingleBean(OtlpMeterRegistry.class);
|
||||
OtlpMeterRegistry registry = context.getBean(OtlpMeterRegistry.class);
|
||||
assertThat(registry).extracting("scheduledExecutorService")
|
||||
.satisfies((executor) -> ScheduledExecutorServiceAssert.assertThat((ScheduledExecutorService) executor)
|
||||
.usesPlatformThreads());
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
@EnabledForJreRange(min = JRE.JAVA_21)
|
||||
void allowsVirtualThreadsToBeUsed() {
|
||||
this.contextRunner.withUserConfiguration(BaseConfiguration.class)
|
||||
.withPropertyValues("spring.threads.virtual.enabled=true")
|
||||
.run((context) -> {
|
||||
assertThat(context).hasSingleBean(OtlpMeterRegistry.class);
|
||||
OtlpMeterRegistry registry = context.getBean(OtlpMeterRegistry.class);
|
||||
assertThat(registry).extracting("scheduledExecutorService")
|
||||
.satisfies(
|
||||
(executor) -> ScheduledExecutorServiceAssert.assertThat((ScheduledExecutorService) executor)
|
||||
.usesVirtualThreads());
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
void allowsRegistryToBeCustomized() {
|
||||
this.contextRunner.withUserConfiguration(CustomRegistryConfiguration.class)
|
||||
|
||||
@@ -0,0 +1,93 @@
|
||||
/*
|
||||
* Copyright 2012-2024 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.testsupport.assertj;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.concurrent.ScheduledExecutorService;
|
||||
import java.util.concurrent.ScheduledThreadPoolExecutor;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import org.assertj.core.api.AbstractAssert;
|
||||
import org.assertj.core.api.Assert;
|
||||
|
||||
import org.springframework.util.ReflectionUtils;
|
||||
|
||||
/**
|
||||
* AssertJ {@link Assert} for {@link ScheduledThreadPoolExecutor}.
|
||||
*
|
||||
* @author Mike Turbe
|
||||
* @author Moritz Halbritter
|
||||
*/
|
||||
public final class ScheduledExecutorServiceAssert
|
||||
extends AbstractAssert<ScheduledExecutorServiceAssert, ScheduledExecutorService> {
|
||||
|
||||
private ScheduledExecutorServiceAssert(ScheduledExecutorService actual) {
|
||||
super(actual, ScheduledExecutorServiceAssert.class);
|
||||
}
|
||||
|
||||
/**
|
||||
* Verifies that the actual executor uses platform threads.
|
||||
* @return {@code this} assertion object
|
||||
* @throws AssertionError if the actual executor doesn't use platform threads
|
||||
*/
|
||||
public ScheduledExecutorServiceAssert usesPlatformThreads() {
|
||||
isNotNull();
|
||||
if (producesVirtualThreads()) {
|
||||
failWithMessage("Expected executor to use platform threads, but it uses virtual threads");
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Verifies that the actual executor uses virtual threads.
|
||||
* @return {@code this} assertion object
|
||||
* @throws AssertionError if the actual executor doesn't use virtual threads
|
||||
*/
|
||||
public ScheduledExecutorServiceAssert usesVirtualThreads() {
|
||||
isNotNull();
|
||||
if (!producesVirtualThreads()) {
|
||||
failWithMessage("Expected executor to use virtual threads, but it uses platform threads");
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
private boolean producesVirtualThreads() {
|
||||
try {
|
||||
return this.actual.schedule(() -> {
|
||||
Method isVirtual = ReflectionUtils.findMethod(Thread.class, "isVirtual");
|
||||
if (isVirtual == null) {
|
||||
return false;
|
||||
}
|
||||
return (boolean) ReflectionUtils.invokeMethod(isVirtual, Thread.currentThread());
|
||||
}, 0, TimeUnit.SECONDS).get();
|
||||
}
|
||||
catch (InterruptedException | ExecutionException ex) {
|
||||
throw new AssertionError(ex);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new assertion class with the given {@link ScheduledExecutorService}.
|
||||
* @param actual the {@link ScheduledExecutorService}
|
||||
* @return the assertion class
|
||||
*/
|
||||
public static ScheduledExecutorServiceAssert assertThat(ScheduledExecutorService actual) {
|
||||
return new ScheduledExecutorServiceAssert(actual);
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user