Loki Query Builder: Throw warning in query builder when order of operations is ambiguous (#75198)

* flag vector aggregations containing metric expressions (i.e.`(...)`) containing binary operation expressions with ambiguous error in the UI when switching between code and visual query builders.
This commit is contained in:
Galen Kistler 2023-09-25 13:28:51 -05:00 committed by GitHub
parent ef441f02d0
commit a996f3b4a7
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 37 additions and 6 deletions

View File

@ -235,6 +235,22 @@ describe('buildVisualQueryFromString', () => {
);
});
it('returns error when parsing ambiguous query', () => {
//becomes topk(5, count_over_time({app="aggregator"} [1m])) / count_over_time({cluster="dev-eu-west-2"} [1m])
const context = buildVisualQueryFromString(
'topk(5,count_over_time({app="aggregator"}[1m])/count_over_time({cluster="dev-eu-west-2"}[1m]))'
);
expect(context).toMatchObject({
errors: [
{
from: 7,
text: 'Query parsing is ambiguous.',
to: 93,
},
],
});
});
it('parses query with matcher label filter', () => {
expect(buildVisualQueryFromString('{app="frontend"} | bar="baz"')).toEqual(
noErrors({
@ -535,7 +551,8 @@ describe('buildVisualQueryFromString', () => {
});
it('parses metrics query with function and aggregation with grouping at the end', () => {
expect(buildVisualQueryFromString('sum(rate({app="frontend"} | json [5m])) without(job,name)')).toEqual(
const expression = 'sum(rate({app="frontend"} | json [5m])) without(job,name)';
expect(buildVisualQueryFromString(expression)).toEqual(
noErrors({
labels: [
{
@ -667,7 +684,9 @@ describe('buildVisualQueryFromString', () => {
});
it('parses query with multiple label format', () => {
expect(buildVisualQueryFromString('{app="frontend"} | label_format renameTo=original, bar=baz')).toEqual(
// Converted to {app="frontend"} | label_format renameTo=original | label_format bar=baz by visual query builder
const expression = '{app="frontend"} | label_format renameTo=original, bar=baz';
expect(buildVisualQueryFromString(expression)).toEqual(
noErrors({
labels: [
{
@ -715,9 +734,10 @@ describe('buildVisualQueryFromString', () => {
});
it('parses chained binary query', () => {
expect(
buildVisualQueryFromString('rate({project="bar"}[5m]) * 2 / rate({project="foo"}[5m]) + rate({app="test"}[1m])')
).toEqual(
const expression = 'rate({project="bar"}[5m]) * 2 / rate({project="foo"}[5m]) + rate({app="test"}[1m])';
// is converted to (rate({project="bar"} [5m]) * 2) / (rate({project="foo"} [5m]) + rate({app="test"} [1m])) by visual query builder
// Note the extra parenthesis around the first binary operation expression: (rate({project="bar"} [5m]) * 2)
expect(buildVisualQueryFromString(expression)).toEqual(
noErrors({
labels: [{ op: '=', value: 'bar', label: 'project' }],
operations: [
@ -777,7 +797,9 @@ describe('buildVisualQueryFromString', () => {
});
it('parses a regexp with no param', () => {
expect(buildVisualQueryFromString('{app="frontend"} | regexp ')).toEqual(
const expression = '{app="frontend"} | regexp ';
// Converted to {app="frontend"} | regexp `` by visual query builder
expect(buildVisualQueryFromString(expression)).toEqual(
noErrors({
labels: [
{

View File

@ -541,6 +541,15 @@ function handleVectorAggregation(expr: string, node: SyntaxNode, context: Contex
const op: QueryBuilderOperation = { id: funcName, params };
if (metricExpr) {
// A vector aggregation expression with a child of metric expression with a child of binary expression is ambiguous after being parsed into a visual query
if (metricExpr.firstChild?.type.id === BinOpExpr) {
context.errors.push({
text: 'Query parsing is ambiguous.',
from: metricExpr.firstChild.from,
to: metricExpr.firstChild?.to,
});
}
handleExpression(expr, metricExpr, context);
}