Heracles/src/query.rs

198 lines
5.7 KiB
Rust
Raw Permalink Normal View History

2024-02-24 19:53:25 -05:00
use std::collections::HashMap;
2024-02-12 15:50:35 -06:00
// Copyright 2023 Jeremy Wall
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
2024-02-07 19:18:30 -06:00
use chrono::prelude::*;
use prometheus_http_query::{
response::{Data, PromqlResult},
Client,
};
use serde::{Deserialize, Serialize};
use tracing::debug;
2024-02-24 19:53:25 -05:00
use crate::dashboard::PlotMeta;
2024-02-21 16:31:56 -05:00
#[derive(Deserialize, Clone, Debug)]
2024-02-11 19:08:15 -06:00
pub enum QueryType {
Range,
Scalar,
}
2024-02-21 16:31:56 -05:00
#[derive(Debug)]
pub struct TimeSpan {
2024-02-14 19:45:28 -06:00
pub end: DateTime<Utc>,
pub duration: chrono::Duration,
pub step_seconds: i64,
}
2024-02-21 16:31:56 -05:00
#[derive(Debug)]
pub struct QueryConn<'conn> {
source: &'conn str,
query: &'conn str,
span: Option<TimeSpan>,
query_type: QueryType,
2024-02-16 17:23:11 -05:00
pub meta: PlotMeta,
}
impl<'conn> QueryConn<'conn> {
2024-02-16 17:23:11 -05:00
pub fn new<'a: 'conn>(source: &'a str, query: &'a str, query_type: QueryType, meta: PlotMeta) -> Self {
Self {
source,
query,
2024-02-11 19:08:15 -06:00
query_type,
2024-02-16 17:23:11 -05:00
meta,
span: None,
}
}
2024-02-16 17:23:11 -05:00
pub fn with_span(
mut self,
end: DateTime<Utc>,
duration: chrono::Duration,
step: chrono::Duration,
) -> Self {
self.span = Some(TimeSpan {
end,
duration,
step_seconds: step.num_seconds(),
});
self
}
pub async fn get_results(&self) -> anyhow::Result<PromqlResult> {
debug!("Getting results for query");
let client = Client::try_from(self.source)?;
2024-02-14 19:45:28 -06:00
let (start, end, step_resolution) = if let Some(TimeSpan {
end,
duration: du,
2024-02-13 15:53:12 -06:00
step_seconds,
}) = self.span
{
2024-02-16 17:23:11 -05:00
let start = end - du;
debug!(
?start,
?end,
step_seconds,
"Running Query with range values"
);
(start.timestamp(), end.timestamp(), step_seconds as f64)
} else {
let end = Utc::now();
let start = end - chrono::Duration::minutes(10);
2024-02-16 17:23:11 -05:00
debug!(
?start,
?end,
step_seconds = 30,
"Running Query with range values"
);
(start.timestamp(), end.timestamp(), 30 as f64)
};
//debug!(start, end, step_resolution, "Running Query with range values");
2024-02-11 19:08:15 -06:00
match self.query_type {
QueryType::Range => {
let results = client
2024-02-16 17:23:11 -05:00
.query_range(self.query, start, end, step_resolution)
.get()
.await?;
//debug!(?results, "range results");
Ok(results)
2024-02-16 17:23:11 -05:00
}
2024-02-11 19:08:15 -06:00
QueryType::Scalar => Ok(client.query(self.query).get().await?),
}
}
}
#[derive(Serialize, Deserialize, Debug)]
pub struct DataPoint {
2024-02-07 19:18:30 -06:00
timestamp: f64,
value: f64,
}
#[derive(Serialize, Deserialize)]
pub enum QueryResult {
2024-02-16 17:23:11 -05:00
Series(Vec<(HashMap<String, String>, PlotMeta, Vec<DataPoint>)>),
Scalar(Vec<(HashMap<String, String>, PlotMeta, DataPoint)>),
}
2024-02-15 15:10:18 -05:00
impl std::fmt::Debug for QueryResult {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
2024-02-16 17:23:11 -05:00
QueryResult::Series(v) => {
2024-02-15 15:10:18 -05:00
f.write_fmt(format_args!("Series trace count = {}", v.len()))?;
2024-02-16 17:23:11 -05:00
for (idx, (tags, meta, trace)) in v.iter().enumerate() {
f.write_fmt(format_args!(
"; {}: tags {:?} meta: {:?} datapoint count = {};",
idx,
tags,
meta,
trace.len()
))?;
2024-02-15 15:10:18 -05:00
}
}
QueryResult::Scalar(v) => {
f.write_fmt(format_args!("{} traces", v.len()))?;
}
}
Ok(())
}
}
2024-02-16 17:23:11 -05:00
pub fn to_samples(data: Data, meta: PlotMeta) -> QueryResult {
match data {
Data::Matrix(mut range) => QueryResult::Series(
range
.drain(0..)
.map(|rv| {
let (metric, mut samples) = rv.into_inner();
(
metric,
2024-02-16 17:23:11 -05:00
meta.clone(),
samples
.drain(0..)
.map(|s| DataPoint {
timestamp: s.timestamp(),
value: s.value(),
})
.collect(),
)
})
.collect(),
),
Data::Vector(mut vector) => QueryResult::Scalar(
vector
.drain(0..)
.map(|iv| {
let (metric, sample) = iv.into_inner();
(
metric,
2024-02-16 17:23:11 -05:00
meta.clone(),
DataPoint {
timestamp: sample.timestamp(),
value: sample.value(),
},
)
})
.collect(),
),
Data::Scalar(sample) => QueryResult::Scalar(vec![(
HashMap::new(),
2024-02-16 17:23:11 -05:00
meta.clone(),
DataPoint {
timestamp: sample.timestamp(),
value: sample.value(),
},
)]),
}
}