-
Notifications
You must be signed in to change notification settings - Fork 0
/
prometheus.go
110 lines (91 loc) · 2.76 KB
/
prometheus.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
package main
import (
"net/http"
"time"
"github.com/prometheus/client_golang/prometheus"
"github.com/prometheus/client_golang/prometheus/promauto"
)
var (
// Total requests counter
totalRequests = promauto.NewCounterVec(
prometheus.CounterOpts{
Name: "http_requests_total",
Help: "Total number of HTTP requests.",
},
[]string{"method", "endpoint", "status"},
)
// Request duration histogram
requestDuration = promauto.NewHistogramVec(
prometheus.HistogramOpts{
Name: "http_request_duration_seconds",
Help: "HTTP request duration in seconds.",
Buckets: prometheus.DefBuckets,
},
[]string{"method", "endpoint"},
)
// Response size histogram
responseSize = promauto.NewHistogramVec(
prometheus.HistogramOpts{
Name: "http_response_size_bytes",
Help: "HTTP response size in bytes.",
Buckets: []float64{100, 500, 1000, 5000, 10000},
},
[]string{"method", "endpoint"},
)
// Active requests gauge
activeRequests = promauto.NewGauge(prometheus.GaugeOpts{
Name: "http_active_requests",
Help: "Number of active HTTP requests.",
})
// Failed requests counter
failedRequests = promauto.NewCounterVec(
prometheus.CounterOpts{
Name: "http_requests_failed_total",
Help: "Total number of failed HTTP requests.",
},
[]string{"method", "endpoint", "error"},
)
)
// PrometheusMiddleware implements mux.MiddlewareFunc
func PrometheusMiddleware(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
start := time.Now()
activeRequests.Inc()
// Create response writer wrapper to capture status code
rw := NewResponseWriter(w)
next.ServeHTTP(rw, r)
// Decrease active requests counter
activeRequests.Dec()
// Record metrics
duration := time.Since(start).Seconds()
status := rw.statusCode
// Update request total
totalRequests.WithLabelValues(r.Method, r.URL.Path, string(rune(status))).Inc()
// Update duration histogram
requestDuration.WithLabelValues(r.Method, r.URL.Path).Observe(duration)
// Update response size
responseSize.WithLabelValues(r.Method, r.URL.Path).Observe(float64(rw.size))
// Record failed requests (status >= 400)
if status >= 400 {
failedRequests.WithLabelValues(r.Method, r.URL.Path, string(rune(status))).Inc()
}
})
}
// ResponseWriter wrapper to capture status code and response size
type ResponseWriter struct {
http.ResponseWriter
statusCode int
size int
}
func NewResponseWriter(w http.ResponseWriter) *ResponseWriter {
return &ResponseWriter{ResponseWriter: w}
}
func (rw *ResponseWriter) WriteHeader(code int) {
rw.statusCode = code
rw.ResponseWriter.WriteHeader(code)
}
func (rw *ResponseWriter) Write(b []byte) (int, error) {
size, err := rw.ResponseWriter.Write(b)
rw.size += size
return size, err
}