Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add graphql query complexity histogram metric #2349

Merged
merged 2 commits into from
Oct 14, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,9 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
### Added
- [2335](https://github.com/FuelLabs/fuel-core/pull/2335): Added CLI arguments for configuring GraphQL query costs.

### Added
- [2347](https://github.com/FuelLabs/fuel-core/pull/2347): Add GraphQL complexity histogram

## [Version 0.39.0]

### Added
Expand Down
13 changes: 13 additions & 0 deletions crates/fuel-core/src/graphql_api/metrics_extension.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,14 @@ use async_graphql::{
NextParseQuery,
NextRequest,
NextResolve,
NextValidation,
ResolveInfo,
},
parser::types::ExecutableDocument,
Response,
ServerError,
ServerResult,
ValidationResult,
Value,
Variables,
};
Expand Down Expand Up @@ -118,4 +121,14 @@ impl Extension for MetricsExtInner {

res
}

async fn validation(
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It doesn't look like this gets used by anything in this PR... where is it used?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not very familiar with async-graphql but the trait seems to have a default implementation and I override it. For me this is call by async-graphql itself when triggering validation step of the query

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It is how async-graphql library works. It has a bunch of default methods that are called during the processing of the request. Valuation is one of the phases there.
image

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah. I missed it was a trait impl. That makes sense now.

&self,
ctx: &ExtensionContext<'_>,
next: NextValidation<'_>,
) -> Result<ValidationResult, Vec<ServerError>> {
let result = next.run(ctx).await?;
graphql_metrics().graphql_complexity_observe(result.complexity as f64);
Ok(result)
}
}
29 changes: 29 additions & 0 deletions crates/metrics/src/graphql_metrics.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,16 +22,23 @@ pub struct GraphqlMetrics {
// using gauges in case blocks are rolled back for any reason
pub total_txs_count: Gauge,
requests: Family<Label, Histogram>,
queries_complexity: Histogram,
}

impl GraphqlMetrics {
fn new() -> Self {
let tx_count_gauge = Gauge::default();
let queries_complexity = Histogram::new(buckets_complexity());
let requests = Family::<Label, Histogram>::new_with_constructor(|| {
Histogram::new(timing_buckets().iter().cloned())
});
let mut registry = global_registry().registry.lock();
registry.register("graphql_request_duration_seconds", "", requests.clone());
registry.register(
"graphql_query_complexity",
"The complexity of all queries received",
queries_complexity.clone(),
);

registry.register(
"importer_tx_count",
Expand All @@ -41,6 +48,7 @@ impl GraphqlMetrics {

Self {
total_txs_count: tx_count_gauge,
queries_complexity,
requests,
}
}
Expand All @@ -51,9 +59,30 @@ impl GraphqlMetrics {
});
histogram.observe(time);
}

pub fn graphql_complexity_observe(&self, complexity: f64) {
self.queries_complexity.observe(complexity);
}
}

static GRAPHQL_METRICS: OnceLock<GraphqlMetrics> = OnceLock::new();
pub fn graphql_metrics() -> &'static GraphqlMetrics {
GRAPHQL_METRICS.get_or_init(GraphqlMetrics::new)
}

fn buckets_complexity() -> impl Iterator<Item = f64> {
[
1_000.0,
5_000.0,
10_000.0,
20_000.0,
50_000.0,
100_000.0,
250_000.0,
500_000.0,
1_000_000.0,
5_000_000.0,
10_000_000.0,
]
.into_iter()
}
Loading