From 73266df0f5e2508fb7276b99069a0e858ab8c45e Mon Sep 17 00:00:00 2001 From: TheFox0x7 Date: Tue, 14 Jan 2025 00:01:21 +0100 Subject: [PATCH] feat(metrics): add cache, process and http metrics --- modules/cache/cache.go | 22 ++++++++++++++++++++++ modules/cache/string_cache.go | 6 ++++++ routers/common/middleware.go | 28 ++++++++++++++++++++++++++++ routers/web/web.go | 2 ++ 4 files changed, 58 insertions(+) diff --git a/modules/cache/cache.go b/modules/cache/cache.go index f7828e3cae2..49bb3bff9f8 100644 --- a/modules/cache/cache.go +++ b/modules/cache/cache.go @@ -9,11 +9,33 @@ import ( "time" "code.gitea.io/gitea/modules/setting" + "github.com/prometheus/client_golang/prometheus" + "github.com/prometheus/client_golang/prometheus/promauto" _ "gitea.com/go-chi/cache/memcache" //nolint:depguard // memcache plugin for cache, it is required for config "ADAPTER=memcache" ) var defaultCache StringCache +var hitCounter = promauto.NewCounter(prometheus.CounterOpts{ + Namespace: "gitea", + Help: "Cache hit count", + Subsystem: "cache", + Name: "hit", +}) +var missCounter = promauto.NewCounter(prometheus.CounterOpts{ + Namespace: "gitea", + Help: "Cache miss count", + Subsystem: "cache", + Name: "miss", +}) +var latencyHistogram = promauto.NewHistogram( + prometheus.HistogramOpts{ + Namespace: "gitea", + Help: "Cache latency", + Subsystem: "cache", + Name: "duration", + }, +) // Init start cache service func Init() error { diff --git a/modules/cache/string_cache.go b/modules/cache/string_cache.go index 4f659616f50..328cb6d2135 100644 --- a/modules/cache/string_cache.go +++ b/modules/cache/string_cache.go @@ -6,6 +6,7 @@ package cache import ( "errors" "strings" + "time" "code.gitea.io/gitea/modules/json" "code.gitea.io/gitea/modules/setting" @@ -63,10 +64,15 @@ func (sc *stringCache) Ping() error { } func (sc *stringCache) Get(key string) (string, bool) { + start := time.Now() v := sc.chiCache.Get(key) + elapsed := time.Since(start).Seconds() + latencyHistogram.Observe(elapsed) if v == nil { + missCounter.Add(1) return "", false } + hitCounter.Add(1) s, ok := v.(string) return s, ok } diff --git a/routers/common/middleware.go b/routers/common/middleware.go index 2ba02de8edc..739c92918aa 100644 --- a/routers/common/middleware.go +++ b/routers/common/middleware.go @@ -7,6 +7,7 @@ import ( "fmt" "net/http" "strings" + "time" "code.gitea.io/gitea/modules/cache" "code.gitea.io/gitea/modules/gtprof" @@ -19,8 +20,17 @@ import ( "gitea.com/go-chi/session" "github.com/chi-middleware/proxy" "github.com/go-chi/chi/v5" + "github.com/prometheus/client_golang/prometheus" + "github.com/prometheus/client_golang/prometheus/promauto" ) +var responseLatency = promauto.NewHistogramVec(prometheus.HistogramOpts{ + Namespace: "http", + Subsystem: "request", + Name: "duration_seconds", + Help: "Gitea response time", +}, []string{"route"}) + // ProtocolMiddlewares returns HTTP protocol related middlewares, and it provides a global panic recovery func ProtocolMiddlewares() (handlers []any) { // the order is important @@ -38,6 +48,9 @@ func ProtocolMiddlewares() (handlers []any) { if setting.IsAccessLogEnabled() { handlers = append(handlers, context.AccessLogger()) } + if setting.Metrics.Enabled { + handlers = append(handlers, RouteMetrics()) + } return handlers } @@ -107,6 +120,21 @@ func ForwardedHeadersHandler(limit int, trustedProxies []string) func(h http.Han return proxy.ForwardedHeaders(opt) } +func RouteMetrics() func(h http.Handler) http.Handler { + return func(next http.Handler) http.Handler { + return http.HandlerFunc(func(resp http.ResponseWriter, req *http.Request) { + start := time.Now() + next.ServeHTTP(resp, req) + elapsed := time.Since(start).Seconds() + route := "ui" + if strings.HasPrefix(req.URL.Path, "/api") { + route = "api" + } + responseLatency.WithLabelValues(route).Observe(elapsed) + }) + } +} + func Sessioner() func(next http.Handler) http.Handler { return session.Sessioner(session.Options{ Provider: setting.SessionConfig.Provider, diff --git a/routers/web/web.go b/routers/web/web.go index ef26dd9a743..02167b60d75 100644 --- a/routers/web/web.go +++ b/routers/web/web.go @@ -52,6 +52,7 @@ import ( "github.com/go-chi/cors" "github.com/klauspost/compress/gzhttp" "github.com/prometheus/client_golang/prometheus" + "github.com/prometheus/client_golang/prometheus/collectors" ) var GzipMinSize = 1400 // min size to compress for the body size of response @@ -258,6 +259,7 @@ func Routes() *web.Router { } if setting.Metrics.Enabled { + prometheus.MustRegister(collectors.NewProcessCollector(collectors.ProcessCollectorOpts{Namespace: "gitea"})) prometheus.MustRegister(metrics.NewCollector()) routes.Get("/metrics", append(mid, Metrics)...) }