1 package ginmetrics
2
3 import (
4 "fmt"
5 "strconv"
6 "time"
7
8 "github.com/gin-gonic/gin"
9 "github.com/prometheus/client_golang/prometheus/promhttp"
10
11 "github.com/penglongli/gin-metrics/bloom"
12 )
13
14 var (
15 metricRequestTotal = "gin_request_total"
16 metricRequestUVTotal = "gin_request_uv_total"
17 metricURIRequestTotal = "gin_uri_request_total"
18 metricRequestBody = "gin_request_body_total"
19 metricResponseBody = "gin_response_body_total"
20 metricRequestDuration = "gin_request_duration"
21 metricSlowRequest = "gin_slow_request_total"
22
23 bloomFilter *bloom.BloomFilter
24 )
25
26
27 func (m *Monitor) Use(r gin.IRoutes) {
28 m.initGinMetrics()
29
30 r.Use(m.monitorInterceptor)
31 r.GET(m.metricPath, func(ctx *gin.Context) {
32 promhttp.Handler().ServeHTTP(ctx.Writer, ctx.Request)
33 })
34 }
35
36
37
38
39 func (m *Monitor) UseWithoutExposingEndpoint(r gin.IRoutes) {
40 m.initGinMetrics()
41 r.Use(m.monitorInterceptor)
42 }
43
44
45
46
47 func (m *Monitor) Expose(r gin.IRoutes) {
48 r.GET(m.metricPath, func(ctx *gin.Context) {
49 promhttp.Handler().ServeHTTP(ctx.Writer, ctx.Request)
50 })
51 }
52
53
54 func (m *Monitor) initGinMetrics() {
55 bloomFilter = bloom.NewBloomFilter()
56
57 _ = monitor.AddMetric(&Metric{
58 Type: Counter,
59 Name: metricRequestTotal,
60 Description: "all the server received request num.",
61 Labels: nil,
62 })
63 _ = monitor.AddMetric(&Metric{
64 Type: Counter,
65 Name: metricRequestUVTotal,
66 Description: "all the server received ip num.",
67 Labels: nil,
68 })
69 _ = monitor.AddMetric(&Metric{
70 Type: Counter,
71 Name: metricURIRequestTotal,
72 Description: "all the server received request num with every uri.",
73 Labels: []string{"uri", "method", "code"},
74 })
75 _ = monitor.AddMetric(&Metric{
76 Type: Counter,
77 Name: metricRequestBody,
78 Description: "the server received request body size, unit byte",
79 Labels: nil,
80 })
81 _ = monitor.AddMetric(&Metric{
82 Type: Counter,
83 Name: metricResponseBody,
84 Description: "the server send response body size, unit byte",
85 Labels: nil,
86 })
87 _ = monitor.AddMetric(&Metric{
88 Type: Histogram,
89 Name: metricRequestDuration,
90 Description: "the time server took to handle the request.",
91 Labels: []string{"uri"},
92 Buckets: m.reqDuration,
93 })
94 _ = monitor.AddMetric(&Metric{
95 Type: Counter,
96 Name: metricSlowRequest,
97 Description: fmt.Sprintf("the server handled slow requests counter, t=%d.", m.slowTime),
98 Labels: []string{"uri", "method", "code"},
99 })
100 }
101
102
103 func (m *Monitor) monitorInterceptor(ctx *gin.Context) {
104 if ctx.Request.URL.Path == m.metricPath {
105 ctx.Next()
106 return
107 }
108 startTime := time.Now()
109
110
111 ctx.Next()
112
113
114 m.ginMetricHandle(ctx, startTime)
115 }
116
117 func (m *Monitor) ginMetricHandle(ctx *gin.Context, start time.Time) {
118 r := ctx.Request
119 w := ctx.Writer
120
121
122 _ = m.GetMetric(metricRequestTotal).Inc(nil)
123
124
125 if clientIP := ctx.ClientIP(); !bloomFilter.Contains(clientIP) {
126 bloomFilter.Add(clientIP)
127 _ = m.GetMetric(metricRequestUVTotal).Inc(nil)
128 }
129
130
131 _ = m.GetMetric(metricURIRequestTotal).Inc([]string{ctx.FullPath(), r.Method, strconv.Itoa(w.Status())})
132
133
134
135 if r.ContentLength >= 0 {
136 _ = m.GetMetric(metricRequestBody).Add(nil, float64(r.ContentLength))
137 }
138
139
140 latency := time.Since(start)
141 if int32(latency.Seconds()) > m.slowTime {
142 _ = m.GetMetric(metricSlowRequest).Inc([]string{ctx.FullPath(), r.Method, strconv.Itoa(w.Status())})
143 }
144
145
146 _ = m.GetMetric(metricRequestDuration).Observe([]string{ctx.FullPath()}, latency.Seconds())
147
148
149 if w.Size() > 0 {
150 _ = m.GetMetric(metricResponseBody).Add(nil, float64(w.Size()))
151 }
152 }
153
View as plain text