package middleware import ( "strconv" "time" "github.com/gin-gonic/gin" "github.com/prometheus/client_golang/prometheus" "github.com/prometheus/client_golang/prometheus/promauto" ) var ( // RequestsTotal counts the number of HTTP requests processed RequestsTotal = promauto.NewCounterVec( prometheus.CounterOpts{ Name: "http_requests_total", Help: "Total number of HTTP requests", }, []string{"method", "path", "status"}, ) // RequestDuration observes the HTTP request duration RequestDuration = promauto.NewHistogramVec( prometheus.HistogramOpts{ Name: "http_request_duration_seconds", Help: "HTTP request duration in seconds", Buckets: prometheus.DefBuckets, }, []string{"method", "path"}, ) // ResponseSize observes the HTTP response size ResponseSize = promauto.NewHistogramVec( prometheus.HistogramOpts{ Name: "http_response_size_bytes", Help: "HTTP response size in bytes", Buckets: prometheus.ExponentialBuckets(100, 10, 8), // From 100B to 10GB }, []string{"method", "path"}, ) ) // Metrics is a middleware that collects Prometheus metrics for HTTP requests func Metrics(c *gin.Context) { start := time.Now() // Create a custom response writer to capture status code and response size mrw := &metricsResponseWriter{ResponseWriter: c.Writer} c.Writer = mrw // Process the request c.Next() // Record metrics duration := time.Since(start).Seconds() statusCode := strconv.Itoa(mrw.statusCode) method := c.Request.Method path := c.Request.URL.Path RequestsTotal.WithLabelValues(method, path, statusCode).Inc() RequestDuration.WithLabelValues(method, path).Observe(duration) ResponseSize.WithLabelValues(method, path).Observe(float64(mrw.responseSize)) } // metricsResponseWriter is a custom ResponseWriter that captures status code and response size type metricsResponseWriter struct { gin.ResponseWriter statusCode int responseSize int } // WriteHeader captures the status code func (mrw *metricsResponseWriter) WriteHeader(code int) { mrw.statusCode = code mrw.ResponseWriter.WriteHeader(code) } // Write captures the response size func (mrw *metricsResponseWriter) Write(b []byte) (int, error) { n, err := mrw.ResponseWriter.Write(b) if err != nil { return n, err } mrw.responseSize += n return n, nil }