2024-02-12 15:50:35 -06:00
|
|
|
// Copyright 2023 Jeremy Wall
|
2024-02-03 16:31:41 -06:00
|
|
|
//
|
|
|
|
// 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-04 16:39:25 -06:00
|
|
|
use std::collections::HashMap;
|
2024-02-03 16:31:41 -06:00
|
|
|
|
2024-02-07 19:18:30 -06:00
|
|
|
use chrono::prelude::*;
|
2024-02-13 14:22:26 -06:00
|
|
|
use prometheus_http_query::{
|
|
|
|
response::{Data, PromqlResult},
|
|
|
|
Client,
|
|
|
|
};
|
|
|
|
use serde::{Deserialize, Serialize};
|
|
|
|
use tracing::debug;
|
2024-02-04 16:39:25 -06:00
|
|
|
|
2024-02-11 19:08:15 -06:00
|
|
|
#[derive(Deserialize, Clone)]
|
|
|
|
pub enum QueryType {
|
|
|
|
Range,
|
|
|
|
Scalar,
|
|
|
|
}
|
|
|
|
|
2024-02-13 14:22:26 -06:00
|
|
|
pub struct TimeSpan {
|
2024-02-14 19:45:28 -06:00
|
|
|
pub end: DateTime<Utc>,
|
2024-02-13 14:22:26 -06:00
|
|
|
pub duration: chrono::Duration,
|
|
|
|
pub step_seconds: i64,
|
|
|
|
}
|
|
|
|
|
2024-02-04 16:39:25 -06:00
|
|
|
pub struct QueryConn<'conn> {
|
|
|
|
source: &'conn str,
|
|
|
|
query: &'conn str,
|
2024-02-13 14:22:26 -06:00
|
|
|
span: Option<TimeSpan>,
|
|
|
|
query_type: QueryType,
|
2024-02-03 16:31:41 -06:00
|
|
|
}
|
|
|
|
|
2024-02-04 16:39:25 -06:00
|
|
|
impl<'conn> QueryConn<'conn> {
|
2024-02-11 19:08:15 -06:00
|
|
|
pub fn new<'a: 'conn>(source: &'a str, query: &'a str, query_type: QueryType) -> Self {
|
2024-02-03 16:31:41 -06:00
|
|
|
Self {
|
2024-02-04 16:39:25 -06:00
|
|
|
source,
|
|
|
|
query,
|
2024-02-11 19:08:15 -06:00
|
|
|
query_type,
|
2024-02-13 14:22:26 -06:00
|
|
|
span: None,
|
2024-02-04 16:39:25 -06:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-02-14 19:45:28 -06: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() , });
|
2024-02-13 14:22:26 -06:00
|
|
|
self
|
|
|
|
}
|
|
|
|
|
2024-02-04 16:39:25 -06:00
|
|
|
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 {
|
2024-02-15 15:28:31 -05:00
|
|
|
end,
|
2024-02-13 14:22:26 -06:00
|
|
|
duration: du,
|
2024-02-13 15:53:12 -06:00
|
|
|
step_seconds,
|
2024-02-13 14:22:26 -06:00
|
|
|
}) = self.span
|
|
|
|
{
|
2024-02-15 15:28:31 -05:00
|
|
|
let start = end - du;
|
|
|
|
debug!(?start, ?end, step_seconds, "Running Query with range values");
|
|
|
|
(start.timestamp(), end.timestamp(), step_seconds as f64)
|
2024-02-13 14:22:26 -06:00
|
|
|
} else {
|
2024-02-15 15:28:31 -05:00
|
|
|
let end = Utc::now();
|
|
|
|
let start = end - chrono::Duration::minutes(10);
|
|
|
|
debug!(?start, ?end, step_seconds=30, "Running Query with range values");
|
|
|
|
(start.timestamp(), end.timestamp(), 30 as f64)
|
2024-02-13 14:22:26 -06:00
|
|
|
};
|
2024-02-15 15:28:31 -05:00
|
|
|
//debug!(start, end, step_resolution, "Running Query with range values");
|
2024-02-11 19:08:15 -06:00
|
|
|
match self.query_type {
|
2024-02-15 15:28:31 -05:00
|
|
|
QueryType::Range => {
|
|
|
|
let results = client
|
2024-02-13 14:22:26 -06:00
|
|
|
.query_range(self.query, start, end, step_resolution)
|
|
|
|
.get()
|
2024-02-15 15:28:31 -05:00
|
|
|
.await?;
|
|
|
|
//debug!(?results, "range results");
|
|
|
|
Ok(results)
|
|
|
|
},
|
2024-02-11 19:08:15 -06:00
|
|
|
QueryType::Scalar => Ok(client.query(self.query).get().await?),
|
|
|
|
}
|
2024-02-04 16:39:25 -06:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-02-15 15:28:31 -05:00
|
|
|
#[derive(Serialize, Deserialize, Debug)]
|
2024-02-04 16:39:25 -06:00
|
|
|
pub struct DataPoint {
|
2024-02-07 19:18:30 -06:00
|
|
|
timestamp: f64,
|
2024-02-04 16:39:25 -06:00
|
|
|
value: f64,
|
|
|
|
}
|
|
|
|
|
|
|
|
#[derive(Serialize, Deserialize)]
|
|
|
|
pub enum QueryResult {
|
|
|
|
Series(Vec<(HashMap<String, String>, Vec<DataPoint>)>),
|
2024-02-11 19:08:15 -06:00
|
|
|
Scalar(Vec<(HashMap<String, String>, DataPoint)>),
|
2024-02-04 16:39:25 -06:00
|
|
|
}
|
|
|
|
|
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 {
|
|
|
|
QueryResult::Series(v) => {
|
|
|
|
f.write_fmt(format_args!("Series trace count = {}", v.len()))?;
|
|
|
|
for (idx, (tags, trace)) in v.iter().enumerate() {
|
|
|
|
f.write_fmt(format_args!("; {}: meta {:?} datapoint count = {};", idx, tags, trace.len()))?;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
QueryResult::Scalar(v) => {
|
|
|
|
f.write_fmt(format_args!("{} traces", v.len()))?;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-02-04 16:39:25 -06:00
|
|
|
pub fn to_samples(data: Data) -> QueryResult {
|
|
|
|
match data {
|
2024-02-13 14:22:26 -06:00
|
|
|
Data::Matrix(mut range) => QueryResult::Series(
|
|
|
|
range
|
|
|
|
.drain(0..)
|
|
|
|
.map(|rv| {
|
|
|
|
let (metric, mut samples) = rv.into_inner();
|
|
|
|
(
|
|
|
|
metric,
|
|
|
|
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,
|
|
|
|
DataPoint {
|
|
|
|
timestamp: sample.timestamp(),
|
|
|
|
value: sample.value(),
|
|
|
|
},
|
|
|
|
)
|
|
|
|
})
|
|
|
|
.collect(),
|
|
|
|
),
|
|
|
|
Data::Scalar(sample) => QueryResult::Scalar(vec![(
|
|
|
|
HashMap::new(),
|
|
|
|
DataPoint {
|
|
|
|
timestamp: sample.timestamp(),
|
|
|
|
value: sample.value(),
|
|
|
|
},
|
|
|
|
)]),
|
2024-02-03 16:31:41 -06:00
|
|
|
}
|
|
|
|
}
|