mirror of
https://github.com/zaphar/Heracles.git
synced 2025-07-22 20:19:50 -04:00
dev: Only apply filters when there is a placeholder
* Allows you to respect commas placement * This is effectively the only way you can safely apply filters when there are complicated query expressions.
This commit is contained in:
parent
0a2bde6990
commit
a0b3956d8a
@ -12,7 +12,7 @@
|
||||
tickformat: "~%"
|
||||
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]))' # The PromQL query for this plot
|
||||
query: 'sum by (instance)(irate(node_cpu_seconds_total{FILTERS, job="nodestats"}[5m]))' # The PromQL query for this plot
|
||||
meta: # metadata for this plot
|
||||
name_format: "`${labels.instance}`" # javascript template literal to format the trace name
|
||||
fill: tozeroy
|
||||
@ -39,7 +39,7 @@
|
||||
- source: http://heimdall:9001
|
||||
# You can use the FILTERS placeholder to indicate where user selected filters should be placed.
|
||||
query: |
|
||||
sum by (instance)(irate(node_cpu_seconds_total{FILTERS mode="system",job="nodestats"}[5m])) / sum by (instance)(irate(node_cpu_seconds_total{FILTERS job="nodestats"}[5m]))
|
||||
sum by (instance)(irate(node_cpu_seconds_total{FILTERS mode="system",job="nodestats"}[5m])) / sum by (instance)(irate(node_cpu_seconds_total{FILTERS, job="nodestats"}[5m]))
|
||||
meta:
|
||||
name_format: "`${labels.instance} system`"
|
||||
yaxis: "y"
|
||||
|
@ -224,6 +224,7 @@ impl Graph {
|
||||
plot.meta.clone(),
|
||||
);
|
||||
if let Some(filters) = filters {
|
||||
debug!(?filters, "query connection with filters");
|
||||
conn = conn.with_filters(filters);
|
||||
}
|
||||
// Query params take precendence over all other settings. Then graph settings take
|
||||
|
@ -24,6 +24,10 @@ use crate::dashboard::PlotMeta;
|
||||
|
||||
use super::{DataPoint, QueryResult, QueryType, TimeSpan};
|
||||
|
||||
pub const FILTER_PLACEHOLDER: &'static str = "FILTERS";
|
||||
pub const FILTER_COMMA_PLACEHOLDER: &'static str = ",FILTERS";
|
||||
pub const FILTER_PLACEHOLDER_COMMA: &'static str = "FILTERS,";
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct PromQueryConn<'conn> {
|
||||
source: &'conn str,
|
||||
@ -73,6 +77,7 @@ impl<'conn> PromQueryConn<'conn> {
|
||||
fn get_query(&self) -> String {
|
||||
let first = true;
|
||||
let mut filter_string = String::new();
|
||||
debug!(filters=?self.filters, orig=?self.query, "Filters from request");
|
||||
if let Some(filters) = self.filters {
|
||||
for (k, v) in filters.iter() {
|
||||
if !first {
|
||||
@ -84,16 +89,26 @@ impl<'conn> PromQueryConn<'conn> {
|
||||
filter_string.push_str(*v);
|
||||
filter_string.push('"');
|
||||
}
|
||||
filter_string.push(',');
|
||||
}
|
||||
if self.query.contains("FILTERS") {
|
||||
// TODO(jwall): replace the FILTERS placeholder with our filters
|
||||
self.query.replace("FILTERS", &filter_string)
|
||||
if self.query.contains(FILTER_PLACEHOLDER_COMMA) {
|
||||
debug!("Replacing Filter comma placeholder");
|
||||
if !filter_string.is_empty() {
|
||||
filter_string.push(',');
|
||||
}
|
||||
self.query.replace(FILTER_PLACEHOLDER, &filter_string)
|
||||
} else if self.query.contains(FILTER_COMMA_PLACEHOLDER) {
|
||||
debug!("Replacing Filter comma placeholder");
|
||||
if !filter_string.is_empty() {
|
||||
let mut temp: String = ",".into();
|
||||
temp.push_str(&filter_string);
|
||||
filter_string = temp;
|
||||
}
|
||||
self.query.replace(FILTER_PLACEHOLDER, &filter_string)
|
||||
} else if self.query.contains(FILTER_PLACEHOLDER) {
|
||||
debug!("Replacing Filter placeholder");
|
||||
self.query.replace(FILTER_PLACEHOLDER, &filter_string)
|
||||
} else {
|
||||
let mut filter_string_curly = String::from("{");
|
||||
filter_string_curly.push_str(&filter_string);
|
||||
// TODO(jwall): Place them after the first `{`
|
||||
self.query.replace("{", &filter_string_curly)
|
||||
self.query.to_string()
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -28,7 +28,7 @@ use tracing::debug;
|
||||
use crate::dashboard::{
|
||||
loki_query_data, prom_query_data, AxisDefinition, Dashboard, Graph, GraphSpan, Orientation, LogStream,
|
||||
};
|
||||
use crate::query::QueryResult;
|
||||
use crate::query::{self, QueryResult};
|
||||
|
||||
type Config = State<Arc<Vec<Dashboard>>>;
|
||||
|
||||
@ -91,6 +91,7 @@ pub async fn graph_query(
|
||||
}
|
||||
|
||||
fn query_to_filterset<'v, 'a: 'v>(query: &'a HashMap<String, String>) -> Option<HashMap<&'v str, &'v str>> {
|
||||
debug!(query_params=?query, "Filtering query params to filter requests");
|
||||
let mut label_set = HashMap::new();
|
||||
for (k, v) in query.iter() {
|
||||
if k.starts_with("filter-") {
|
||||
@ -153,13 +154,14 @@ pub fn graph_component(dash_idx: usize, graph_idx: usize, graph: &Graph) -> Mark
|
||||
let graph_id = format!("graph-{}-{}", dash_idx, graph_idx);
|
||||
let graph_data_uri = format!("/api/dash/{}/graph/{}", dash_idx, graph_idx);
|
||||
let graph_embed_uri = format!("/embed/dash/{}/graph/{}", dash_idx, graph_idx);
|
||||
let allow_filters = graph.plots.iter().find(|p| p.query.contains(query::FILTER_PLACEHOLDER)).is_some();
|
||||
html!(
|
||||
div {
|
||||
h2 { (graph.title) " - " a href=(graph_embed_uri) { "embed url" } }
|
||||
@if graph.d3_tick_format.is_some() {
|
||||
graph-plot uri=(graph_data_uri) id=(graph_id) d3-tick-format=(graph.d3_tick_format.as_ref().unwrap()) { }
|
||||
graph-plot allow-uri-filters=(allow_filters) uri=(graph_data_uri) id=(graph_id) d3-tick-format=(graph.d3_tick_format.as_ref().unwrap()) { }
|
||||
} @else {
|
||||
graph-plot uri=(graph_data_uri) id=(graph_id) { }
|
||||
graph-plot allow-uri-filters=(allow_filters) uri=(graph_data_uri) id=(graph_id) { }
|
||||
}
|
||||
}
|
||||
)
|
||||
|
@ -64,6 +64,8 @@ function getCssVariableValue(variableName) {
|
||||
export class GraphPlot extends HTMLElement {
|
||||
/** @type {?string} */
|
||||
#uri;
|
||||
/** @type {?boolean} */
|
||||
#allowUriFilters;
|
||||
/** @type {?number} */
|
||||
#width;
|
||||
/** @type {?number} */
|
||||
@ -103,7 +105,7 @@ export class GraphPlot extends HTMLElement {
|
||||
this.#targetNode = this.appendChild(document.createElement("div"));
|
||||
}
|
||||
|
||||
static observedAttributes = ['uri', 'width', 'height', 'poll-seconds', 'end', 'duration', 'step-duration', 'd3-tick-format'];
|
||||
static observedAttributes = ['uri', 'width', 'height', 'poll-seconds', 'end', 'duration', 'step-duration', 'd3-tick-format', 'allow-uri-filter'];
|
||||
|
||||
/**
|
||||
* Callback for attributes changes.
|
||||
@ -138,6 +140,9 @@ export class GraphPlot extends HTMLElement {
|
||||
case 'd3-tick-format':
|
||||
this.#d3TickFormat = newValue;
|
||||
break;
|
||||
case 'allow-uri-filters':
|
||||
this.#allowUriFilters = Boolean(newValue);
|
||||
break;
|
||||
default: // do nothing;
|
||||
break;
|
||||
}
|
||||
@ -153,6 +158,7 @@ export class GraphPlot extends HTMLElement {
|
||||
this.#duration = Number(this.getAttribute('duration')) || null;
|
||||
this.#step_duration = this.getAttribute('step-duration') || null;
|
||||
this.#d3TickFormat = this.getAttribute('d3-tick-format') || this.#d3TickFormat;
|
||||
this.#allowUriFilters = Boolean(this.getAttribute('allow-uri-filters'));
|
||||
this.reset();
|
||||
}
|
||||
|
||||
@ -211,8 +217,21 @@ export class GraphPlot extends HTMLElement {
|
||||
* @returns {string}
|
||||
*/
|
||||
getUri() {
|
||||
//var uriParts = [this.#uri];
|
||||
var uriParts = [];
|
||||
if (this.#end && this.#duration && this.#step_duration) {
|
||||
return this.#uri + "?end=" + this.#end + "&duration=" + this.#duration + "&step_duration=" + this.#step_duration;
|
||||
uriParts.push("end=" + this.#end);
|
||||
uriParts.push("duration=" + this.#duration);
|
||||
uriParts.push("step_duration=" + this.#step_duration);
|
||||
}
|
||||
if (this.#allowUriFilters) {
|
||||
for (const filterName in this.#filteredLabelSets) {
|
||||
const filterVals = this.#filteredLabelSets[filterName].join("|");
|
||||
uriParts.push(`filter-${filterName}=${filterVals}`)
|
||||
}
|
||||
}
|
||||
if (uriParts) {
|
||||
return this.#uri + "?" + uriParts.join('&');
|
||||
} else {
|
||||
return this.#uri;
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user