Skip to content

Failed to record timer metrics in native image with percentiles configured #3002

@shakuzen

Description

@shakuzen

Describe the bug
When running an application as a GraalVM native image with percentiles configured, at runtime an error like the following will happen when trying to record e.g. a Timer.

Failed to record timer metrics

java.lang.IllegalArgumentException: java.lang.NoSuchMethodException: org.HdrHistogram.Histogram.<init>(long, long, int)
        at org.HdrHistogram.DoubleHistogram.<init>(DoubleHistogram.java:220) ~[na:na]
        at org.HdrHistogram.DoubleHistogram.<init>(DoubleHistogram.java:141) ~[na:na]
        at org.HdrHistogram.DoubleHistogram.<init>(DoubleHistogram.java:77) ~[na:na]
        at io.micrometer.core.instrument.distribution.TimeWindowPercentileHistogram.<init>(TimeWindowPercentileHistogram.java:38) ~[na:na]
        at io.micrometer.core.instrument.AbstractTimer.<init>(AbstractTimer.java:85) ~[na:na]
        at io.micrometer.prometheus.PrometheusTimer.<init>(PrometheusTimer.java:42) ~[na:na]
        at io.micrometer.prometheus.PrometheusMeterRegistry.newTimer(PrometheusMeterRegistry.java:268) ~[na:na]
        at io.micrometer.core.instrument.MeterRegistry.lambda$timer$2(MeterRegistry.java:311) ~[actuator-webmvc-metrics:1.8.2]
        at io.micrometer.core.instrument.MeterRegistry.getOrCreateMeter(MeterRegistry.java:620) ~[actuator-webmvc-metrics:1.8.2]
        at io.micrometer.core.instrument.MeterRegistry.registerMeterIfNecessary(MeterRegistry.java:569) ~[actuator-webmvc-metrics:1.8.2]
        at io.micrometer.core.instrument.MeterRegistry.timer(MeterRegistry.java:309) ~[actuator-webmvc-metrics:1.8.2]
        at io.micrometer.core.instrument.Timer$Builder.register(Timer.java:403) ~[na:na]
        at org.springframework.boot.actuate.metrics.web.servlet.WebMvcMetricsFilter.getTimer(WebMvcMetricsFilter.java:161) ~[na:na]
        at org.springframework.boot.actuate.metrics.web.servlet.WebMvcMetricsFilter.lambda$record$0(WebMvcMetricsFilter.java:139) ~[na:na]
        at org.springframework.boot.actuate.metrics.AutoTimer.apply(AutoTimer.java:109) ~[actuator-webmvc-metrics:2.6.3]
        at org.springframework.boot.actuate.metrics.web.servlet.WebMvcMetricsFilter.record(WebMvcMetricsFilter.java:138) ~[na:na]
        at org.springframework.boot.actuate.metrics.web.servlet.WebMvcMetricsFilter.doFilterInternal(WebMvcMetricsFilter.java:103) ~[na:na]
        at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:117) ~[na:na]
        at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:189) ~[na:na]
        at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162) ~[na:na]
        at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:201) ~[na:na]
        at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:117) ~[na:na]
        at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:189) ~[na:na]
        at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162) ~[na:na]
        at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:197) ~[na:na]
        at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:97) ~[na:na]
        at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:540) ~[na:na]
        at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:135) ~[na:na]
        at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:92) ~[na:na]
        at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:78) ~[na:na]
        at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:357) ~[na:na]
        at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:382) ~[na:na]
        at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:65) ~[na:na]
        at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:895) ~[na:na]
        at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1732) ~[na:na]
        at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49) ~[na:na]
        at org.apache.tomcat.util.threads.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1191) ~[na:na]
        at org.apache.tomcat.util.threads.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:659) ~[na:na]
        at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61) ~[na:na]
        at java.lang.Thread.run(Thread.java:833) ~[na:na]
        at com.oracle.svm.core.thread.JavaThreads.threadStartRoutine(JavaThreads.java:600) ~[na:na]
        at com.oracle.svm.core.posix.thread.PosixJavaThreads.pthreadStartRoutine(PosixJavaThreads.java:192) ~[na:na]
Caused by: java.lang.NoSuchMethodException: org.HdrHistogram.Histogram.<init>(long, long, int)
        at java.lang.Class.getConstructor0(DynamicHub.java:3585) ~[actuator-webmvc-metrics:na]
        at java.lang.Class.getConstructor(DynamicHub.java:2271) ~[actuator-webmvc-metrics:na]
        at org.HdrHistogram.DoubleHistogram.<init>(DoubleHistogram.java:178) ~[na:na]
        ... 41 common frames omitted

Environment

  • Micrometer version: 1.8.2
  • Micrometer registry: any
  • OS: macOS
  • Java version: [e.g. output of java -version] tested with GraalVM 22.0.0.2.r17-grl

To Reproduce
How to reproduce the bug:

In an application with micrometer-core on the classpath, have a main class like the following. Compile it to a native image and run it.

public static void main(String[] args ) {
    MeterRegistry registry = new SimpleMeterRegistry();
    Timer timer = Timer.builder("my.timer").publishPercentiles(0.5, 0.9, 0.99).register(registry);
    timer.record(5, TimeUnit.MILLISECONDS);
}

Expected behavior
No runtime exception. No additional reflection config required.

Additional context
While it would be ideal if the HdrHistogram library had the necessary native image reflection config provided, we may want to add configuration for the reflection usage we know about from Micrometer code.
The Spring Native project recently added hints for this same issue, but for non-Spring native usage of Micrometer, it would help those users to have it here, or eventually perhaps in HdrHistogram itself.

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions