metrics.go 2.3 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586
  1. package middleware
  2. import (
  3. "strconv"
  4. "time"
  5. "github.com/gin-gonic/gin"
  6. "github.com/prometheus/client_golang/prometheus"
  7. "github.com/prometheus/client_golang/prometheus/promauto"
  8. )
  9. var (
  10. // RequestsTotal counts the number of HTTP requests processed
  11. RequestsTotal = promauto.NewCounterVec(
  12. prometheus.CounterOpts{
  13. Name: "http_requests_total",
  14. Help: "Total number of HTTP requests",
  15. },
  16. []string{"method", "path", "status"},
  17. )
  18. // RequestDuration observes the HTTP request duration
  19. RequestDuration = promauto.NewHistogramVec(
  20. prometheus.HistogramOpts{
  21. Name: "http_request_duration_seconds",
  22. Help: "HTTP request duration in seconds",
  23. Buckets: prometheus.DefBuckets,
  24. },
  25. []string{"method", "path"},
  26. )
  27. // ResponseSize observes the HTTP response size
  28. ResponseSize = promauto.NewHistogramVec(
  29. prometheus.HistogramOpts{
  30. Name: "http_response_size_bytes",
  31. Help: "HTTP response size in bytes",
  32. Buckets: prometheus.ExponentialBuckets(100, 10, 8), // From 100B to 10GB
  33. },
  34. []string{"method", "path"},
  35. )
  36. )
  37. // Metrics is a middleware that collects Prometheus metrics for HTTP requests
  38. func Metrics(c *gin.Context) {
  39. start := time.Now()
  40. // Create a custom response writer to capture status code and response size
  41. mrw := &metricsResponseWriter{ResponseWriter: c.Writer}
  42. c.Writer = mrw
  43. // Process the request
  44. c.Next()
  45. // Record metrics
  46. duration := time.Since(start).Seconds()
  47. statusCode := strconv.Itoa(mrw.statusCode)
  48. method := c.Request.Method
  49. path := c.Request.URL.Path
  50. RequestsTotal.WithLabelValues(method, path, statusCode).Inc()
  51. RequestDuration.WithLabelValues(method, path).Observe(duration)
  52. ResponseSize.WithLabelValues(method, path).Observe(float64(mrw.responseSize))
  53. }
  54. // metricsResponseWriter is a custom ResponseWriter that captures status code and response size
  55. type metricsResponseWriter struct {
  56. gin.ResponseWriter
  57. statusCode int
  58. responseSize int
  59. }
  60. // WriteHeader captures the status code
  61. func (mrw *metricsResponseWriter) WriteHeader(code int) {
  62. mrw.statusCode = code
  63. mrw.ResponseWriter.WriteHeader(code)
  64. }
  65. // Write captures the response size
  66. func (mrw *metricsResponseWriter) Write(b []byte) (int, error) {
  67. n, err := mrw.ResponseWriter.Write(b)
  68. if err != nil {
  69. return n, err
  70. }
  71. mrw.responseSize += n
  72. return n, nil
  73. }