Monorepo for Tangled
tangled.org
1package metrics
2
3import (
4 "bufio"
5 "fmt"
6 "net"
7 "net/http"
8 "time"
9
10 "github.com/go-chi/chi/v5"
11)
12
13type statusRecorder struct {
14 http.ResponseWriter
15 status int
16}
17
18func (r *statusRecorder) WriteHeader(status int) {
19 r.status = status
20 r.ResponseWriter.WriteHeader(status)
21}
22
23func (r *statusRecorder) Hijack() (net.Conn, *bufio.ReadWriter, error) {
24 h, ok := r.ResponseWriter.(http.Hijacker)
25 if !ok {
26 return nil, nil, fmt.Errorf("underlying ResponseWriter does not support hijacking")
27 }
28 return h.Hijack()
29}
30
31func Middleware(next http.Handler) http.Handler {
32 return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
33 rec := &statusRecorder{ResponseWriter: w, status: http.StatusOK}
34 start := time.Now()
35
36 next.ServeHTTP(rec, r)
37
38 // use the matched route pattern to avoid high cardinality
39 routePattern := chi.RouteContext(r.Context()).RoutePattern()
40 if routePattern == "" {
41 routePattern = "unknown"
42 }
43
44 status := fmt.Sprintf("%d", rec.status)
45 duration := time.Since(start).Seconds()
46
47 HttpRequestsTotal.WithLabelValues(r.Method, routePattern, status).Inc()
48 HttpRequestDuration.WithLabelValues(r.Method, routePattern, status).Observe(duration)
49 })
50}