From cef7b42fac0121b35e67a383339b686ba3362e9c Mon Sep 17 00:00:00 2001 From: Jeremy Wall Date: Tue, 12 Mar 2024 20:33:05 -0400 Subject: [PATCH] dev: lay ground for sending filters via get params --- src/dashboard.rs | 11 +++++++++-- src/main.rs | 2 +- src/query/prom.rs | 8 ++++++++ src/routes.rs | 23 ++++++++++++++++++++--- 4 files changed, 38 insertions(+), 6 deletions(-) diff --git a/src/dashboard.rs b/src/dashboard.rs index 65749f1..cede8d0 100644 --- a/src/dashboard.rs +++ b/src/dashboard.rs @@ -1,3 +1,4 @@ +use std::collections::HashMap; // Copyright 2023 Jeremy Wall // // Licensed under the Apache License, Version 2.0 (the "License"); @@ -120,12 +121,13 @@ pub struct LogStream { pub query_type: QueryType, } -pub async fn prom_query_data( +pub async fn prom_query_data<'a>( graph: &Graph, dash: &Dashboard, query_span: Option, + filters: &Option>, ) -> Result> { - let connections = graph.get_query_connections(&dash.span, &query_span); + let connections = graph.get_query_connections(&dash.span, &query_span, filters); let mut data = Vec::new(); for conn in connections { data.push(prom_to_samples( @@ -205,12 +207,14 @@ impl Graph { &'graph self, graph_span: &'graph Option, query_span: &'graph Option, + filters: &'graph Option>, ) -> Vec> { let mut conns = Vec::new(); for plot in self.plots.iter() { debug!( query = plot.query, source = plot.source, + filters = ?filters, "Getting query connection for graph", ); let mut conn = PromQueryConn::new( @@ -219,6 +223,9 @@ impl Graph { self.query_type.clone(), plot.meta.clone(), ); + if let Some(filters) = filters { + conn = conn.with_filters(filters); + } // Query params take precendence over all other settings. Then graph settings take // precedences and finally the dashboard settings take precendence if let Some((end, duration, step_duration)) = graph_span_to_tuple(query_span) { diff --git a/src/main.rs b/src/main.rs index 6a15458..b2a99c7 100644 --- a/src/main.rs +++ b/src/main.rs @@ -53,7 +53,7 @@ struct Cli { async fn validate(dash: &Dashboard) -> anyhow::Result<()> { if let Some(ref graphs) = dash.graphs { for graph in graphs.iter() { - let data = prom_query_data(graph, &dash, None).await; + let data = prom_query_data(graph, &dash, None, &None).await; if data.is_err() { error!(err=?data, "Invalid dashboard graph query or queries"); } diff --git a/src/query/prom.rs b/src/query/prom.rs index ace9c88..d05d1b2 100644 --- a/src/query/prom.rs +++ b/src/query/prom.rs @@ -30,6 +30,7 @@ pub struct PromQueryConn<'conn> { query: &'conn str, span: Option, query_type: QueryType, + filters: Option<&'conn HashMap<&'conn str, &'conn str>>, pub meta: PlotMeta, } @@ -46,9 +47,16 @@ impl<'conn> PromQueryConn<'conn> { query_type, meta, span: None, + filters: None, + } } + pub fn with_filters(mut self, filters: &'conn HashMap<&'conn str, &'conn str>) -> Self { + self.filters = Some(filters); + self + } + pub fn with_span( mut self, end: DateTime, diff --git a/src/routes.rs b/src/routes.rs index 6348728..4747825 100644 --- a/src/routes.rs +++ b/src/routes.rs @@ -54,7 +54,7 @@ pub async fn loki_query( .expect("No logs in this dashboard") .get(loki_idx) .expect(&format!("No such log query {}", loki_idx)); - let plots = vec![loki_query_data(log, dash, query_to_graph_span(query)) + let plots = vec![loki_query_data(log, dash, query_to_graph_span(&query)) .await .expect("Unable to get log query results")]; Json(GraphPayload { @@ -79,7 +79,8 @@ pub async fn graph_query( .expect("No graphs in this dashboard") .get(graph_idx) .expect(&format!("No such graph in dasboard {}", dash_idx)); - let plots = prom_query_data(graph, dash, query_to_graph_span(query)) + let filters = query_to_filterset(&query); + let plots = prom_query_data(graph, dash, query_to_graph_span(&query), &filters) .await .expect("Unable to get query results"); Json(GraphPayload { @@ -89,7 +90,23 @@ pub async fn graph_query( }) } -fn query_to_graph_span(query: HashMap) -> Option { +fn query_to_filterset<'v, 'a: 'v>(query: &'a HashMap) -> Option> { + let mut label_set = HashMap::new(); + for (k, v) in query.iter() { + if k.starts_with("filter-") { + if let Some(label) = k.strip_prefix("filter-") { + label_set.insert(label, v.as_str()); + } + } + } + if label_set.is_empty() { + None + } else { + Some(label_set) + } +} + +fn query_to_graph_span<'a>(query: &'a HashMap) -> Option { let query_span = { if query.contains_key("end") && query.contains_key("duration")