mirror of
https://github.com/zaphar/Heracles.git
synced 2025-07-23 12:39:50 -04:00
feat: Dashboard level timespans
This commit is contained in:
parent
7ef0af2b43
commit
710f73332d
@ -11,6 +11,10 @@
|
||||
step_duration: 1min
|
||||
name_label: instance
|
||||
- title: Test Dasbboard 2
|
||||
span:
|
||||
start: 2024-02-10T00:00:00.00Z
|
||||
duration: 2d
|
||||
step_duration: 1min
|
||||
graphs:
|
||||
- title: Node cpu
|
||||
source: http://heimdall:9001
|
||||
|
@ -14,18 +14,13 @@
|
||||
use std::path::Path;
|
||||
|
||||
use chrono::prelude::*;
|
||||
use chrono::Duration;
|
||||
use serde::Deserialize;
|
||||
use serde_yaml;
|
||||
use tracing::{debug, error};
|
||||
|
||||
use crate::query::{QueryConn, QueryType};
|
||||
|
||||
#[derive(Deserialize)]
|
||||
pub struct Dashboard {
|
||||
pub title: String,
|
||||
pub graphs: Vec<Graph>,
|
||||
}
|
||||
|
||||
#[derive(Deserialize)]
|
||||
pub struct GraphSpan {
|
||||
pub start: DateTime<Utc>,
|
||||
@ -33,6 +28,13 @@ pub struct GraphSpan {
|
||||
pub step_duration: String,
|
||||
}
|
||||
|
||||
#[derive(Deserialize)]
|
||||
pub struct Dashboard {
|
||||
pub title: String,
|
||||
pub graphs: Vec<Graph>,
|
||||
pub span: Option<GraphSpan>
|
||||
}
|
||||
|
||||
#[derive(Deserialize)]
|
||||
pub struct Graph {
|
||||
pub title: String,
|
||||
@ -44,9 +46,9 @@ pub struct Graph {
|
||||
pub query_type: QueryType,
|
||||
}
|
||||
|
||||
fn duration_from_string(duration: &str) -> Option<chrono::Duration> {
|
||||
fn duration_from_string(duration: &str) -> Option<Duration> {
|
||||
match parse_duration::parse(duration) {
|
||||
Ok(d) => match chrono::Duration::from_std(d) {
|
||||
Ok(d) => match Duration::from_std(d) {
|
||||
Ok(d) => Some(d),
|
||||
Err(e) => {
|
||||
error!(err = ?e, "specified Duration is out of bounds");
|
||||
@ -63,30 +65,40 @@ fn duration_from_string(duration: &str) -> Option<chrono::Duration> {
|
||||
}
|
||||
}
|
||||
|
||||
fn graph_span_to_tuple(span: &Option<GraphSpan>) -> Option<(DateTime<Utc>, Duration, Duration)> {
|
||||
if span.is_none() {
|
||||
return None;
|
||||
}
|
||||
let span = span.as_ref().unwrap();
|
||||
let duration = match duration_from_string(&span.duration) {
|
||||
Some(d) => d,
|
||||
None => {
|
||||
error!("Invalid query duration not assigning span to to graph query");
|
||||
return None;
|
||||
}
|
||||
};
|
||||
let step_duration = match duration_from_string(&span.step_duration) {
|
||||
Some(d) => d,
|
||||
None => {
|
||||
error!("Invalid query step resolution not assigning span to to graph query");
|
||||
return None;
|
||||
}
|
||||
};
|
||||
Some((span.start.clone(), duration, step_duration))
|
||||
}
|
||||
|
||||
impl Graph {
|
||||
pub fn get_query_connection<'conn, 'graph: 'conn>(&'graph self) -> QueryConn<'conn> {
|
||||
pub fn get_query_connection<'conn, 'graph: 'conn>(&'graph self, graph_span: &'graph Option<GraphSpan>) -> QueryConn<'conn> {
|
||||
debug!(
|
||||
query = self.query,
|
||||
source = self.source,
|
||||
"Getting query connection for graph"
|
||||
);
|
||||
let mut conn = QueryConn::new(&self.source, &self.query, self.query_type.clone());
|
||||
if let Some(span) = &self.span {
|
||||
let duration = match duration_from_string(&span.duration) {
|
||||
Some(d) => d,
|
||||
None => {
|
||||
error!("Invalid query duration not assigning span to to graph query");
|
||||
return conn;
|
||||
}
|
||||
};
|
||||
let step_duration = match duration_from_string(&span.step_duration) {
|
||||
Some(d) => d,
|
||||
None => {
|
||||
error!("Invalid query step resolution not assigning span to to graph query");
|
||||
return conn;
|
||||
}
|
||||
};
|
||||
conn = conn.with_span(span.start.clone(), duration, step_duration);
|
||||
if let Some((start, duration, step_duration)) = graph_span_to_tuple(&self.span) {
|
||||
conn = conn.with_span(start, duration, step_duration);
|
||||
} else if let Some((start, duration, step_duration)) = graph_span_to_tuple(graph_span) {
|
||||
conn = conn.with_span(start, duration, step_duration);
|
||||
}
|
||||
conn
|
||||
}
|
||||
|
@ -34,15 +34,15 @@ pub async fn graph_query(
|
||||
Path((dash_idx, graph_idx)): Path<(usize, usize)>,
|
||||
) -> Json<QueryResult> {
|
||||
debug!("Getting data for query");
|
||||
let graph = config
|
||||
let dash = config
|
||||
.get(dash_idx)
|
||||
.expect("No such dashboard index")
|
||||
.graphs
|
||||
.expect("No such dashboard index");
|
||||
let graph = dash.graphs
|
||||
.get(graph_idx)
|
||||
.expect(&format!("No such graph in dasboard {}", dash_idx));
|
||||
let data = to_samples(
|
||||
graph
|
||||
.get_query_connection()
|
||||
.get_query_connection(&dash.span)
|
||||
.get_results()
|
||||
.await
|
||||
.expect("Unable to get query results")
|
||||
@ -54,6 +54,7 @@ pub async fn graph_query(
|
||||
|
||||
pub fn mk_api_routes(config: Arc<Vec<Dashboard>>) -> Router<Config> {
|
||||
// Query routes
|
||||
// TODO(zaphar): Allow passing the timespan in via query
|
||||
Router::new().route(
|
||||
"/dash/:dash_idx/graph/:graph_idx",
|
||||
get(graph_query).with_state(config),
|
||||
|
Loading…
x
Reference in New Issue
Block a user