Monorepo for Tangled
0

Configure Feed

Select the types of activity you want to include in your feed.

knotmirror/xrpc: add more prometheus metrics

Signed-off-by: Anirudh Oppiliappan <anirudh@tangled.org>

Anirudh Oppiliappan (May 12, 2026, 12:24 AM +0300) daa2beea 76ffc5de

+67 -1
+59
knotmirror/xrpc/metrics.go
··· 1 + package xrpc 2 + 3 + import ( 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 + 13 + var ( 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 + 26 + type statusRecorder struct { 27 + http.ResponseWriter 28 + status int 29 + } 30 + 31 + func (r *statusRecorder) WriteHeader(status int) { 32 + r.status = status 33 + r.ResponseWriter.WriteHeader(status) 34 + } 35 + 36 + func 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 + }
+1
knotmirror/xrpc/xrpc.go
··· 41 41 42 42 func (x *Xrpc) Router() http.Handler { 43 43 r := chi.NewRouter() 44 + r.Use(metricsMiddleware) 44 45 45 46 r.Get("/"+tangled.GitTempGetArchiveNSID, x.GetArchive) 46 47 r.Get("/"+tangled.GitTempGetBlobNSID, x.GetBlob)
+7 -1
nix/modules/knotmirror.nix
··· 36 36 description = "Address to listen on"; 37 37 }; 38 38 39 + metricsListenAddr = mkOption { 40 + type = types.str; 41 + default = "127.0.0.1:7100"; 42 + description = "Listen address for the Prometheus metrics endpoint"; 43 + }; 44 + 39 45 hostname = mkOption { 40 46 type = types.str; 41 47 example = "my.knotmirror.com"; ··· 143 149 "MIRROR_KNOT_USE_SSL=${boolToString cfg.knotUseSSL}" 144 150 "MIRROR_KNOT_SSRF=${boolToString cfg.knotSSRF}" 145 151 "MIRROR_RESYNC_PARALLELISM=12" 146 - "MIRROR_METRICS_LISTEN=127.0.0.1:7100" 152 + "MIRROR_METRICS_LISTEN=${cfg.metricsListenAddr}" 147 153 "MIRROR_ADMIN_LISTEN=${cfg.adminListenAddr}" 148 154 "MIRROR_SLURPER_CONCURRENCY=4" 149 155 ];