Add metrics for task execution and scheduling
Closes gh-23818
This commit is contained in:
		
							parent
							
								
									fbbfe6ac86
								
							
						
					
					
						commit
						f8555b9071
					
				| 
						 | 
					@ -0,0 +1,127 @@
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * Copyright 2012-2021 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.actuate.autoconfigure.metrics.task;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import java.util.Map;
 | 
				
			||||||
 | 
					import java.util.concurrent.Executor;
 | 
				
			||||||
 | 
					import java.util.concurrent.ThreadPoolExecutor;
 | 
				
			||||||
 | 
					import java.util.function.Supplier;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import io.micrometer.core.instrument.MeterRegistry;
 | 
				
			||||||
 | 
					import io.micrometer.core.instrument.binder.jvm.ExecutorServiceMetrics;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import org.springframework.beans.factory.annotation.Autowired;
 | 
				
			||||||
 | 
					import org.springframework.boot.actuate.autoconfigure.metrics.MetricsAutoConfiguration;
 | 
				
			||||||
 | 
					import org.springframework.boot.actuate.autoconfigure.metrics.export.simple.SimpleMetricsExportAutoConfiguration;
 | 
				
			||||||
 | 
					import org.springframework.boot.autoconfigure.AutoConfigureAfter;
 | 
				
			||||||
 | 
					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.task.TaskExecutionAutoConfiguration;
 | 
				
			||||||
 | 
					import org.springframework.boot.autoconfigure.task.TaskSchedulingAutoConfiguration;
 | 
				
			||||||
 | 
					import org.springframework.context.annotation.Configuration;
 | 
				
			||||||
 | 
					import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
 | 
				
			||||||
 | 
					import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler;
 | 
				
			||||||
 | 
					import org.springframework.util.StringUtils;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * {@link EnableAutoConfiguration Auto-configuration} for metrics on all available
 | 
				
			||||||
 | 
					 * {@link ThreadPoolTaskExecutor task executors} and {@link ThreadPoolTaskScheduler task
 | 
				
			||||||
 | 
					 * schedulers}.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * @author Stephane Nicoll
 | 
				
			||||||
 | 
					 * @since 2.6.0
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					@Configuration(proxyBeanMethods = false)
 | 
				
			||||||
 | 
					@AutoConfigureAfter({ MetricsAutoConfiguration.class, SimpleMetricsExportAutoConfiguration.class,
 | 
				
			||||||
 | 
							TaskExecutionAutoConfiguration.class, TaskSchedulingAutoConfiguration.class })
 | 
				
			||||||
 | 
					@ConditionalOnClass(ExecutorServiceMetrics.class)
 | 
				
			||||||
 | 
					@ConditionalOnBean({ Executor.class, MeterRegistry.class })
 | 
				
			||||||
 | 
					public class TaskExecutorMetricsAutoConfiguration {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						private static final String TASK_EXECUTOR_SUFFIX = "taskExecutor";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						private static final String TASK_SCHEDULER_SUFFIX = "taskScheduler";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						@Autowired
 | 
				
			||||||
 | 
						public void bindTaskExecutorsToRegistry(Map<String, Executor> executors, MeterRegistry registry) {
 | 
				
			||||||
 | 
							executors.forEach((beanName, executor) -> {
 | 
				
			||||||
 | 
								if (executor instanceof ThreadPoolTaskExecutor) {
 | 
				
			||||||
 | 
									monitor(registry, safeGetThreadPoolExecutor((ThreadPoolTaskExecutor) executor),
 | 
				
			||||||
 | 
											() -> getTaskExecutorName(beanName));
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								else if (executor instanceof ThreadPoolTaskScheduler) {
 | 
				
			||||||
 | 
									monitor(registry, safeGetThreadPoolExecutor((ThreadPoolTaskScheduler) executor),
 | 
				
			||||||
 | 
											() -> getTaskSchedulerName(beanName));
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							});
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						private void monitor(MeterRegistry registry, ThreadPoolExecutor threadPoolExecutor, Supplier<String> beanName) {
 | 
				
			||||||
 | 
							if (threadPoolExecutor != null) {
 | 
				
			||||||
 | 
								ExecutorServiceMetrics.monitor(registry, threadPoolExecutor, beanName.get());
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						private ThreadPoolExecutor safeGetThreadPoolExecutor(ThreadPoolTaskExecutor taskExecutor) {
 | 
				
			||||||
 | 
							try {
 | 
				
			||||||
 | 
								return taskExecutor.getThreadPoolExecutor();
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							catch (IllegalStateException ex) {
 | 
				
			||||||
 | 
								return null;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						private ThreadPoolExecutor safeGetThreadPoolExecutor(ThreadPoolTaskScheduler taskScheduler) {
 | 
				
			||||||
 | 
							try {
 | 
				
			||||||
 | 
								return taskScheduler.getScheduledThreadPoolExecutor();
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							catch (IllegalStateException ex) {
 | 
				
			||||||
 | 
								return null;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/**
 | 
				
			||||||
 | 
						 * Get the name of a {@link ThreadPoolTaskExecutor} based on its {@code beanName}.
 | 
				
			||||||
 | 
						 * @param beanName the name of the {@link ThreadPoolTaskExecutor} bean
 | 
				
			||||||
 | 
						 * @return a name for the given task executor
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						private String getTaskExecutorName(String beanName) {
 | 
				
			||||||
 | 
							if (beanName.length() > TASK_EXECUTOR_SUFFIX.length()
 | 
				
			||||||
 | 
									&& StringUtils.endsWithIgnoreCase(beanName, TASK_EXECUTOR_SUFFIX)) {
 | 
				
			||||||
 | 
								return beanName.substring(0, beanName.length() - TASK_EXECUTOR_SUFFIX.length());
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							return beanName;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/**
 | 
				
			||||||
 | 
						 * Get the name of a {@link ThreadPoolTaskScheduler} based on its {@code beanName}.
 | 
				
			||||||
 | 
						 * @param beanName the name of the {@link ThreadPoolTaskScheduler} bean
 | 
				
			||||||
 | 
						 * @return a name for the given task scheduler
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						private String getTaskSchedulerName(String beanName) {
 | 
				
			||||||
 | 
							if (beanName.equals(TASK_SCHEDULER_SUFFIX)) {
 | 
				
			||||||
 | 
								return "application";
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							if (beanName.length() > TASK_SCHEDULER_SUFFIX.length()
 | 
				
			||||||
 | 
									&& StringUtils.endsWithIgnoreCase(beanName, TASK_SCHEDULER_SUFFIX)) {
 | 
				
			||||||
 | 
								return beanName.substring(0, beanName.length() - TASK_SCHEDULER_SUFFIX.length());
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							return beanName;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -0,0 +1,20 @@
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * Copyright 2012-2021 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.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Auto-configuration for task execution and scheduling metrics.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					package org.springframework.boot.actuate.autoconfigure.metrics.task;
 | 
				
			||||||
| 
						 | 
					@ -74,6 +74,7 @@ org.springframework.boot.actuate.autoconfigure.metrics.jersey.JerseyServerMetric
 | 
				
			||||||
org.springframework.boot.actuate.autoconfigure.metrics.mongo.MongoMetricsAutoConfiguration,\
 | 
					org.springframework.boot.actuate.autoconfigure.metrics.mongo.MongoMetricsAutoConfiguration,\
 | 
				
			||||||
org.springframework.boot.actuate.autoconfigure.metrics.orm.jpa.HibernateMetricsAutoConfiguration,\
 | 
					org.springframework.boot.actuate.autoconfigure.metrics.orm.jpa.HibernateMetricsAutoConfiguration,\
 | 
				
			||||||
org.springframework.boot.actuate.autoconfigure.metrics.r2dbc.ConnectionPoolMetricsAutoConfiguration,\
 | 
					org.springframework.boot.actuate.autoconfigure.metrics.r2dbc.ConnectionPoolMetricsAutoConfiguration,\
 | 
				
			||||||
 | 
					org.springframework.boot.actuate.autoconfigure.metrics.task.TaskExecutorMetricsAutoConfiguration,\
 | 
				
			||||||
org.springframework.boot.actuate.autoconfigure.metrics.web.client.HttpClientMetricsAutoConfiguration,\
 | 
					org.springframework.boot.actuate.autoconfigure.metrics.web.client.HttpClientMetricsAutoConfiguration,\
 | 
				
			||||||
org.springframework.boot.actuate.autoconfigure.metrics.web.jetty.JettyMetricsAutoConfiguration,\
 | 
					org.springframework.boot.actuate.autoconfigure.metrics.web.jetty.JettyMetricsAutoConfiguration,\
 | 
				
			||||||
org.springframework.boot.actuate.autoconfigure.metrics.web.reactive.WebFluxMetricsAutoConfiguration,\
 | 
					org.springframework.boot.actuate.autoconfigure.metrics.web.reactive.WebFluxMetricsAutoConfiguration,\
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -0,0 +1,147 @@
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * Copyright 2012-2021 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.actuate.autoconfigure.metrics.task;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import java.util.Collection;
 | 
				
			||||||
 | 
					import java.util.concurrent.Executor;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import io.micrometer.core.instrument.FunctionCounter;
 | 
				
			||||||
 | 
					import io.micrometer.core.instrument.MeterRegistry;
 | 
				
			||||||
 | 
					import org.junit.jupiter.api.Test;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import org.springframework.boot.actuate.autoconfigure.metrics.test.MetricsRun;
 | 
				
			||||||
 | 
					import org.springframework.boot.autoconfigure.AutoConfigurations;
 | 
				
			||||||
 | 
					import org.springframework.boot.autoconfigure.task.TaskExecutionAutoConfiguration;
 | 
				
			||||||
 | 
					import org.springframework.boot.autoconfigure.task.TaskSchedulingAutoConfiguration;
 | 
				
			||||||
 | 
					import org.springframework.boot.test.context.runner.ApplicationContextRunner;
 | 
				
			||||||
 | 
					import org.springframework.context.annotation.Configuration;
 | 
				
			||||||
 | 
					import org.springframework.scheduling.annotation.EnableScheduling;
 | 
				
			||||||
 | 
					import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
 | 
				
			||||||
 | 
					import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import static org.assertj.core.api.Assertions.assertThat;
 | 
				
			||||||
 | 
					import static org.mockito.BDDMockito.given;
 | 
				
			||||||
 | 
					import static org.mockito.Mockito.mock;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Tests for {@link TaskExecutorMetricsAutoConfiguration}.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * @author Stephane Nicoll
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					class TaskExecutorMetricsAutoConfigurationTests {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						private final ApplicationContextRunner contextRunner = new ApplicationContextRunner().with(MetricsRun.simple())
 | 
				
			||||||
 | 
								.withConfiguration(AutoConfigurations.of(TaskExecutorMetricsAutoConfiguration.class));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						@Test
 | 
				
			||||||
 | 
						void taskExecutorUsingAutoConfigurationIsInstrumented() {
 | 
				
			||||||
 | 
							this.contextRunner.withConfiguration(AutoConfigurations.of(TaskExecutionAutoConfiguration.class))
 | 
				
			||||||
 | 
									.run((context) -> {
 | 
				
			||||||
 | 
										MeterRegistry registry = context.getBean(MeterRegistry.class);
 | 
				
			||||||
 | 
										Collection<FunctionCounter> meters = registry.get("executor.completed").functionCounters();
 | 
				
			||||||
 | 
										assertThat(meters).singleElement()
 | 
				
			||||||
 | 
												.satisfies((meter) -> assertThat(meter.getId().getTag("name")).isEqualTo("application"));
 | 
				
			||||||
 | 
									});
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						@Test
 | 
				
			||||||
 | 
						void taskExecutorsWithCustomNamesAreInstrumented() {
 | 
				
			||||||
 | 
							this.contextRunner.withBean("firstTaskExecutor", Executor.class, ThreadPoolTaskExecutor::new)
 | 
				
			||||||
 | 
									.withBean("customName", ThreadPoolTaskExecutor.class, ThreadPoolTaskExecutor::new).run((context) -> {
 | 
				
			||||||
 | 
										MeterRegistry registry = context.getBean(MeterRegistry.class);
 | 
				
			||||||
 | 
										Collection<FunctionCounter> meters = registry.get("executor.completed").functionCounters();
 | 
				
			||||||
 | 
										assertThat(meters).map((meter) -> meter.getId().getTag("name")).containsExactlyInAnyOrder("first",
 | 
				
			||||||
 | 
												"customName");
 | 
				
			||||||
 | 
									});
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						@Test
 | 
				
			||||||
 | 
						void threadPoolTaskExecutorWithNoTaskExecutorIsIgnored() {
 | 
				
			||||||
 | 
							ThreadPoolTaskExecutor unavailableTaskExecutor = mock(ThreadPoolTaskExecutor.class);
 | 
				
			||||||
 | 
							given(unavailableTaskExecutor.getThreadPoolExecutor()).willThrow(new IllegalStateException("Test"));
 | 
				
			||||||
 | 
							this.contextRunner.withBean("firstTaskExecutor", ThreadPoolTaskExecutor.class, ThreadPoolTaskExecutor::new)
 | 
				
			||||||
 | 
									.withBean("customName", ThreadPoolTaskExecutor.class, () -> unavailableTaskExecutor).run((context) -> {
 | 
				
			||||||
 | 
										MeterRegistry registry = context.getBean(MeterRegistry.class);
 | 
				
			||||||
 | 
										Collection<FunctionCounter> meters = registry.get("executor.completed").functionCounters();
 | 
				
			||||||
 | 
										assertThat(meters).singleElement()
 | 
				
			||||||
 | 
												.satisfies((meter) -> assertThat(meter.getId().getTag("name")).isEqualTo("first"));
 | 
				
			||||||
 | 
									});
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						@Test
 | 
				
			||||||
 | 
						void taskExecutorInstrumentationCanBeDisabled() {
 | 
				
			||||||
 | 
							this.contextRunner.withPropertyValues("management.metrics.enable.executor=false")
 | 
				
			||||||
 | 
									.withConfiguration(AutoConfigurations.of(TaskExecutionAutoConfiguration.class)).run((context) -> {
 | 
				
			||||||
 | 
										MeterRegistry registry = context.getBean(MeterRegistry.class);
 | 
				
			||||||
 | 
										assertThat(registry.find("executor.completed").tags("name", "application").functionCounter())
 | 
				
			||||||
 | 
												.isNull();
 | 
				
			||||||
 | 
									});
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						@Test
 | 
				
			||||||
 | 
						void taskSchedulerUsingAutoConfigurationIsInstrumented() {
 | 
				
			||||||
 | 
							this.contextRunner.withConfiguration(AutoConfigurations.of(TaskSchedulingAutoConfiguration.class))
 | 
				
			||||||
 | 
									.withUserConfiguration(SchedulingTestConfiguration.class).run((context) -> {
 | 
				
			||||||
 | 
										MeterRegistry registry = context.getBean(MeterRegistry.class);
 | 
				
			||||||
 | 
										Collection<FunctionCounter> meters = registry.get("executor.completed").functionCounters();
 | 
				
			||||||
 | 
										assertThat(meters).singleElement()
 | 
				
			||||||
 | 
												.satisfies((meter) -> assertThat(meter.getId().getTag("name")).isEqualTo("application"));
 | 
				
			||||||
 | 
									});
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						@Test
 | 
				
			||||||
 | 
						void taskSchedulersWithCustomNamesAreInstrumented() {
 | 
				
			||||||
 | 
							this.contextRunner.withBean("firstTaskScheduler", Executor.class, ThreadPoolTaskScheduler::new)
 | 
				
			||||||
 | 
									.withBean("customName", ThreadPoolTaskScheduler.class, ThreadPoolTaskScheduler::new).run((context) -> {
 | 
				
			||||||
 | 
										MeterRegistry registry = context.getBean(MeterRegistry.class);
 | 
				
			||||||
 | 
										Collection<FunctionCounter> meters = registry.get("executor.completed").functionCounters();
 | 
				
			||||||
 | 
										assertThat(meters).map((meter) -> meter.getId().getTag("name")).containsExactlyInAnyOrder("first",
 | 
				
			||||||
 | 
												"customName");
 | 
				
			||||||
 | 
									});
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						@Test
 | 
				
			||||||
 | 
						void threadPoolTaskSchedulerWithNoTaskExecutorIsIgnored() {
 | 
				
			||||||
 | 
							ThreadPoolTaskScheduler unavailableTaskExecutor = mock(ThreadPoolTaskScheduler.class);
 | 
				
			||||||
 | 
							given(unavailableTaskExecutor.getScheduledThreadPoolExecutor()).willThrow(new IllegalStateException("Test"));
 | 
				
			||||||
 | 
							this.contextRunner.withBean("firstTaskScheduler", ThreadPoolTaskScheduler.class, ThreadPoolTaskScheduler::new)
 | 
				
			||||||
 | 
									.withBean("customName", ThreadPoolTaskScheduler.class, () -> unavailableTaskExecutor).run((context) -> {
 | 
				
			||||||
 | 
										MeterRegistry registry = context.getBean(MeterRegistry.class);
 | 
				
			||||||
 | 
										Collection<FunctionCounter> meters = registry.get("executor.completed").functionCounters();
 | 
				
			||||||
 | 
										assertThat(meters).singleElement()
 | 
				
			||||||
 | 
												.satisfies((meter) -> assertThat(meter.getId().getTag("name")).isEqualTo("first"));
 | 
				
			||||||
 | 
									});
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						@Test
 | 
				
			||||||
 | 
						void taskSchedulerInstrumentationCanBeDisabled() {
 | 
				
			||||||
 | 
							this.contextRunner.withPropertyValues("management.metrics.enable.executor=false")
 | 
				
			||||||
 | 
									.withConfiguration(AutoConfigurations.of(TaskSchedulingAutoConfiguration.class))
 | 
				
			||||||
 | 
									.withUserConfiguration(SchedulingTestConfiguration.class).run((context) -> {
 | 
				
			||||||
 | 
										MeterRegistry registry = context.getBean(MeterRegistry.class);
 | 
				
			||||||
 | 
										assertThat(registry.find("executor.completed").tags("name", "application").functionCounter())
 | 
				
			||||||
 | 
												.isNull();
 | 
				
			||||||
 | 
									});
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						@Configuration(proxyBeanMethods = false)
 | 
				
			||||||
 | 
						@EnableScheduling
 | 
				
			||||||
 | 
						static class SchedulingTestConfiguration {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -586,6 +586,13 @@ Details are published under the `log4j2.events.` or `logback.events.` meter name
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[[actuator.metrics.supported.tasks]]
 | 
				
			||||||
 | 
					==== Task Execution and Scheduling Metrics
 | 
				
			||||||
 | 
					Auto-configuration enables the instrumentation of all available `ThreadPoolTaskExecutor` and `ThreadPoolTaskScheduler` beans, as long as the underling `ThreadPoolExecutor` is available.
 | 
				
			||||||
 | 
					Metrics are tagged by the name of the executor that is derived from the bean name.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
[[actuator.metrics.supported.spring-mvc]]
 | 
					[[actuator.metrics.supported.spring-mvc]]
 | 
				
			||||||
==== Spring MVC Metrics
 | 
					==== Spring MVC Metrics
 | 
				
			||||||
Auto-configuration enables the instrumentation of all requests handled by Spring MVC controllers and functional handlers.
 | 
					Auto-configuration enables the instrumentation of all requests handled by Spring MVC controllers and functional handlers.
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in New Issue