// internal/metrics/prometheus.go package metrics import ( "strconv" "time" "github.com/gin-gonic/gin" "github.com/prometheus/client_golang/prometheus" "github.com/prometheus/client_golang/prometheus/promauto" ) var ( // HttpRequestsTotal counts the total number of API requests HttpRequestsTotal = promauto.NewCounterVec( prometheus.CounterOpts{ Name: "musicapp_http_requests_total", Help: "Total number of HTTP requests", }, []string{"method", "path", "status"}, ) // HttpRequestDuration measures how long your API endpoints take to respond HttpRequestDuration = promauto.NewHistogramVec( prometheus.HistogramOpts{ Name: "musicapp_http_request_duration_seconds", Help: "Duration of HTTP requests in seconds", Buckets: prometheus.DefBuckets, }, []string{"method", "path"}, ) ) func PrometheusMiddleware() gin.HandlerFunc { return func(c *gin.Context) { start := time.Now() c.Next() duration := time.Since(start).Seconds() status := strconv.Itoa(c.Writer.Status()) method := c.Request.Method // If we used URL.Path, "/tracks/123" and "/tracks/456" would create thousands // of different metrics and crash Prometheus. FullPath() gives us "/tracks/:id". path := c.FullPath() if path == "" { path = "unknown" } // Don't track the /metrics endpoint itself if path != "/metrics" { HttpRequestsTotal.WithLabelValues(method, path, status).Inc() HttpRequestDuration.WithLabelValues(method, path).Observe(duration) } } }