Monorepo for Tangled
tangled.org
1package xrpc
2
3import (
4 "fmt"
5 "net/http"
6 "time"
7
8 "github.com/go-chi/chi/v5"
9 "github.com/prometheus/client_golang/prometheus"
10 "github.com/prometheus/client_golang/prometheus/promauto"
11)
12
13var (
14 httpRequestsTotal = promauto.NewCounterVec(prometheus.CounterOpts{
15 Name: "knotmirror_http_requests_total",
16 Help: "Total number of HTTP requests",
17 }, []string{"method", "path", "status", "repo"})
18
19 httpRequestDuration = promauto.NewHistogramVec(prometheus.HistogramOpts{
20 Name: "knotmirror_http_request_duration_seconds",
21 Help: "HTTP request duration in seconds",
22 Buckets: prometheus.DefBuckets,
23 }, []string{"method", "path", "status", "repo"})
24)
25
26type statusRecorder struct {
27 http.ResponseWriter
28 status int
29}
30
31func (r *statusRecorder) WriteHeader(status int) {
32 r.status = status
33 r.ResponseWriter.WriteHeader(status)
34}
35
36func metricsMiddleware(next http.Handler) http.Handler {
37 return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
38 rec := &statusRecorder{ResponseWriter: w, status: http.StatusOK}
39 start := time.Now()
40
41 next.ServeHTTP(rec, r)
42
43 routePattern := chi.RouteContext(r.Context()).RoutePattern()
44 if routePattern == "" {
45 routePattern = "unknown"
46 }
47
48 repo := r.URL.Query().Get("repo")
49 if repo == "" {
50 repo = "unknown"
51 }
52
53 status := fmt.Sprintf("%d", rec.status)
54 duration := time.Since(start).Seconds()
55
56 httpRequestsTotal.WithLabelValues(r.Method, routePattern, status, repo).Inc()
57 httpRequestDuration.WithLabelValues(r.Method, routePattern, status, repo).Observe(duration)
58 })
59}