Skip to content

ExecutorServiceMetrics: repeatedly logs exception when monitoring ThreadPerTaskExecutor without --add-opens #6726

@AB-xdev

Description

@AB-xdev

Describe the bug
https://github.com/micrometer-metrics/micrometer/blob/v1.15.4/micrometer-core/src/main/java/io/micrometer/core/instrument/binder/jvm/ExecutorServiceMetrics.java

METHOD_HANDLE_THREAD_COUNT_FROM_THREAD_PER_TASK_EXECUTOR can be null when --add-opens java.base/java.util.concurrent=ALL-UNNAMED is missing.
However it will still be utilized because allowIllegalReflectiveAccess is set to true - by default.

This causes constant crashes with java.util.concurrent.ThreadPerTaskExecutor.

Environment

  • Micrometer version: 1.15.3 (Spring Boot 3.x)
  • Micrometer registry: prometheus
  • OS: irrelevant
  • Java version: 21.0.8 (Temurin)

To Reproduce
How to reproduce the bug:

Register ExecutorServiceMetrics to java.util.concurrent.ThreadPerTaskExecutor.
Then scrape the metrics

Observe the following exception:

12:01:11.111Z DEBUG 16741 --- [omcat-handler-0] i.m.c.instrument.internal.DefaultGauge   : Failed to apply the value function for the gauge 'executor.active'.

java.lang.RuntimeException: java.lang.NullPointerException: Cannot invoke "java.lang.invoke.MethodHandle.invoke(java.util.concurrent.ExecutorService)" because "io.micrometer.core.instrument.binder.jvm.ExecutorServiceMetrics.METHOD_HANDLE_THREAD_COUNT_FROM_THREAD_PER_TASK_EXECUTOR" is null
	at io.micrometer.core.instrument.binder.jvm.ExecutorServiceMetrics.getThreadCountFromThreadPerTaskExecutor(ExecutorServiceMetrics.java:482) ~[micrometer-core-1.15.3.jar:1.15.3]
	at io.micrometer.core.instrument.internal.DefaultGauge.value(DefaultGauge.java:53) ~[micrometer-core-1.15.3.jar:1.15.3]
	at io.micrometer.prometheusmetrics.PrometheusMeterRegistry.lambda$newGauge$12(PrometheusMeterRegistry.java:339) ~[micrometer-registry-prometheus-1.15.3.jar:1.15.3]
	at io.micrometer.prometheusmetrics.MicrometerCollector.collect(MicrometerCollector.java:84) ~[micrometer-registry-prometheus-1.15.3.jar:1.15.3]
	at io.prometheus.metrics.model.registry.PrometheusRegistry.scrape(PrometheusRegistry.java:84) ~[prometheus-metrics-model-1.3.10.jar:na]
	at io.prometheus.metrics.model.registry.PrometheusRegistry.scrape(PrometheusRegistry.java:66) ~[prometheus-metrics-model-1.3.10.jar:na]
	at org.springframework.boot.actuate.metrics.export.prometheus.PrometheusScrapeEndpoint.scrape(PrometheusScrapeEndpoint.java:75) ~[spring-boot-actuator-3.5.5.jar:3.5.5]
	at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:103) ~[na:na]
	at java.base/java.lang.reflect.Method.invoke(Method.java:580) ~[na:na]
	at org.springframework.util.ReflectionUtils.invokeMethod(ReflectionUtils.java:281) ~[spring-core-6.2.10.jar:6.2.10]
	at org.springframework.boot.actuate.endpoint.invoke.reflect.ReflectiveOperationInvoker.invoke(ReflectiveOperationInvoker.java:74) ~[spring-boot-actuator-3.5.5.jar:3.5.5]
	...
	at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:116) ~[tomcat-embed-core-10.1.44.jar:10.1.44]
	at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:93) ~[tomcat-embed-core-10.1.44.jar:10.1.44]
	at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:74) ~[tomcat-embed-core-10.1.44.jar:10.1.44]
	at org.apache.catalina.valves.RemoteIpValve.invoke(RemoteIpValve.java:732) ~[tomcat-embed-core-10.1.44.jar:10.1.44]
	at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:344) ~[tomcat-embed-core-10.1.44.jar:10.1.44]
	at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:398) ~[tomcat-embed-core-10.1.44.jar:10.1.44]
	at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:63) ~[tomcat-embed-core-10.1.44.jar:10.1.44]
	at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:903) ~[tomcat-embed-core-10.1.44.jar:10.1.44]
	at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1769) ~[tomcat-embed-core-10.1.44.jar:10.1.44]
	at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:52) ~[tomcat-embed-core-10.1.44.jar:10.1.44]
	at java.base/java.lang.VirtualThread.run(VirtualThread.java:329) ~[na:na]
Caused by: java.lang.NullPointerException: Cannot invoke "java.lang.invoke.MethodHandle.invoke(java.util.concurrent.ExecutorService)" because "io.micrometer.core.instrument.binder.jvm.ExecutorServiceMetrics.METHOD_HANDLE_THREAD_COUNT_FROM_THREAD_PER_TASK_EXECUTOR" is null
	at io.micrometer.core.instrument.binder.jvm.ExecutorServiceMetrics.getThreadCountFromThreadPerTaskExecutor(ExecutorServiceMetrics.java:479) ~[micrometer-core-1.15.3.jar:1.15.3]
	... 144 common frames omitted

I think the best solution would be to add a check here if METHOD_HANDLE_THREAD_COUNT_FROM_THREAD_PER_TASK_EXECUTOR is null and if this is the case: Not bind the executor and log a warning instead.

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugA general bughelp wantedAn issue that a contributor can help us withinstrumentationAn issue that is related to instrumenting a componentmodule: micrometer-coreAn issue that is related to our core module

    Type

    Projects

    No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions