@@ -64,8 +64,8 @@ type gatewayHandler struct {
64
64
config GatewayConfig
65
65
api coreiface.CoreAPI
66
66
67
- // TODO: add metrics for non-unixfs responses (block, car)
68
- unixfsGetMetric * prometheus.SummaryVec
67
+ unixfsGetMetric * prometheus. SummaryVec
68
+ firstBlockGetMetric * prometheus.SummaryVec
69
69
}
70
70
71
71
// StatusResponseWriter enables us to override HTTP Status Code passed to
@@ -90,11 +90,12 @@ func (sw *statusResponseWriter) WriteHeader(code int) {
90
90
91
91
func newGatewayHandler (c GatewayConfig , api coreiface.CoreAPI ) * gatewayHandler {
92
92
unixfsGetMetric := prometheus .NewSummaryVec (
93
+ // TODO: deprecated, use first_block_get_latency_seconds instead
93
94
prometheus.SummaryOpts {
94
95
Namespace : "ipfs" ,
95
96
Subsystem : "http" ,
96
97
Name : "unixfs_get_latency_seconds" ,
97
- Help : "The time till the first block is received when 'getting' a file from the gateway." ,
98
+ Help : "The time till the first block is received when 'getting' a unixfs file from the gateway." ,
98
99
},
99
100
[]string {"gateway" },
100
101
)
@@ -106,10 +107,28 @@ func newGatewayHandler(c GatewayConfig, api coreiface.CoreAPI) *gatewayHandler {
106
107
}
107
108
}
108
109
110
+ firstBlockGetMetric := prometheus .NewSummaryVec (
111
+ prometheus.SummaryOpts {
112
+ Namespace : "ipfs" ,
113
+ Subsystem : "http" ,
114
+ Name : "first_block_get_latency_seconds" ,
115
+ Help : "The time till the first block is successfully received when reading data from the gateway." ,
116
+ },
117
+ []string {"gateway" },
118
+ )
119
+ if err := prometheus .Register (firstBlockGetMetric ); err != nil {
120
+ if are , ok := err .(prometheus.AlreadyRegisteredError ); ok {
121
+ firstBlockGetMetric = are .ExistingCollector .(* prometheus.SummaryVec )
122
+ } else {
123
+ log .Errorf ("failed to register firstBlockGetMetric: %v" , err )
124
+ }
125
+ }
126
+
109
127
i := & gatewayHandler {
110
- config : c ,
111
- api : api ,
112
- unixfsGetMetric : unixfsGetMetric ,
128
+ config : c ,
129
+ api : api ,
130
+ unixfsGetMetric : unixfsGetMetric ,
131
+ firstBlockGetMetric : firstBlockGetMetric ,
113
132
}
114
133
return i
115
134
}
@@ -305,6 +324,15 @@ func (i *gatewayHandler) getOrHeadHandler(w http.ResponseWriter, r *http.Request
305
324
return
306
325
}
307
326
327
+ // Update the global metric of the time it takes to read the final root block of the requested resource
328
+ // NOTE: this needs to happen before we go into content-type specific code paths
329
+ _ , err = i .api .Block ().Get (r .Context (), resolvedPath )
330
+ if err != nil {
331
+ webError (w , "ipfs block get " + resolvedPath .Cid ().String (), err , http .StatusServiceUnavailable )
332
+ return
333
+ }
334
+ i .firstBlockGetMetric .WithLabelValues (parsedPath .Namespace ()).Observe (time .Since (begin ).Seconds ())
335
+
308
336
// HTTP Headers
309
337
i .addUserHeaders (w ) // ok, _now_ write user's headers.
310
338
w .Header ().Set ("X-Ipfs-Path" , urlPath )
@@ -348,7 +376,6 @@ func (i *gatewayHandler) getOrHeadHandler(w http.ResponseWriter, r *http.Request
348
376
webError (w , "ipfs cat " + escapedURLPath , err , http .StatusNotFound )
349
377
return
350
378
}
351
- // TODO: do we want to reuse unixfsGetMetric for block/car, or should we have separate ones?
352
379
i .unixfsGetMetric .WithLabelValues (parsedPath .Namespace ()).Observe (time .Since (begin ).Seconds ())
353
380
defer dr .Close ()
354
381
0 commit comments