@@ -23,6 +23,7 @@ package fiberprometheus
23
23
24
24
import (
25
25
"strconv"
26
+ "strings"
26
27
"time"
27
28
28
29
"github.com/gofiber/fiber/v2"
@@ -39,10 +40,8 @@ type FiberPrometheus struct {
39
40
requestsTotal * prometheus.CounterVec
40
41
requestDuration * prometheus.HistogramVec
41
42
requestInFlight * prometheus.GaugeVec
42
- cacheHeaderKey string
43
- cacheCounter * prometheus.CounterVec
44
43
defaultURL string
45
- skipPaths map [string ]struct {}
44
+ skipPaths map [string ]bool
46
45
}
47
46
48
47
func create (registry prometheus.Registerer , serviceName , namespace , subsystem string , labels map [string ]string ) * FiberPrometheus {
@@ -67,15 +66,6 @@ func create(registry prometheus.Registerer, serviceName, namespace, subsystem st
67
66
[]string {"status_code" , "method" , "path" },
68
67
)
69
68
70
- cacheCounter := promauto .With (registry ).NewCounterVec (
71
- prometheus.CounterOpts {
72
- Name : prometheus .BuildFQName (namespace , subsystem , "cache_results" ),
73
- Help : "Counts all cache hits by status code, method, and path" ,
74
- ConstLabels : constLabels ,
75
- },
76
- []string {"status_code" , "method" , "path" , "cache_result" },
77
- )
78
-
79
69
histogram := promauto .With (registry ).NewHistogramVec (prometheus.HistogramOpts {
80
70
Name : prometheus .BuildFQName (namespace , subsystem , "request_duration_seconds" ),
81
71
Help : "Duration of all HTTP requests by status code, method and path." ,
@@ -115,6 +105,7 @@ func create(registry prometheus.Registerer, serviceName, namespace, subsystem st
115
105
15.0 ,
116
106
20.0 ,
117
107
30.0 ,
108
+ 60.0 , // 1m
118
109
},
119
110
},
120
111
[]string {"status_code" , "method" , "path" },
@@ -138,18 +129,10 @@ func create(registry prometheus.Registerer, serviceName, namespace, subsystem st
138
129
requestsTotal : counter ,
139
130
requestDuration : histogram ,
140
131
requestInFlight : gauge ,
141
- cacheHeaderKey : "X-Cache" ,
142
- cacheCounter : cacheCounter ,
143
132
defaultURL : "/metrics" ,
144
133
}
145
134
}
146
135
147
- // CustomCacheKey allows to set a custom header key for caching
148
- // By default it is set to "X-Cache", the fiber default
149
- func (ps * FiberPrometheus ) CustomCacheKey (cacheHeaderKey string ) {
150
- ps .cacheHeaderKey = cacheHeaderKey
151
- }
152
-
153
136
// New creates a new instance of FiberPrometheus middleware
154
137
// serviceName is available as a const label
155
138
func New (serviceName string ) * FiberPrometheus {
@@ -191,6 +174,11 @@ func NewWithRegistry(registry prometheus.Registerer, serviceName, namespace, sub
191
174
return create (registry , serviceName , namespace , subsystem , labels )
192
175
}
193
176
177
+ // NewWithDefaultRegistry creates a new instance of FiberPrometheus middleware using the default prometheus registry
178
+ func NewWithDefaultRegistry (serviceName string ) * FiberPrometheus {
179
+ return create (prometheus .DefaultRegisterer , serviceName , "http" , "" , nil )
180
+ }
181
+
194
182
// RegisterAt will register the prometheus handler at a given URL
195
183
func (ps * FiberPrometheus ) RegisterAt (app fiber.Router , url string , handlers ... fiber.Handler ) {
196
184
ps .defaultURL = url
@@ -201,61 +189,77 @@ func (ps *FiberPrometheus) RegisterAt(app fiber.Router, url string, handlers ...
201
189
202
190
// SetSkipPaths allows to set the paths that should be skipped from the metrics
203
191
func (ps * FiberPrometheus ) SetSkipPaths (paths []string ) {
204
- ps .skipPaths = make (map [string ]struct {})
192
+ if ps .skipPaths == nil {
193
+ ps .skipPaths = make (map [string ]bool )
194
+ }
205
195
for _ , path := range paths {
206
- ps .skipPaths [path ] = struct {}{}
196
+ ps .skipPaths [path ] = true
207
197
}
208
198
}
209
199
210
200
// Middleware is the actual default middleware implementation
211
201
func (ps * FiberPrometheus ) Middleware (ctx * fiber.Ctx ) error {
212
- path := string (ctx .Request ().RequestURI ())
213
-
214
- if path == ps .defaultURL {
215
- return ctx .Next ()
216
- }
202
+ // Retrieve the request method
203
+ method := utils .CopyString (ctx .Method ())
217
204
218
- // Check if the path is in the map of skipped paths
219
- if _ , exists := ps .skipPaths [path ]; exists {
220
- return ctx .Next () // Skip metrics collection
221
- }
222
-
223
- // Start metrics timer
224
- start := time .Now ()
225
- method := ctx .Route ().Method
205
+ // Increment the in-flight gauge
226
206
ps .requestInFlight .WithLabelValues (method ).Inc ()
227
207
defer func () {
228
208
ps .requestInFlight .WithLabelValues (method ).Dec ()
229
209
}()
230
210
211
+ // Start metrics timer
212
+ start := time .Now ()
213
+
214
+ // Continue stack
231
215
err := ctx .Next ()
232
- // initialize with default error code
233
- // https://docs.gofiber.io/guide/error-handling
216
+
217
+ // Get the route path
218
+ routePath := utils .CopyString (ctx .Route ().Path )
219
+
220
+ // If the route path is empty, use the current path
221
+ if routePath == "/" {
222
+ routePath = utils .CopyString (ctx .Path ())
223
+ }
224
+
225
+ // Normalize the path
226
+ if routePath != "" && routePath != "/" {
227
+ routePath = normalizePath (routePath )
228
+ }
229
+
230
+ // Check if the normalized path should be skipped
231
+ if ps .skipPaths [routePath ] {
232
+ return nil
233
+ }
234
+
235
+ // Determine status code from stack
234
236
status := fiber .StatusInternalServerError
235
237
if err != nil {
236
238
if e , ok := err .(* fiber.Error ); ok {
237
- // Get correct error code from fiber.Error type
238
239
status = e .Code
239
240
}
240
241
} else {
241
242
status = ctx .Response ().StatusCode ()
242
243
}
243
244
244
- // Get status as string
245
+ // Convert status code to string
245
246
statusCode := strconv .Itoa (status )
246
247
247
- // Update total requests counter
248
- ps .requestsTotal .WithLabelValues (statusCode , method , path ).Inc ()
249
-
250
- // Update the cache counter
251
- cacheResult := utils .CopyString (ctx .GetRespHeader (ps .cacheHeaderKey , "" ))
252
- if cacheResult != "" {
253
- ps .cacheCounter .WithLabelValues (statusCode , method , path , cacheResult ).Inc ()
254
- }
248
+ // Update metrics
249
+ ps .requestsTotal .WithLabelValues (statusCode , method , routePath ).Inc ()
255
250
256
- // Update the request duration histogram
251
+ // Observe the Request Duration
257
252
elapsed := float64 (time .Since (start ).Nanoseconds ()) / 1e9
258
- ps .requestDuration .WithLabelValues (statusCode , method , path ).Observe (elapsed )
253
+ ps .requestDuration .WithLabelValues (statusCode , method , routePath ).Observe (elapsed )
259
254
260
255
return err
261
256
}
257
+
258
+ // normalizePath will remove the trailing slash from the route path
259
+ func normalizePath (routePath string ) string {
260
+ normalized := strings .TrimRight (routePath , "/" )
261
+ if normalized == "" {
262
+ return "/"
263
+ }
264
+ return normalized
265
+ }
0 commit comments