Serve /metrics from a registry of its own (closes #227)
check / check (push) Successful in 3m25s

A second metrics-enabled router in one process panicked on a duplicate collector registration, because every collector registered on Prometheus's global default registry. metrics.NewRegistry now builds one registry with the Go runtime and process collectors; fx provides it and the delivery metric set built on it. The middleware builds its HTTP recorder once on that registry (NewForTest on a fresh one), the engine and handlers take the metric set from fx, and nothing registers on the global default any more.

/metrics is served from the new registry with the same series names, labels and auth. A test builds two metrics-enabled routers in one process.

Model: opus-5-5
This commit was merged in pull request #346.
This commit is contained in:
2026-10-02 09:06:20 +02:00
parent cb7bafab17
commit eb4c4cc849
17 changed files with 194 additions and 64 deletions
+7 -8
View File
@@ -7,7 +7,6 @@ import (
"github.com/go-chi/chi"
httpmetrics "github.com/slok/go-http-metrics/metrics"
prommetrics "github.com/slok/go-http-metrics/metrics/prometheus"
ghmm "github.com/slok/go-http-metrics/middleware"
"github.com/slok/go-http-metrics/middleware/std"
)
@@ -151,17 +150,17 @@ func (r boundedLabelRecorder) AddInflightRequests(
var _ httpmetrics.Recorder = boundedLabelRecorder{}
// Metrics returns middleware that records Prometheus HTTP metrics on
// the default registry, which is the one the /metrics route gathers.
// Metrics returns middleware that records Prometheus HTTP metrics
// with the Middleware's one recorder, which New builds on the registry
// the /metrics route serves and NewForTest on a registry of its own.
// Every call reuses that recorder, so any number of routers can
// install it.
func (s *Middleware) Metrics() func(http.Handler) http.Handler {
return metricsMiddleware(
prommetrics.NewRecorder(prommetrics.Config{}),
)
return metricsMiddleware(s.metricsRecorder)
}
// metricsMiddleware builds the recording middleware against a given
// recorder, so tests can gather from a registry of their own instead
// of the process-wide default.
// recorder, so tests can gather from a registry of their own.
func metricsMiddleware(
rec httpmetrics.Recorder,
) func(http.Handler) http.Handler {