Skip to main content

Java Registry

The Java registry implements MetricRegistry, wrapping the Prometheus Java library. This provides interoperability with anything that depends on the Java library.

ℹ️ The Java Registry does add a runtime constraint that goes beyond constraints that Prometheus itself imposes: You cannot have two metrics of the same name with different labels. This issue describes the problem.

See the example below on how to use the Java Registry:

import cats.effect.IO
import cats.effect.Resource

import io.prometheus.metrics.model.registry.PrometheusRegistry

import prometheus4cats.MetricFactory
import prometheus4cats.javaclient.JavaMetricRegistry

// Construct a Java registry using a default PrometheusRegistry
val default: Resource[IO, JavaMetricRegistry[IO]] =
JavaMetricRegistry.Builder[IO]().build

// Construct a Java registry using a custom PrometheusRegistry
val custom: Resource[IO, JavaMetricRegistry[IO]] =
JavaMetricRegistry.Builder[IO]().withRegistry(new PrometheusRegistry()).build

// Use the registry to get a factory
val factory: Resource[IO, MetricFactory[IO]] =
custom.map(MetricFactory.builder.build(_))

Stale Series Eviction

Metrics labelled by unbounded or churning values accumulate dead series for the lifetime of the process, growing the exposition (and scrape cost) without bound. Builder#withStaleSeriesEviction(ttl) opts in to evicting them: a label set that has not been written to within ttl is exposed one final time and then removed at scrape time, so it is absent from subsequent scrapes. A later write recreates the series, which restarts from zero — consumers should be comfortable with counters resetting.

Operational caveats:

  • Only metrics with at least one dynamic label participate; unlabelled, common-labels-only, Info and callback-backed metrics are untouched.
  • Every labelled stateful metric participates, gauges included. A labelled gauge that is set once (a build_info style constant) or only on change is evicted ttl after its last set and stays absent until the next one, so absent(...) or == 1 alerts over it can misfire. Keep such gauges unlabelled, or do not enable eviction on the registry that holds them.
  • Eviction is driven by the scrape, so a registry that is never scraped never evicts.
  • The registry retains a small tracking entry (label values plus a timestamp) per live label set.

Implementation Notes

As per the MetricRegistry interface, this implementation returns Cats-Effect Resources to indicate a metric being registered and ultimately de-registered. Requesting a metric of the same name (and labels) multiple times will not result in an error, instead you will be returned the currently registered metric. The Java registry wrapper implements reference counting to ensure that a metric will only be de-registered when there are no more references to it or when the wrapper's surrounding Resource is finalized.