Skip to content

Commit 92d5c46

Browse files
committed
graphql: metrics for the GraphQL validation phas
1 parent 8ea2995 commit 92d5c46

File tree

2 files changed

+59
-1
lines changed

2 files changed

+59
-1
lines changed

graphql/src/execution/query.rs

+5
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ use graph::prelude::{
2121

2222
use crate::execution::ast as a;
2323
use crate::query::{ast as qast, ext::BlockConstraint};
24+
use crate::runner::ValidationMetrics;
2425
use crate::schema::ast::{self as sast};
2526
use crate::values::coercion;
2627
use crate::{execution::get_field, schema::api::ErrorPolicy};
@@ -149,10 +150,14 @@ impl Query {
149150
query: GraphDataQuery,
150151
max_complexity: Option<u64>,
151152
max_depth: u8,
153+
validation_phase: Arc<ValidationMetrics>,
152154
) -> Result<Arc<Self>, Vec<QueryExecutionError>> {
155+
let validation_phase_start = Instant::now();
153156
let validation_errors =
154157
validate(schema.document(), &query.document, &GRAPHQL_VALIDATION_PLAN);
155158

159+
validation_phase.observe(validation_phase_start.elapsed().as_nanos() as usize);
160+
156161
if !validation_errors.is_empty() {
157162
if !ENV_VARS.graphql.silent_graphql_validations {
158163
return Err(validation_errors

graphql/src/runner.rs

+54-1
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,52 @@ use graph::{
2020
prelude::QueryStore,
2121
};
2222

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+
2369
pub struct ResultSizeMetrics {
2470
histogram: Box<Histogram>,
2571
max_gauge: Box<Gauge>,
@@ -73,6 +119,7 @@ pub struct GraphQlRunner<S, SM> {
73119
subscription_manager: Arc<SM>,
74120
load_manager: Arc<LoadManager>,
75121
result_size: Arc<ResultSizeMetrics>,
122+
validation_phase: Arc<ValidationMetrics>,
76123
}
77124

78125
#[cfg(debug_assertions)]
@@ -95,13 +142,15 @@ where
95142
registry: Arc<dyn MetricsRegistry>,
96143
) -> Self {
97144
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));
99147
GraphQlRunner {
100148
logger,
101149
store,
102150
subscription_manager,
103151
load_manager,
104152
result_size,
153+
validation_phase,
105154
}
106155
}
107156

@@ -144,6 +193,7 @@ where
144193
max_first: Option<u32>,
145194
max_skip: Option<u32>,
146195
result_size: Arc<ResultSizeMetrics>,
196+
validation_phase: Arc<ValidationMetrics>,
147197
) -> Result<QueryResults, QueryResults> {
148198
// We need to use the same `QueryStore` for the entire query to ensure
149199
// we have a consistent view if the world, even when replicas, which
@@ -175,6 +225,7 @@ where
175225
query,
176226
max_complexity,
177227
max_depth,
228+
validation_phase,
178229
)?;
179230
self.load_manager
180231
.decide(
@@ -260,6 +311,7 @@ where
260311
max_first,
261312
max_skip,
262313
self.result_size.cheap_clone(),
314+
self.validation_phase.cheap_clone(),
263315
)
264316
.await
265317
.unwrap_or_else(|e| e)
@@ -281,6 +333,7 @@ where
281333
subscription.query,
282334
ENV_VARS.graphql.max_complexity,
283335
ENV_VARS.graphql.max_depth,
336+
self.validation_phase.cheap_clone(),
284337
)?;
285338

286339
if let Err(err) = self

0 commit comments

Comments
 (0)