Prometheus: Support with aggregations without labels (#45160)

This commit is contained in:
Torkel Ödegaard 2022-02-10 11:48:48 +01:00 committed by GitHub
parent 14c639fdb5
commit 68eb18c758
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 75 additions and 4 deletions

View File

@ -80,6 +80,16 @@ describe('PromQueryModeller', () => {
).toBe('avg(sum by(server, job) (metric))');
});
it('Can use aggregation without label', () => {
expect(
modeller.renderQuery({
metric: 'metric',
labels: [],
operations: [{ id: '__sum_without', params: ['server', 'job'] }],
})
).toBe('sum without(server, job) (metric)');
});
it('Can render aggregations with parameters', () => {
expect(
modeller.renderQuery({

View File

@ -67,7 +67,28 @@ function createAggregationOperation(name: string): QueryBuilderOperationDef[] {
renderer: getAggregationByRenderer(name),
addOperationHandler: defaultAddOperationHandler,
paramChangedHandler: getLastLabelRemovedHandler(name),
explainHandler: getAggregationExplainer(name),
explainHandler: getAggregationExplainer(name, 'by'),
hideFromList: true,
},
{
id: `__${name}_without`,
name: `${getPromAndLokiOperationDisplayName(name)} without`,
params: [
{
name: 'Label',
type: 'string',
restParam: true,
optional: true,
editor: LabelParamEditor,
},
],
defaultParams: [''],
alternativesKey: 'aggregations by',
category: PromVisualQueryOperationCategory.Aggregations,
renderer: getAggregationWithoutRenderer(name),
addOperationHandler: defaultAddOperationHandler,
paramChangedHandler: getLastLabelRemovedHandler(name),
explainHandler: getAggregationExplainer(name, 'without'),
hideFromList: true,
},
];
@ -94,14 +115,24 @@ function getAggregationByRenderer(aggregation: string) {
};
}
function getAggregationWithoutRenderer(aggregation: string) {
return function aggregationRenderer(model: QueryBuilderOperation, def: QueryBuilderOperationDef, innerExpr: string) {
return `${aggregation} without(${model.params.join(', ')}) (${innerExpr})`;
};
}
/**
* Very simple poc implementation, needs to be modified to support all aggregation operators
*/
function getAggregationExplainer(aggregationName: string) {
function getAggregationExplainer(aggregationName: string, mode: 'by' | 'without') {
return function aggregationExplainer(model: QueryBuilderOperation) {
const labels = model.params.map((label) => `\`${label}\``).join(' and ');
const labelWord = pluralize('label', model.params.length);
return `Calculates ${aggregationName} over dimensions while preserving ${labelWord} ${labels}.`;
if (mode === 'by') {
return `Calculates ${aggregationName} over dimensions while preserving ${labelWord} ${labels}.`;
} else {
return `Calculates ${aggregationName} over the dimensions ${labels}. All other labels are preserved.`;
}
};
}

View File

@ -93,6 +93,31 @@ describe('buildVisualQueryFromString', () => {
);
});
it('parses query with aggregation without labels', () => {
const visQuery = {
metric: 'metric_name',
labels: [
{
label: 'instance',
op: '=',
value: 'internal:3000',
},
],
operations: [
{
id: '__sum_without',
params: ['app', 'version'],
},
],
};
expect(buildVisualQueryFromString('sum(metric_name{instance="internal:3000"}) without (app, version)')).toEqual(
noErrors(visQuery)
);
expect(buildVisualQueryFromString('sum without (app, version)(metric_name{instance="internal:3000"})')).toEqual(
noErrors(visQuery)
);
});
it('parses aggregation with params', () => {
expect(buildVisualQueryFromString('topk(5, http_requests_total)')).toEqual(
noErrors({

View File

@ -233,12 +233,17 @@ function handleAggregation(expr: string, node: SyntaxNode, context: Context) {
const modifier = node.getChild('AggregateModifier');
const labels = [];
// TODO: support also Without modifier (but we don't support it in visual query yet)
if (modifier) {
const byModifier = modifier.getChild(`By`);
if (byModifier && funcName) {
funcName = `__${funcName}_by`;
}
const withoutModifier = modifier.getChild(`Without`);
if (withoutModifier) {
funcName = `__${funcName}_without`;
}
labels.push(...getAllByType(expr, modifier, 'GroupingLabel'));
}