fix: follow promql rule for hanndling label of aggr (#6788)

* fix: follow promql rule for hanndling label of aggr

Signed-off-by: Ruihang Xia <waynestxia@gmail.com>

* adopt more rules

Signed-off-by: Ruihang Xia <waynestxia@gmail.com>

* fix clippy

Signed-off-by: Ruihang Xia <waynestxia@gmail.com>

---------

Signed-off-by: Ruihang Xia <waynestxia@gmail.com>
This commit is contained in:
Ruihang Xia
2025-08-25 20:37:08 -07:00
committed by GitHub
parent 69eed2c3fa
commit eb5e627ddd

View File

@@ -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<String> {
/// Recursively collect all metric names from a PromQL expression
fn collect_metric_names(expr: &PromqlExpr, metric_names: &mut HashSet<String>) {
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,
},