mirror of
https://github.com/zaphar/Heracles.git
synced 2025-07-25 13:29:48 -04:00
feat: Flag to validate config and queries succeeed.
This commit is contained in:
parent
835c120d4b
commit
8aa41eb68c
18
examples/example_bad_dashboard.yaml
Normal file
18
examples/example_bad_dashboard.yaml
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
--- # A list of dashboards
|
||||||
|
- title: Invalid Dasbboard
|
||||||
|
graphs: # Each Dashboard can have 1 or more graphs in it.
|
||||||
|
- title: Node cpu # Graphs have titles
|
||||||
|
query_type: Range # The type of graph. Range for timeseries and Scalar for point in time
|
||||||
|
d3_tick_format: "~s" # Default tick format for the graph y axis
|
||||||
|
plots: # List of pluts to show on the graph
|
||||||
|
- source: http://heimdall:9001 # Prometheus source uri for this plot
|
||||||
|
query: 'sum by (instance)(irate(node_cpu_seconds_total{job="nodestats"}[5m])' # syntax error in query
|
||||||
|
meta: # metadata for this plot
|
||||||
|
name_format: "`${labels.instance}`" # javascript template literal to format the trace name
|
||||||
|
fill: tozeroy
|
||||||
|
#d3_tick_format: "~%" # d3 tick format override for this plot's yaxis
|
||||||
|
#named_axis: "y" # yaxis name to use for this subplots traces
|
||||||
|
span: # The span for this range query
|
||||||
|
end: now # Where the span ends. RFC3339 format with special handling for the now keyword
|
||||||
|
duration: 1d # duration of the span. Uses SI formatting for duration amounts.
|
||||||
|
step_duration: 10min # step size for the duration amounts.
|
@ -18,8 +18,9 @@ use chrono::Duration;
|
|||||||
use serde::Deserialize;
|
use serde::Deserialize;
|
||||||
use serde_yaml;
|
use serde_yaml;
|
||||||
use tracing::{debug, error};
|
use tracing::{debug, error};
|
||||||
|
use anyhow::Result;
|
||||||
|
|
||||||
use crate::query::{QueryConn, QueryType, PlotMeta};
|
use crate::query::{QueryConn, QueryType, QueryResult, PlotMeta, to_samples};
|
||||||
|
|
||||||
#[derive(Deserialize, Debug)]
|
#[derive(Deserialize, Debug)]
|
||||||
pub struct GraphSpan {
|
pub struct GraphSpan {
|
||||||
@ -52,6 +53,21 @@ pub struct Graph {
|
|||||||
pub d3_tick_format: Option<String>,
|
pub d3_tick_format: Option<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub async fn query_data(graph: &Graph, dash: &Dashboard, query_span: Option<GraphSpan>) -> Result<Vec<QueryResult>> {
|
||||||
|
let connections = graph.get_query_connections(&dash.span, &query_span);
|
||||||
|
let mut data = Vec::new();
|
||||||
|
for conn in connections {
|
||||||
|
data.push(to_samples(
|
||||||
|
conn.get_results()
|
||||||
|
.await?
|
||||||
|
.data()
|
||||||
|
.clone(),
|
||||||
|
conn.meta,
|
||||||
|
));
|
||||||
|
}
|
||||||
|
Ok(data)
|
||||||
|
}
|
||||||
|
|
||||||
fn duration_from_string(duration_string: &str) -> Option<Duration> {
|
fn duration_from_string(duration_string: &str) -> Option<Duration> {
|
||||||
match parse_duration::parse(duration_string) {
|
match parse_duration::parse(duration_string) {
|
||||||
Ok(d) => match Duration::from_std(d) {
|
Ok(d) => match Duration::from_std(d) {
|
||||||
|
24
src/main.rs
24
src/main.rs
@ -12,12 +12,13 @@
|
|||||||
// See the License for the specific language governing permissions and
|
// See the License for the specific language governing permissions and
|
||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
|
|
||||||
use anyhow;
|
use anyhow;
|
||||||
use axum::{self, extract::State, routing::*, Router};
|
use axum::{self, extract::State, routing::*, Router};
|
||||||
use clap::{self, Parser, ValueEnum};
|
use clap::{self, Parser, ValueEnum};
|
||||||
|
use dashboard::{Dashboard, query_data};
|
||||||
use tokio::net::TcpListener;
|
use tokio::net::TcpListener;
|
||||||
use tower_http::trace::TraceLayer;
|
use tower_http::trace::TraceLayer;
|
||||||
|
use tracing::{error, info};
|
||||||
use tracing::Level;
|
use tracing::Level;
|
||||||
use tracing_subscriber::FmtSubscriber;
|
use tracing_subscriber::FmtSubscriber;
|
||||||
|
|
||||||
@ -43,6 +44,19 @@ struct Cli {
|
|||||||
pub config: PathBuf,
|
pub config: PathBuf,
|
||||||
#[arg(long, value_enum, default_value_t = Verbosity::INFO)]
|
#[arg(long, value_enum, default_value_t = Verbosity::INFO)]
|
||||||
pub verbose: Verbosity,
|
pub verbose: Verbosity,
|
||||||
|
#[arg(long, default_value_t = false)]
|
||||||
|
pub validate: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn validate(dash: &Dashboard) -> anyhow::Result<()> {
|
||||||
|
for graph in dash.graphs.iter() {
|
||||||
|
let data = query_data(graph, &dash, None).await;
|
||||||
|
if data.is_err() {
|
||||||
|
error!(err=?data, "Invalid dashboard query or queries");
|
||||||
|
}
|
||||||
|
let _ = data?;
|
||||||
|
}
|
||||||
|
return Ok(());
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tokio::main]
|
#[tokio::main]
|
||||||
@ -61,6 +75,14 @@ async fn main() -> anyhow::Result<()> {
|
|||||||
.expect("setting default subscriber failed");
|
.expect("setting default subscriber failed");
|
||||||
|
|
||||||
let config = std::sync::Arc::new(dashboard::read_dashboard_list(args.config.as_path())?);
|
let config = std::sync::Arc::new(dashboard::read_dashboard_list(args.config.as_path())?);
|
||||||
|
|
||||||
|
if args.validate {
|
||||||
|
for dash in config.iter() {
|
||||||
|
validate(&dash).await?;
|
||||||
|
info!("All Queries successfully run against source");
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
}
|
||||||
let router = Router::new()
|
let router = Router::new()
|
||||||
// JSON api endpoints
|
// JSON api endpoints
|
||||||
.nest("/js", routes::mk_js_routes(config.clone()))
|
.nest("/js", routes::mk_js_routes(config.clone()))
|
||||||
|
@ -24,7 +24,7 @@ use axum::{
|
|||||||
use maud::{html, Markup};
|
use maud::{html, Markup};
|
||||||
use tracing::debug;
|
use tracing::debug;
|
||||||
|
|
||||||
use crate::dashboard::{Dashboard, Graph, GraphSpan};
|
use crate::dashboard::{Dashboard, Graph, GraphSpan, query_data};
|
||||||
use crate::query::{to_samples, QueryResult};
|
use crate::query::{to_samples, QueryResult};
|
||||||
|
|
||||||
type Config = State<Arc<Vec<Dashboard>>>;
|
type Config = State<Arc<Vec<Dashboard>>>;
|
||||||
@ -54,18 +54,7 @@ pub async fn graph_query(
|
|||||||
None
|
None
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
let connections = graph.get_query_connections(&dash.span, &query_span);
|
let data = query_data(graph, dash, query_span).await.expect("Unable to get query results");
|
||||||
let mut data = Vec::new();
|
|
||||||
for conn in connections {
|
|
||||||
data.push(to_samples(
|
|
||||||
conn.get_results()
|
|
||||||
.await
|
|
||||||
.expect("Unable to get query results")
|
|
||||||
.data()
|
|
||||||
.clone(),
|
|
||||||
conn.meta,
|
|
||||||
));
|
|
||||||
}
|
|
||||||
Json(data)
|
Json(data)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user