diff --git a/src/servers/src/http/prometheus.rs b/src/servers/src/http/prometheus.rs index 5d74be1458..86ffe51704 100644 --- a/src/servers/src/http/prometheus.rs +++ b/src/servers/src/http/prometheus.rs @@ -34,10 +34,11 @@ use futures::future::join_all; use futures::StreamExt; use itertools::Itertools; use promql_parser::label::{MatchOp, Matcher, Matchers, METRIC_NAME}; +use promql_parser::parser::token::{self}; use promql_parser::parser::value::ValueType; use promql_parser::parser::{ - AggregateExpr, BinaryExpr, Call, Expr as PromqlExpr, MatrixSelector, ParenExpr, SubqueryExpr, - UnaryExpr, VectorSelector, + AggregateExpr, BinaryExpr, Call, Expr as PromqlExpr, LabelModifier, MatrixSelector, ParenExpr, + SubqueryExpr, UnaryExpr, VectorSelector, }; use query::parser::{PromQuery, QueryLanguageParser, DEFAULT_LOOKBACK_STRING}; use query::promql::planner::normalize_matcher; @@ -838,13 +839,36 @@ fn promql_expr_to_metric_name(expr: &PromqlExpr) -> Option { /// Recursively collect all metric names from a PromQL expression fn collect_metric_names(expr: &PromqlExpr, metric_names: &mut HashSet) { match expr { - PromqlExpr::Aggregate(AggregateExpr { expr, .. }) => { + PromqlExpr::Aggregate(AggregateExpr { modifier, expr, .. }) => { + match modifier { + Some(LabelModifier::Include(labels)) => { + if !labels.labels.contains(&METRIC_NAME.to_string()) { + metric_names.clear(); + return; + } + } + Some(LabelModifier::Exclude(labels)) => { + if labels.labels.contains(&METRIC_NAME.to_string()) { + metric_names.clear(); + return; + } + } + _ => {} + } collect_metric_names(expr, metric_names) } - PromqlExpr::Unary(UnaryExpr { expr }) => collect_metric_names(expr, metric_names), - PromqlExpr::Binary(BinaryExpr { lhs, rhs, .. }) => { - collect_metric_names(lhs, metric_names); - collect_metric_names(rhs, metric_names); + PromqlExpr::Unary(UnaryExpr { .. }) => metric_names.clear(), + PromqlExpr::Binary(BinaryExpr { lhs, op, .. }) => { + if matches!( + op.id(), + token::T_LAND // INTERSECT + | token::T_LOR // UNION + | token::T_LUNLESS // EXCEPT + ) { + collect_metric_names(lhs, metric_names) + } else { + metric_names.clear() + } } PromqlExpr::Paren(ParenExpr { expr }) => collect_metric_names(expr, metric_names), PromqlExpr::Subquery(SubqueryExpr { expr, .. }) => collect_metric_names(expr, metric_names), @@ -1436,7 +1460,7 @@ mod tests { TestCase { name: "metric with unary operator", promql: "-cpu_usage", - expected_metric: Some("cpu_usage"), + expected_metric: None, expected_type: ValueType::Vector, should_error: false, }, @@ -1451,6 +1475,20 @@ mod tests { TestCase { name: "complex aggregation", promql: r#"sum by (instance) (cpu_usage{job="node"})"#, + expected_metric: None, + expected_type: ValueType::Vector, + should_error: false, + }, + TestCase { + name: "complex aggregation", + promql: r#"sum by (__name__) (cpu_usage{job="node"})"#, + expected_metric: Some("cpu_usage"), + expected_type: ValueType::Vector, + should_error: false, + }, + TestCase { + name: "complex aggregation", + promql: r#"sum without (instance) (cpu_usage{job="node"})"#, expected_metric: Some("cpu_usage"), expected_type: ValueType::Vector, should_error: false, @@ -1459,14 +1497,14 @@ mod tests { TestCase { name: "same metric addition", promql: "cpu_usage + cpu_usage", - expected_metric: Some("cpu_usage"), + expected_metric: None, expected_type: ValueType::Vector, should_error: false, }, TestCase { name: "metric with scalar addition", - promql: r#"sum(rate(cpu_usage{job="node"}[5m])) by (instance) + 100"#, - expected_metric: Some("cpu_usage"), + promql: r#"sum(rate(cpu_usage{job="node"}[5m])) + 100"#, + expected_metric: None, expected_type: ValueType::Vector, should_error: false, }, @@ -1489,7 +1527,7 @@ mod tests { TestCase { name: "unless with different metrics", promql: "cpu_usage unless memory_usage", - expected_metric: None, + expected_metric: Some("cpu_usage"), expected_type: ValueType::Vector, should_error: false, },