@@ -20,6 +20,52 @@ use graph::{
20
20
prelude:: QueryStore ,
21
21
} ;
22
22
23
+ pub struct ValidationMetrics {
24
+ histogram : Box < Histogram > ,
25
+ max_gauge : Box < Gauge > ,
26
+ }
27
+
28
+ impl ValidationMetrics {
29
+ fn new ( registry : Arc < dyn MetricsRegistry > ) -> Self {
30
+ // Divide the Histogram into exponentially sized buckets between 1k and 4G
31
+ let bins = ( 10 ..32 ) . map ( |n| 2u64 . pow ( n) as f64 ) . collect :: < Vec < _ > > ( ) ;
32
+ let histogram = registry
33
+ . new_histogram (
34
+ "graphql_validation_time_ns" ,
35
+ "the time of the GraphQL validation phase (in nanoseconds)" ,
36
+ bins,
37
+ )
38
+ . unwrap ( ) ;
39
+
40
+ let max_gauge = registry
41
+ . new_gauge (
42
+ "graphql_validation_max_time_ns" ,
43
+ "the maximum time of the GraphQL validation phase (in nanoseconds)" ,
44
+ HashMap :: new ( ) ,
45
+ )
46
+ . unwrap ( ) ;
47
+
48
+ Self {
49
+ histogram,
50
+ max_gauge,
51
+ }
52
+ }
53
+
54
+ // Tests need to construct one of these, but normal code doesn't
55
+ #[ cfg( debug_assertions) ]
56
+ pub fn make ( registry : Arc < dyn MetricsRegistry > ) -> Self {
57
+ Self :: new ( registry)
58
+ }
59
+
60
+ pub fn observe ( & self , size : usize ) {
61
+ let size = size as f64 ;
62
+ self . histogram . observe ( size) ;
63
+ if self . max_gauge . get ( ) < size {
64
+ self . max_gauge . set ( size) ;
65
+ }
66
+ }
67
+ }
68
+
23
69
pub struct ResultSizeMetrics {
24
70
histogram : Box < Histogram > ,
25
71
max_gauge : Box < Gauge > ,
@@ -73,6 +119,7 @@ pub struct GraphQlRunner<S, SM> {
73
119
subscription_manager : Arc < SM > ,
74
120
load_manager : Arc < LoadManager > ,
75
121
result_size : Arc < ResultSizeMetrics > ,
122
+ validation_phase : Arc < ValidationMetrics > ,
76
123
}
77
124
78
125
#[ cfg( debug_assertions) ]
@@ -95,13 +142,15 @@ where
95
142
registry : Arc < dyn MetricsRegistry > ,
96
143
) -> Self {
97
144
let logger = logger. new ( o ! ( "component" => "GraphQlRunner" ) ) ;
98
- let result_size = Arc :: new ( ResultSizeMetrics :: new ( registry) ) ;
145
+ let result_size = Arc :: new ( ResultSizeMetrics :: new ( registry. cheap_clone ( ) ) ) ;
146
+ let validation_phase = Arc :: new ( ValidationMetrics :: new ( registry) ) ;
99
147
GraphQlRunner {
100
148
logger,
101
149
store,
102
150
subscription_manager,
103
151
load_manager,
104
152
result_size,
153
+ validation_phase,
105
154
}
106
155
}
107
156
@@ -144,6 +193,7 @@ where
144
193
max_first : Option < u32 > ,
145
194
max_skip : Option < u32 > ,
146
195
result_size : Arc < ResultSizeMetrics > ,
196
+ validation_phase : Arc < ValidationMetrics > ,
147
197
) -> Result < QueryResults , QueryResults > {
148
198
// We need to use the same `QueryStore` for the entire query to ensure
149
199
// we have a consistent view if the world, even when replicas, which
@@ -175,6 +225,7 @@ where
175
225
query,
176
226
max_complexity,
177
227
max_depth,
228
+ validation_phase,
178
229
) ?;
179
230
self . load_manager
180
231
. decide (
@@ -260,6 +311,7 @@ where
260
311
max_first,
261
312
max_skip,
262
313
self . result_size . cheap_clone ( ) ,
314
+ self . validation_phase . cheap_clone ( ) ,
263
315
)
264
316
. await
265
317
. unwrap_or_else ( |e| e)
@@ -281,6 +333,7 @@ where
281
333
subscription. query ,
282
334
ENV_VARS . graphql . max_complexity ,
283
335
ENV_VARS . graphql . max_depth ,
336
+ self . validation_phase . cheap_clone ( ) ,
284
337
) ?;
285
338
286
339
if let Err ( err) = self
0 commit comments