add chi metrics middleware.

This commit is contained in:
Miroslav Šedivý
2022-06-15 00:22:27 +02:00
parent 5b7784f2a4
commit 0952be6a94
5 changed files with 162 additions and 0 deletions

View File

@ -5,6 +5,8 @@ import (
"errors"
"net/http"
"github.com/prometheus/client_golang/prometheus/promhttp"
"gitlab.com/demodesk/neko/server/internal/api/members"
"gitlab.com/demodesk/neko/server/internal/api/room"
"gitlab.com/demodesk/neko/server/pkg/auth"
@ -62,6 +64,11 @@ func (api *ApiManagerCtx) Route(r types.Router) {
_, err := w.Write([]byte("true"))
return err
})
r.Get("/metrics", func(w http.ResponseWriter, r *http.Request) error {
promhttp.Handler().ServeHTTP(w, r)
return nil
})
}
func (api *ApiManagerCtx) Authenticate(w http.ResponseWriter, r *http.Request) (context.Context, error) {

57
internal/http/metrics.go Normal file
View File

@ -0,0 +1,57 @@
package http
import (
"net/http"
"time"
"github.com/go-chi/chi/middleware"
"github.com/prometheus/client_golang/prometheus"
)
// Middleware is a handler that exposes prometheus metrics for the number of requests,
// the latency and the response size, partitioned by status code, method and HTTP path.
type metrics struct {
reqs *prometheus.CounterVec
latency *prometheus.HistogramVec
}
// NewMiddleware returns a new prometheus Middleware handler.
func middlewareMetrics(next http.Handler) http.Handler {
var m metrics
m.reqs = prometheus.NewCounterVec(
prometheus.CounterOpts{
Name: "requests_total",
Namespace: "neko",
Subsystem: "http",
Help: "How many HTTP requests processed, partitioned by status code, method and HTTP path.",
},
[]string{"code", "method", "path"},
)
prometheus.MustRegister(m.reqs)
m.latency = prometheus.NewHistogramVec(prometheus.HistogramOpts{
Name: "request_duration_milliseconds",
Namespace: "neko",
Subsystem: "http",
Help: "How long it took to process the request, partitioned by status code, method and HTTP path.",
Buckets: []float64{300, 1200, 5000},
},
[]string{"code", "method", "path"},
)
prometheus.MustRegister(m.latency)
return m.handler(next)
}
func (c metrics) handler(next http.Handler) http.Handler {
fn := func(w http.ResponseWriter, r *http.Request) {
start := time.Now()
ww := middleware.NewWrapResponseWriter(w, r.ProtoMajor)
next.ServeHTTP(ww, r)
c.reqs.WithLabelValues(http.StatusText(ww.Status()), r.Method, r.URL.Path).Inc()
c.latency.WithLabelValues(http.StatusText(ww.Status()), r.Method, r.URL.Path).Observe(float64(time.Since(start).Nanoseconds()) / 1000000)
}
return http.HandlerFunc(fn)
}

View File

@ -20,6 +20,7 @@ func newRouter(logger zerolog.Logger) *router {
r := chi.NewRouter()
r.Use(middleware.RequestID) // Create a request ID for each request
r.Use(middleware.RequestLogger(&logFormatter{logger}))
r.Use(middlewareMetrics)
r.Use(middleware.Recoverer) // Recover from panics without crashing server
return &router{r}
}