mirror of
https://github.com/grafana/grafana.git
synced 2025-02-15 01:53:33 -06:00
Loki: Add parsing for vector aggregations with grouping (#47257)
* Parse aggregations with grouping * Move getByType to shared parsing utils
This commit is contained in:
parent
78bdcede70
commit
24cf70dd29
@ -179,6 +179,44 @@ describe('buildVisualQueryFromString', () => {
|
||||
);
|
||||
});
|
||||
|
||||
it('parses metrics query with function and aggregation with grouping', () => {
|
||||
expect(buildVisualQueryFromString('sum by (job,name) (rate({app="frontend"} | json [5m]))')).toEqual(
|
||||
noErrors({
|
||||
labels: [
|
||||
{
|
||||
op: '=',
|
||||
value: 'frontend',
|
||||
label: 'app',
|
||||
},
|
||||
],
|
||||
operations: [
|
||||
{ id: 'json', params: [] },
|
||||
{ id: 'rate', params: ['5m'] },
|
||||
{ id: '__sum_by', params: ['job', 'name'] },
|
||||
],
|
||||
})
|
||||
);
|
||||
});
|
||||
|
||||
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(
|
||||
noErrors({
|
||||
labels: [
|
||||
{
|
||||
op: '=',
|
||||
value: 'frontend',
|
||||
label: 'app',
|
||||
},
|
||||
],
|
||||
operations: [
|
||||
{ id: 'json', params: [] },
|
||||
{ id: 'rate', params: ['5m'] },
|
||||
{ id: '__sum_without', params: ['job', 'name'] },
|
||||
],
|
||||
})
|
||||
);
|
||||
});
|
||||
|
||||
it('parses metrics query with function and aggregation and filters', () => {
|
||||
expect(buildVisualQueryFromString('sum(rate({app="frontend"} |~ `abc` | json | bar="baz" [5m]))')).toEqual(
|
||||
noErrors({
|
||||
|
@ -2,6 +2,7 @@ import { parser } from '@grafana/lezer-logql';
|
||||
import { SyntaxNode } from '@lezer/common';
|
||||
import {
|
||||
ErrorName,
|
||||
getAllByType,
|
||||
getLeftMostChild,
|
||||
getString,
|
||||
makeBinOp,
|
||||
@ -217,7 +218,6 @@ function getLabelFilter(expr: string, node: SyntaxNode): QueryBuilderOperation {
|
||||
}
|
||||
|
||||
function getLineFormat(expr: string, node: SyntaxNode): QueryBuilderOperation {
|
||||
// Not implemented in visual query builder yet
|
||||
const id = 'line_format';
|
||||
const string = handleQuotes(getString(expr, node.getChild('String')));
|
||||
|
||||
@ -228,7 +228,6 @@ function getLineFormat(expr: string, node: SyntaxNode): QueryBuilderOperation {
|
||||
}
|
||||
|
||||
function getLabelFormat(expr: string, node: SyntaxNode): QueryBuilderOperation {
|
||||
// Not implemented in visual query builder yet
|
||||
const id = 'label_format';
|
||||
const identifier = node.getChild('Identifier');
|
||||
const op = identifier!.nextSibling;
|
||||
@ -270,8 +269,25 @@ function handleVectorAggregation(expr: string, node: SyntaxNode, context: Contex
|
||||
const nameNode = node.getChild('VectorOp');
|
||||
let funcName = getString(expr, nameNode);
|
||||
|
||||
const grouping = node.getChild('Grouping');
|
||||
const labels: string[] = [];
|
||||
|
||||
if (grouping) {
|
||||
const byModifier = grouping.getChild(`By`);
|
||||
if (byModifier && funcName) {
|
||||
funcName = `__${funcName}_by`;
|
||||
}
|
||||
|
||||
const withoutModifier = grouping.getChild(`Without`);
|
||||
if (withoutModifier) {
|
||||
funcName = `__${funcName}_without`;
|
||||
}
|
||||
|
||||
labels.push(...getAllByType(expr, grouping, 'Identifier'));
|
||||
}
|
||||
|
||||
const metricExpr = node.getChild('MetricExpr');
|
||||
const op: QueryBuilderOperation = { id: funcName, params: [] };
|
||||
const op: QueryBuilderOperation = { id: funcName, params: labels };
|
||||
|
||||
if (metricExpr) {
|
||||
handleExpression(expr, metricExpr, context);
|
||||
|
@ -3,7 +3,15 @@ import { SyntaxNode } from '@lezer/common';
|
||||
import { QueryBuilderLabelFilter, QueryBuilderOperation } from './shared/types';
|
||||
import { PromVisualQuery, PromVisualQueryBinary } from './types';
|
||||
import { binaryScalarDefs } from './binaryScalarOperations';
|
||||
import { ErrorName, getLeftMostChild, getString, makeBinOp, makeError, replaceVariables } from './shared/parsingUtils';
|
||||
import {
|
||||
ErrorName,
|
||||
getAllByType,
|
||||
getLeftMostChild,
|
||||
getString,
|
||||
makeBinOp,
|
||||
makeError,
|
||||
replaceVariables,
|
||||
} from './shared/parsingUtils';
|
||||
|
||||
/**
|
||||
* Parses a PromQL query into a visual query model.
|
||||
@ -365,26 +373,3 @@ function getBinaryModifier(
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all nodes with type in the tree. This traverses the tree so it is safe only when you know there shouldn't be
|
||||
* too much nesting but you just want to skip some of the wrappers. For example getting function args this way would
|
||||
* not be safe is it would also find arguments of nested functions.
|
||||
* @param expr
|
||||
* @param cur
|
||||
* @param type
|
||||
*/
|
||||
function getAllByType(expr: string, cur: SyntaxNode, type: string): string[] {
|
||||
if (cur.name === type) {
|
||||
return [getString(expr, cur)];
|
||||
}
|
||||
const values: string[] = [];
|
||||
let pos = 0;
|
||||
let child = cur.childAfter(pos);
|
||||
while (child) {
|
||||
values.push(...getAllByType(expr, child, type));
|
||||
pos = child.to;
|
||||
child = cur.childAfter(pos);
|
||||
}
|
||||
return values;
|
||||
}
|
||||
|
@ -106,6 +106,29 @@ export function makeBinOp(
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all nodes with type in the tree. This traverses the tree so it is safe only when you know there shouldn't be
|
||||
* too much nesting but you just want to skip some of the wrappers. For example getting function args this way would
|
||||
* not be safe is it would also find arguments of nested functions.
|
||||
* @param expr
|
||||
* @param cur
|
||||
* @param type
|
||||
*/
|
||||
export function getAllByType(expr: string, cur: SyntaxNode, type: string): string[] {
|
||||
if (cur.name === type) {
|
||||
return [getString(expr, cur)];
|
||||
}
|
||||
const values: string[] = [];
|
||||
let pos = 0;
|
||||
let child = cur.childAfter(pos);
|
||||
while (child) {
|
||||
values.push(...getAllByType(expr, child, type));
|
||||
pos = child.to;
|
||||
child = cur.childAfter(pos);
|
||||
}
|
||||
return values;
|
||||
}
|
||||
|
||||
// Debugging function for convenience. Gives you nice output similar to linux tree util.
|
||||
// @ts-ignore
|
||||
export function log(expr: string, cur?: SyntaxNode) {
|
||||
|
Loading…
Reference in New Issue
Block a user