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