Skip to content

Commit 998f464

Browse files
authored
refactor: remove slow query metric and expose query buckets (#1799)
1 parent 7a71c37 commit 998f464

2 files changed

Lines changed: 5 additions & 182 deletions

File tree

‎src/handlers/http/query.rs‎

Lines changed: 3 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -46,9 +46,7 @@ use tokio::task::JoinSet;
4646
use tracing::{error, warn};
4747

4848
use crate::event::{DEFAULT_TIMESTAMP_KEY, commit_schema};
49-
use crate::metrics::{
50-
QUERY_EXECUTE_TIME, QueryType, increment_query_calls_by_date, record_query_metrics,
51-
};
49+
use crate::metrics::{QUERY_EXECUTE_TIME, increment_query_calls_by_date};
5250
use crate::parseable::{DEFAULT_TENANT, PARSEABLE, StreamNotFound};
5351
use crate::query::error::ExecuteError;
5452
use crate::query::resolve_stream_names;
@@ -160,8 +158,6 @@ pub async fn query(req: HttpRequest, query_request: Query) -> Result<HttpRespons
160158
let mut session_state = QUERY_SESSION.get_ctx().state();
161159
let time_range =
162160
TimeRange::parse_human_time(&query_request.start_time, &query_request.end_time)?;
163-
let query_range_seconds =
164-
(time_range.end - time_range.start).num_milliseconds() as f64 / 1_000.0;
165161
let tables = resolve_stream_names(&query_request.query)?;
166162
// check or load streams in memory
167163
create_streams_for_distributed(tables.clone(), &get_tenant_id_from_request(&req)).await?;
@@ -194,29 +190,13 @@ pub async fn query(req: HttpRequest, query_request: Query) -> Result<HttpRespons
194190
let table = tables
195191
.first()
196192
.ok_or_else(|| QueryError::MalformedQuery("No table name found in query"))?;
197-
return handle_count_query(
198-
&query_request,
199-
table,
200-
column_name,
201-
time,
202-
query_range_seconds,
203-
&tenant_id,
204-
)
205-
.await;
193+
return handle_count_query(&query_request, table, column_name, time, &tenant_id).await;
206194
}
207195

208196
// if the query request has streaming = false (default)
209197
// we use datafusion's `execute` method to get the records
210198
if !query_request.streaming {
211-
return handle_non_streaming_query(
212-
query,
213-
tables,
214-
&query_request,
215-
time,
216-
query_range_seconds,
217-
&tenant_id,
218-
)
219-
.await;
199+
return handle_non_streaming_query(query, tables, &query_request, time, &tenant_id).await;
220200
}
221201

222202
// if the query request has streaming = true
@@ -243,7 +223,6 @@ async fn handle_count_query(
243223
table_name: &str,
244224
column_name: &str,
245225
time: Instant,
246-
query_range_seconds: f64,
247226
tenant_id: &Option<String>,
248227
) -> Result<HttpResponse, QueryError> {
249228
let counts_req = CountsRequest {
@@ -270,7 +249,6 @@ async fn handle_count_query(
270249
QUERY_EXECUTE_TIME
271250
.with_label_values(&[table_name, tenant_id.as_deref().unwrap_or(DEFAULT_TENANT)])
272251
.observe(time);
273-
record_query_metrics(time, query_range_seconds, QueryType::Sql);
274252

275253
Ok(HttpResponse::Ok()
276254
.insert_header((TIME_ELAPSED_HEADER, total_time.as_str()))
@@ -296,7 +274,6 @@ async fn handle_non_streaming_query(
296274
table_name: Vec<String>,
297275
query_request: &Query,
298276
time: Instant,
299-
query_range_seconds: f64,
300277
tenant_id: &Option<String>,
301278
) -> Result<HttpResponse, QueryError> {
302279
let first_table_name = table_name[0].clone();
@@ -318,7 +295,6 @@ async fn handle_non_streaming_query(
318295
tenant_id.as_deref().unwrap_or(DEFAULT_TENANT),
319296
])
320297
.observe(time);
321-
record_query_metrics(time, query_range_seconds, QueryType::Sql);
322298
let response = QueryResponse {
323299
records,
324300
fields,

‎src/metrics/mod.rs‎

Lines changed: 2 additions & 155 deletions
Original file line numberDiff line numberDiff line change
@@ -17,10 +17,7 @@
1717
*/
1818

1919
pub mod prom_utils;
20-
use std::{
21-
path::Path,
22-
sync::{Mutex, OnceLock},
23-
};
20+
use std::{path::Path, sync::OnceLock};
2421

2522
use crate::{
2623
handlers::{TelemetryType, http::metrics_path},
@@ -42,145 +39,10 @@ const SYNC_TASK_DURATION_BUCKETS: &[f64] = &[
4239
15.0, 30.0, 45.0, 60.0, 90.0, 120.0, 150.0, 180.0, 300.0, 600.0,
4340
];
4441

45-
const QUERY_EXECUTE_TIME_BUCKETS: &[f64] = &[
42+
pub const QUERY_EXECUTE_TIME_BUCKETS: &[f64] = &[
4643
0.1, 0.2, 0.5, 1.0, 5.0, 15.0, 30.0, 45.0, 60.0, 90.0, 120.0, 150.0, 180.0,
4744
];
4845

49-
#[derive(Debug, PartialEq)]
50-
pub enum QueryType {
51-
Sql,
52-
Promql,
53-
}
54-
55-
impl QueryType {
56-
fn as_label(&self) -> &'static str {
57-
match self {
58-
Self::Sql => "SQL",
59-
Self::Promql => "PromQL",
60-
}
61-
}
62-
}
63-
64-
#[derive(Debug, PartialEq)]
65-
struct QueryMetricsSnapshot {
66-
duration_seconds: f64,
67-
time_range_seconds: f64,
68-
query_type: QueryType,
69-
}
70-
71-
#[derive(Default)]
72-
struct QueryMetricsAccumulator {
73-
slowest_query: Mutex<Option<QueryMetricsSnapshot>>,
74-
}
75-
76-
impl QueryMetricsAccumulator {
77-
fn record(&self, duration_seconds: f64, time_range_seconds: f64, query_type: QueryType) {
78-
let mut slowest_query = self
79-
.slowest_query
80-
.lock()
81-
.expect("query metrics window lock should not be poisoned");
82-
83-
if slowest_query
84-
.as_ref()
85-
.is_none_or(|query| duration_seconds > query.duration_seconds)
86-
{
87-
*slowest_query = Some(QueryMetricsSnapshot {
88-
duration_seconds,
89-
time_range_seconds,
90-
query_type,
91-
});
92-
}
93-
}
94-
95-
fn take_and_reset(&self) -> Option<QueryMetricsSnapshot> {
96-
let mut slowest_query = self
97-
.slowest_query
98-
.lock()
99-
.expect("query metrics window lock should not be poisoned");
100-
slowest_query.take()
101-
}
102-
}
103-
104-
static QUERY_METRICS_ACCUMULATOR: Lazy<QueryMetricsAccumulator> =
105-
Lazy::new(QueryMetricsAccumulator::default);
106-
107-
pub fn record_query_metrics(duration_seconds: f64, time_range_seconds: f64, query_type: QueryType) {
108-
QUERY_METRICS_ACCUMULATOR.record(duration_seconds, time_range_seconds, query_type);
109-
}
110-
111-
pub fn refresh_query_metrics() {
112-
let snapshot = QUERY_METRICS_ACCUMULATOR.take_and_reset();
113-
SLOWEST_QUERY_DURATION_SECONDS.reset();
114-
115-
if let Some(snapshot) = snapshot {
116-
SLOWEST_QUERY_DURATION_SECONDS
117-
.with_label_values(&[
118-
&snapshot.time_range_seconds.to_string(),
119-
snapshot.query_type.as_label(),
120-
])
121-
.set(snapshot.duration_seconds);
122-
}
123-
}
124-
125-
#[cfg(test)]
126-
mod query_metrics_tests {
127-
use prometheus::core::Collector;
128-
129-
use super::{
130-
METRICS_NAMESPACE, METRICS_REGISTRY, QueryMetricsAccumulator, QueryMetricsSnapshot,
131-
QueryType, SLOWEST_QUERY_DURATION_SECONDS, record_query_metrics, refresh_query_metrics,
132-
};
133-
134-
#[test]
135-
fn tracks_slowest_query_and_resets_after_snapshot() {
136-
let accumulator = QueryMetricsAccumulator::default();
137-
138-
accumulator.record(20.0, 600.0, QueryType::Sql);
139-
accumulator.record(70.0, 7_200.0, QueryType::Promql);
140-
accumulator.record(65.0, 300.0, QueryType::Sql);
141-
142-
assert_eq!(
143-
accumulator.take_and_reset(),
144-
Some(QueryMetricsSnapshot {
145-
duration_seconds: 70.0,
146-
time_range_seconds: 7_200.0,
147-
query_type: QueryType::Promql,
148-
})
149-
);
150-
assert_eq!(accumulator.take_and_reset(), None);
151-
}
152-
153-
#[test]
154-
fn refreshes_gauges_and_clears_previous_window() {
155-
record_query_metrics(20.0, 600.0, QueryType::Sql);
156-
record_query_metrics(70.0, 7_200.0, QueryType::Promql);
157-
refresh_query_metrics();
158-
159-
assert_eq!(
160-
SLOWEST_QUERY_DURATION_SECONDS
161-
.with_label_values(&["7200", "PromQL"])
162-
.get(),
163-
70.0
164-
);
165-
let metric_name = format!("{METRICS_NAMESPACE}_slowest_query_duration_seconds");
166-
assert!(
167-
METRICS_REGISTRY
168-
.gather()
169-
.iter()
170-
.any(|family| family.get_name() == metric_name)
171-
);
172-
173-
refresh_query_metrics();
174-
175-
assert!(
176-
SLOWEST_QUERY_DURATION_SECONDS
177-
.collect()
178-
.iter()
179-
.all(|family| family.get_metric().is_empty())
180-
);
181-
}
182-
}
183-
18446
pub static METRICS_REGISTRY: Lazy<Registry> = Lazy::new(|| {
18547
let registry = Registry::new();
18648
custom_metrics(&registry);
@@ -492,18 +354,6 @@ pub static QUERY_EXECUTE_TIME: Lazy<HistogramVec> = Lazy::new(|| {
492354
.expect("metric can be created")
493355
});
494356

495-
pub static SLOWEST_QUERY_DURATION_SECONDS: Lazy<GaugeVec> = Lazy::new(|| {
496-
GaugeVec::new(
497-
Opts::new(
498-
"slowest_query_duration_seconds",
499-
"Duration of the slowest query completed in the latest query metrics interval",
500-
)
501-
.namespace(METRICS_NAMESPACE),
502-
&["time_range_seconds", "query_type"],
503-
)
504-
.expect("metric can be created")
505-
});
506-
507357
pub static CONVERSION_TASK_DURATION: Lazy<HistogramVec> = Lazy::new(|| {
508358
HistogramVec::new(
509359
HistogramOpts::new(
@@ -1046,9 +896,6 @@ fn custom_metrics(registry: &Registry) {
1046896
registry
1047897
.register(Box::new(QUERY_EXECUTE_TIME.clone()))
1048898
.expect("metric can be registered");
1049-
registry
1050-
.register(Box::new(SLOWEST_QUERY_DURATION_SECONDS.clone()))
1051-
.expect("metric can be registered");
1052899
registry
1053900
.register(Box::new(CONVERSION_TASK_DURATION.clone()))
1054901
.expect("metric can be registered");

0 commit comments

Comments
 (0)