Class MicrometerResilienceMetrics

java.lang.Object
io.github.teceli.resiliencia.micrometer.MicrometerResilienceMetrics
All Implemented Interfaces:
ResilienceMetrics

public final class MicrometerResilienceMetrics extends Object implements ResilienceMetrics
ResilienceMetrics backed by a Micrometer MeterRegistry.

Timers created by this class never opt into publishPercentileHistogram() or serviceLevelObjectives(...), to avoid the internal synchronized bucket-rotation path those features enable.

Every metric emitted here is tagged with the pattern instance's name (the "name" tag). That name must be a static, compile-time-known string — never request-derived or tenant-derived — since it becomes a cardinality-bounded tag value in the Micrometer registry; unbounded distinct names would cause unbounded memory growth in the metrics backend.

The per-metricName + name gauge holder cache is bounded at MAX_GAUGE_CACHE_ENTRIES entries. A caller respecting the "names must be static" contract above will only ever register a small, fixed number of distinct combinations, so this bound is never reached in normal use. If it is reached — a caller not respecting that contract — further distinct combinations are not registered as new gauges (already-registered gauges keep updating normally) and a single WARN is logged, rather than growing the cache without limit. Not evicting is deliberate: an LRU-style eviction would silently stop updating a gauge a caller is still actively using, which is worse than refusing new, previously-unseen entries once the bound is hit. The cache lookup itself stays lock-free (no synchronized), consistent with the pinning-avoidance contract for this module's event-to-metric mapping code — the trade-off is that the bound is enforced with a plain read-then-act check on the cache size, not a single atomic reservation, so under many threads racing to register distinct, previously-unseen keys at exactly the boundary at the same instant, the cache can settle slightly above MAX_GAUGE_CACHE_ENTRIES rather than exactly at it. It never grows without bound, and the same trade-off (approximate, not exact, sizing under concurrent writes) is inherent to lock-free bounded caches generally.

  • Constructor Summary

    Constructors
    Constructor
    Description
    MicrometerResilienceMetrics(io.micrometer.core.instrument.MeterRegistry registry)
     
  • Method Summary

    Modifier and Type
    Method
    Description
    void
    observe(Counters counters)
    Observe a counter/timer-worthy occurrence from any pattern (Retry, Timeout, CircuitBreaker, Bulkhead, RateLimiter) or from Policy's order validation.
    void
    observe(Snapshot snapshot)
    Observe a gauge-worthy snapshot of live state from CircuitBreaker, Bulkhead, or RateLimiter.

    Methods inherited from class java.lang.Object

    clone, equals, finalize, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait
  • Constructor Details

    • MicrometerResilienceMetrics

      public MicrometerResilienceMetrics(io.micrometer.core.instrument.MeterRegistry registry)
  • Method Details

    • observe

      public void observe(Snapshot snapshot)
      Description copied from interface: ResilienceMetrics
      Observe a gauge-worthy snapshot of live state from CircuitBreaker, Bulkhead, or RateLimiter.
      Specified by:
      observe in interface ResilienceMetrics
      Parameters:
      snapshot - the snapshot to observe; never null
    • observe

      public void observe(Counters counters)
      Description copied from interface: ResilienceMetrics
      Observe a counter/timer-worthy occurrence from any pattern (Retry, Timeout, CircuitBreaker, Bulkhead, RateLimiter) or from Policy's order validation.
      Specified by:
      observe in interface ResilienceMetrics
      Parameters:
      counters - the counter event to observe; never null