Skip to content

1.18 Migration Guide

Tommy Ludwig edited this page Oct 28, 2026 · 4 revisions

Atlas Registry

Atlas FunctionTimer Statistics Published as Rates

AtlasMeterRegistry now publishes FunctionTimer statistics (statistic=count and statistic=totalTime) as per-second rates (atlas.dstype=rate) rather than gauges, aligning them with standard Timer and FunctionCounter behavior in Atlas.

What Changed

Previously, AtlasMeterRegistry registered FunctionTimer through the generic newMeter path, which published the measurements as gauges (atlas.dstype=gauge). The reported values were deltas over the step interval (1 minute by default) rather than per-second rates:

  • statistic=count was reported as total events per step interval (e.g., requests per minute).
  • statistic=totalTime was reported as total seconds per step interval (e.g., seconds of work per minute).
  • The values were ~60x higher (with a 1-minute step) than a native Spectator Timer or a standard Micrometer Timer.
  • Because they were typed as gauges, Atlas averaged them rather than normalizing them when consolidating across time into larger step intervals.

Starting with Micrometer 1.18.0:

  • statistic=count is polled via PolledMeter.monitorMonotonicCounter and published as an event rate per second.
  • statistic=totalTime is polled via PolledMeter.monitorMonotonicCounterDouble and published as total seconds per second.
  • Idle FunctionTimer instances whose referenced objects have been garbage collected will now expire after meterTTL rather than continuing to report 0 indefinitely.

This affects every meter binder backed by a FunctionTimer, including Tomcat request metrics (tomcat.global.request, tomcat.servlet.request), Jetty request timers, and cache, executor, and Hibernate timers.

Action Required

  • Dashboards and Alerts: If you have Atlas queries or alert rules that divided FunctionTimer values by 60 (or your configured step interval in seconds) to compute a rate, remove that division.
  • Scale Adjustment: With the default 1-minute step, published count and totalTime values will be ~60x lower than in previous releases.
  • Latency Expressions: Expressions calculating average latency (statistic=totalTime / statistic=count) are unaffected because the rate scaling factors cancel out.

Prometheus Registry

Prometheus Meter Registration: Eager Validation of Duplicate Metric Family Names

In Micrometer 1.18.0, PrometheusMeterRegistry (for Prometheus Java Client 1.x, micrometer-registry-prometheus) validates metric family descriptors at meter registration time rather than during scrape collection.

What Changed

Previously, if different meters mapped to the same Prometheus metric family name (for example, registering a Timer("test") which generates test_seconds_max along with a separate Gauge("test_seconds_max")), both meters were accepted at registration time, but subsequent calls to scrape() would fail with a DuplicateLabelsException.

In 1.18.0, the Prometheus client detects the duplicate metric family name during registration and fails to register meters that would conflict after the first:

  • By default, the duplicate meter registration fails gracefully: a warning is logged and the duplicate meter is discarded. Subsequent scrapes succeed and export only the originally registered meter's metrics.
  • If you configured registry.throwExceptionOnRegistrationFailure() or an onMeterRegistrationFailed callback on registry.config(), the failure occurs immediately upon calling .register(...) instead of when Prometheus scrapes the endpoint.

Consistent Histogram Configuration for Meters with the Same Name

In Prometheus, all time series sharing the same metric name must produce the same metric family type. In Micrometer's Prometheus registry, a Timer or DistributionSummary produces a SUMMARY by default, or a HISTOGRAM if percentile histograms or SLO buckets are configured.

What Changed

In 1.17, registering meters with the same name where only some configured histogram buckets succeeded at registration time but failed with an unhandled ClassCastException when scraping the Prometheus endpoint.

In 1.18.0:

  • Metric family types are validated eagerly when meters are registered.
  • If a Timer or DistributionSummary is registered whose histogram configuration conflicts with an already-registered meter of the same name:
    • Default behavior: A warning log explains that meters with the same name must produce the same family type (e.g. SUMMARY vs HISTOGRAM). The conflicting meter is ignored, preventing the scrape endpoint from failing.
    • When throwExceptionOnRegistrationFailure() is enabled: An IllegalArgumentException is thrown immediately upon calling .register(...).

Action Required

Review your Timer and DistributionSummary configurations to ensure meters sharing the same name configure histograms consistently across all tag sets:

  • Ensure that any MeterFilter configuring histogram buckets (such as publishPercentileHistogram(), serviceLevelObjectives(), or min/max expected values) matches all meters for a given metric name rather than a subset based on specific tag values.
  • Ensure application code and @Timed(histogram = ...) annotations consistently enable or disable histograms across different registration sites for the same metric name.