Browse Source

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
pull/42457/head
Moritz Halbritter 1 year ago
parent
commit
8da3dd7104
  1. 14
      spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/metrics/export/otlp/OtlpMetricsExportAutoConfiguration.java
  2. 31
      spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/metrics/export/otlp/OtlpMetricsExportAutoConfigurationTests.java
  3. 93
      spring-boot-project/spring-boot-tools/spring-boot-test-support/src/main/java/org/springframework/boot/testsupport/assertj/ScheduledExecutorServiceAssert.java

14
spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/metrics/export/otlp/OtlpMetricsExportAutoConfiguration.java

@ -1,5 +1,5 @@ @@ -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; @@ -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 { @@ -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}.
*/

31
spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/metrics/export/otlp/OtlpMetricsExportAutoConfigurationTests.java

@ -16,14 +16,19 @@ @@ -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 { @@ -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)

93
spring-boot-project/spring-boot-tools/spring-boot-test-support/src/main/java/org/springframework/boot/testsupport/assertj/ScheduledExecutorServiceAssert.java

@ -0,0 +1,93 @@ @@ -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);
}
}
Loading…
Cancel
Save