In #23818 support for Task Execution and Scheduling Metrics was added.

However, the TaskExecutorMetricsAutoConfiguration uses ExecutorServiceMetrics.monitor(registry, threadPoolExecutor, beanName.get()) to perform the registration. Doing it like this will cause the metrics to also have each ExecutorService to be wrapped in TimedExecutorService and this will register the following metrics:

  • executor
  • executor.idle

This metrics are entirely useless because they are never updated since the return type is never used. There is #27041 which is requesting support for those 2 metrics and I think that this is something that can be handled separately. For now I would suggest that the TaskExecutorMetricsAutoConfiguration only calls

new ExecutorServiceMetrics(threadPoolExecutor, beanName.get(), Collections.emptySet()).bindTo(registry)

A test case to see this is

@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"));

                ThreadPoolTaskExecutor bean = context.getBean(ThreadPoolTaskExecutor.class);
                Timer timerMeter = registry.get("executor").timer();
                assertThat(timerMeter.count()).isZero();
                CountDownLatch latch = new CountDownLatch(1);
                bean.execute(latch::countDown);
                if (latch.await(100, TimeUnit.MILLISECONDS)) {
                    assertThat(timerMeter.count()).isEqualTo(1);
                } else {
                    fail("Task never executed");
                }

            });
}