Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions collector.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import (

"github.com/go-chi/chi/v5"
"github.com/go-chi/chi/v5/middleware"
"github.com/prometheus/client_golang/prometheus"
)

var (
Expand All @@ -34,6 +35,10 @@ type CollectorOpts struct {
// Skip is an optional predicate function that determines whether to skip recording metrics for a given request.
// If nil, all requests are recorded. If provided, requests where Skip returns true will not be recorded.
Skip func(r *http.Request) bool

// Registry specifies the Prometheus registry to which the metrics will be registered.
// If nil, the default Prometheus registry is used.
Registry prometheus.Registerer
}

// requestLabels defines labels for the counter of total incoming HTTP requests.
Expand Down Expand Up @@ -63,6 +68,9 @@ type inflightLabels struct {
// - http_requests_inflight: Number of incoming HTTP requests currently in flight
// - http_request_duration_seconds: Response latency in seconds for completed requests
func Collector(opts CollectorOpts) func(next http.Handler) http.Handler {

registerMetrics(opts.Registry)

return func(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
if opts.Skip != nil && opts.Skip(r) {
Expand Down
2 changes: 0 additions & 2 deletions counter.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ func Counter(name string, help string) CounterMetric {
Name: mustValidMetricName(name),
Help: help,
}, []string{})
prometheus.MustRegister(vec)
return CounterMetric{vec: vec}
}

Expand All @@ -18,7 +17,6 @@ func CounterWith[T any](name string, help string) CounterMetricLabeled[T] {
Name: mustValidMetricName(name),
Help: help,
}, getLabelKeys[T]())
prometheus.MustRegister(vec)
return CounterMetricLabeled[T]{vec: vec}
}

Expand Down
2 changes: 0 additions & 2 deletions gauge.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ func Gauge(name, help string) GaugeMetric {
Name: mustValidMetricName(name),
Help: help,
}, []string{})
prometheus.MustRegister(vec)
return GaugeMetric{vec: vec}
}

Expand All @@ -18,7 +17,6 @@ func GaugeWith[T any](name, help string) GaugeMetricLabeled[T] {
Name: mustValidMetricName(name),
Help: help,
}, getLabelKeys[T]())
prometheus.MustRegister(vec)
return GaugeMetricLabeled[T]{vec: vec}
}

Expand Down
9 changes: 9 additions & 0 deletions handler.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,3 +15,12 @@ import (
func Handler() http.Handler {
return promhttp.HandlerFor(prometheus.DefaultGatherer, promhttp.HandlerOpts{})
}

// HandlerFor returns an HTTP handler that serves Prometheus metrics from the provided registry
// in the OpenMetrics exposition format.
//
// This handler should typically be mounted at "/metrics" and protected from public access,
// e.g. via middleware.BasicAuth or exposed only on a private port.
func HandlerFor(registry *prometheus.Registry) http.Handler {
return promhttp.HandlerFor(registry, promhttp.HandlerOpts{})
}
Copy link
Contributor

@VojtechVitek VojtechVitek Nov 14, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I designed this package to be agnostic of the github.com/prometheus/client_golang/prometheus dependency. We don't necessarily need to stick with it into the future.

However, this PR would buy us into the prometheus.Registerer and prometheus.Registry types for good.

I like what you have done in this PR and it makes sense to me. However, for the above reason, I'm hesitant to merge it.

@brpaz It might be an obvious questions -- but what is the use case for having multiple prometheus registries? Are there some applications that expose two different sets of /metrics endpoints?

2 changes: 0 additions & 2 deletions histogram.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@ func Histogram(name, help string, buckets []float64) HistogramMetric {
Help: help,
Buckets: buckets,
}, []string{})
prometheus.MustRegister(vec)
return HistogramMetric{vec: vec}
}

Expand All @@ -20,7 +19,6 @@ func HistogramWith[T any](name, help string, buckets []float64) HistogramMetricL
Help: help,
Buckets: buckets,
}, getLabelKeys[T]())
prometheus.MustRegister(vec)
return HistogramMetricLabeled[T]{vec: vec}
}

Expand Down
13 changes: 13 additions & 0 deletions registry.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package metrics

import "github.com/prometheus/client_golang/prometheus"

// registerMetrics registers all metrics with the provided Prometheus registry.
func registerMetrics(registry prometheus.Registerer) {
if registry == nil {
registry = prometheus.DefaultRegisterer.(*prometheus.Registry)
}
registry.MustRegister(requestsCounter.vec)
registry.MustRegister(inflightGauge.vec)
registry.MustRegister(requestsHistogram.vec)
}