A MetricsCollector that records into a Micrometer io.micrometer.core.instrument.MeterRegistry.
Use it when the application already has a registry (Spring Boot's Actuator registry, a Quarkus registry, a PrometheusMeterRegistry of your own) and the LLM metrics should appear next to the rest:
val metrics = new MicrometerMetrics(registry)
val client = LLMConnect.getClient(config, metrics)
The meter names follow the series that llm4s-observability-prometheus exposes, so a dashboard built on llm4s_requests_total or llm4s_request_duration_seconds keeps working when the registry is exported as Prometheus (Micrometer's Prometheus naming turns llm4s.requests into llm4s_requests_total). See MicrometerMetrics.Names for every meter and its tags; the full table is in the monitoring guide.
Properties:
No global state: the registry is the only state, and two collectors on two registries are independent.
Safe: like every MetricsCollector, no method throws. A failure inside Micrometer (for example a MeterFilter that rejects a meter) is logged at WARN and dropped.
Bounded tag cardinality: tags are provider, model, a fixed outcome or error label, a fixed token type, and a fixed set of image operations and circuit-breaker states. Anything outside those sets is recorded as other, and a blank provider or model as unknown. Prompts, user ids, request ids and other unbounded values are never tags. provider and model come from the caller, so they are capped too: after 64 distinct providers or 256 distinct models on one collector, further values are recorded as other (logged once at WARN), so arbitrary model strings cannot grow the registry without limit.
Thread-safe: Micrometer meters are, and this class holds no mutable state.
Differences from PrometheusMetrics: this class also implements recordRetryAttempt, recordCircuitBreakerTransition and recordError, which the Prometheus collector leaves as no-ops, and it ignores negative or non-finite amounts instead of passing them to the registry.
This module is Beta: the meter names are intended to be stable, but they are not covered by the 1.x compatibility promise.
override def recordCost(provider: String, model: String, costUsd: Double): Unit
Record estimated cost in USD.
Record estimated cost in USD.
Use this after pricing metadata is available for a request or image generation operation. Implementations should treat the value as an additive counter.