1
0
mirror of https://github.com/oauth2-proxy/oauth2-proxy.git synced 2025-01-10 04:18:14 +02:00
oauth2-proxy/pkg/middleware/metrics.go

123 lines
4.2 KiB
Go
Raw Normal View History

package middleware
import (
"net/http"
"github.com/justinas/alice"
"github.com/prometheus/client_golang/prometheus"
"github.com/prometheus/client_golang/prometheus/promhttp"
)
// DefaultMetricsHandler is the default http.Handler for serving metrics from
// the default prometheus.Registry
var DefaultMetricsHandler = NewMetricsHandlerWithDefaultRegistry()
// NewMetricsHandlerWithDefaultRegistry creates a new http.Handler for serving
// metrics from the default prometheus.Registry.
func NewMetricsHandlerWithDefaultRegistry() http.Handler {
return NewMetricsHandler(prometheus.DefaultRegisterer, prometheus.DefaultGatherer)
}
// NewMetricsHandler creates a new http.Handler for serving metrics from the
// provided prometheus.Registerer and prometheus.Gatherer
func NewMetricsHandler(registerer prometheus.Registerer, gatherer prometheus.Gatherer) http.Handler {
return promhttp.InstrumentMetricHandler(
registerer, promhttp.HandlerFor(gatherer, promhttp.HandlerOpts{}),
)
}
// NewRequestMetricsWithDefaultRegistry returns a middleware that will record
// metrics for HTTP requests to the default prometheus.Registry
func NewRequestMetricsWithDefaultRegistry() alice.Constructor {
return NewRequestMetrics(prometheus.DefaultRegisterer)
}
// NewRequestMetrics returns a middleware that will record metrics for HTTP
// requests to the provided prometheus.Registerer
func NewRequestMetrics(registerer prometheus.Registerer) alice.Constructor {
return func(next http.Handler) http.Handler {
// Counter for all requests
// This is bucketed based on the response code we set
counterHandler := func(next http.Handler) http.Handler {
return promhttp.InstrumentHandlerCounter(registerRequestsCounter(registerer), next)
}
// Gauge to all requests currently being handled
inFlightHandler := func(next http.Handler) http.Handler {
return promhttp.InstrumentHandlerInFlight(registerInflightRequestsGauge(registerer), next)
}
// The latency of all requests bucketed by HTTP method
durationHandler := func(next http.Handler) http.Handler {
return promhttp.InstrumentHandlerDuration(registerRequestsLatencyHistogram(registerer), next)
}
return alice.New(counterHandler, inFlightHandler, durationHandler).Then(next)
}
}
// registerRequestsCounter registers the 'oauth2_proxy_requests_total' metric
// This keeps a tally of all received requests bucket by their HTTP response
// status code
func registerRequestsCounter(registerer prometheus.Registerer) *prometheus.CounterVec {
counter := prometheus.NewCounterVec(
prometheus.CounterOpts{
Name: "oauth2_proxy_requests_total",
Help: "Total number of requests by HTTP status code.",
},
[]string{"code"},
)
if err := registerer.Register(counter); err != nil {
if are, ok := err.(prometheus.AlreadyRegisteredError); ok {
counter = are.ExistingCollector.(*prometheus.CounterVec)
} else {
panic(err)
}
}
return counter
}
// registerInflightRequestsGauge registers 'oauth2_proxy_requests_in_flight'
// This only keeps the count of currently in progress HTTP requests
func registerInflightRequestsGauge(registerer prometheus.Registerer) prometheus.Gauge {
gauge := prometheus.NewGauge(prometheus.GaugeOpts{
Name: "oauth2_proxy_requests_in_flight",
Help: "Current number of requests being served.",
})
if err := registerer.Register(gauge); err != nil {
if are, ok := err.(prometheus.AlreadyRegisteredError); ok {
gauge = are.ExistingCollector.(prometheus.Gauge)
} else {
panic(err)
}
}
return gauge
}
// registerRequestsLatencyHistogram registers 'oauth2_proxy_response_duration_seconds'
// This keeps tally of the requests bucketed by the time taken to process the request
func registerRequestsLatencyHistogram(registerer prometheus.Registerer) *prometheus.HistogramVec {
histogram := prometheus.NewHistogramVec(
prometheus.HistogramOpts{
Name: "oauth2_proxy_response_duration_seconds",
Help: "A histogram of request latencies.",
Buckets: prometheus.DefBuckets,
},
[]string{"method"},
)
if err := registerer.Register(histogram); err != nil {
if are, ok := err.(prometheus.AlreadyRegisteredError); ok {
histogram = are.ExistingCollector.(*prometheus.HistogramVec)
} else {
panic(err)
}
}
return histogram
}