mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
Prometheus: Remove the auto range vector option (#45715)
* Prometheus: Remove auto range option * Prometheus: Remove auto range option * Overhaul of range vector operations and default param * Make sure label is string
This commit is contained in:
parent
9d61dcb02b
commit
f7291ce270
@ -134,7 +134,7 @@ function createRangeOperation(name: string): QueryBuilderOperationDef {
|
||||
id: name,
|
||||
name: getPromAndLokiOperationDisplayName(name),
|
||||
params: [getRangeVectorParamDef()],
|
||||
defaultParams: ['auto'],
|
||||
defaultParams: ['$__interval'],
|
||||
alternativesKey: 'range function',
|
||||
category: LokiVisualQueryOperationCategory.RangeFunctions,
|
||||
renderer: operationWithRangeVectorRenderer,
|
||||
@ -142,7 +142,7 @@ function createRangeOperation(name: string): QueryBuilderOperationDef {
|
||||
explainHandler: (op, def) => {
|
||||
let opDocs = FUNCTIONS.find((x) => x.insertText === op.id)?.documentation ?? '';
|
||||
|
||||
if (op.params[0] === 'auto' || op.params[0] === '$__interval') {
|
||||
if (op.params[0] === '$__interval') {
|
||||
return `${opDocs} \`$__interval\` is variable that will be replaced with a calculated interval based on **Max data points**, **Min interval** and query time range. You find these options you find under **Query options** at the right of the data source select dropdown.`;
|
||||
} else {
|
||||
return `${opDocs} The [range vector](https://grafana.com/docs/loki/latest/logql/metric_queries/#range-vector-aggregation) is set to \`${op.params[0]}\`.`;
|
||||
@ -170,9 +170,9 @@ function createAggregationOperation(name: string): QueryBuilderOperationDef {
|
||||
|
||||
function getRangeVectorParamDef(): QueryBuilderOperationParamDef {
|
||||
return {
|
||||
name: 'Range vector',
|
||||
name: 'Range',
|
||||
type: 'string',
|
||||
options: ['auto', '$__interval', '$__range', '1m', '5m', '10m', '1h', '24h'],
|
||||
options: ['$__interval', '$__range', '1m', '5m', '10m', '1h', '24h'],
|
||||
};
|
||||
}
|
||||
|
||||
@ -181,12 +181,7 @@ function operationWithRangeVectorRenderer(
|
||||
def: QueryBuilderOperationDef,
|
||||
innerExpr: string
|
||||
) {
|
||||
let rangeVector = (model.params ?? [])[0] ?? 'auto';
|
||||
|
||||
if (rangeVector === 'auto') {
|
||||
rangeVector = '$__interval';
|
||||
}
|
||||
|
||||
let rangeVector = (model.params ?? [])[0] ?? '$__interval';
|
||||
return `${def.id}(${innerExpr} [${rangeVector}])`;
|
||||
}
|
||||
|
||||
|
@ -105,7 +105,7 @@ describe('PromQueryModeller', () => {
|
||||
modeller.renderQuery({
|
||||
metric: 'metric',
|
||||
labels: [{ label: 'pod', op: '=', value: 'A' }],
|
||||
operations: [{ id: PromOperationId.Rate, params: ['auto'] }],
|
||||
operations: [{ id: PromOperationId.Rate, params: ['$__rate_interval'] }],
|
||||
})
|
||||
).toBe('rate(metric{pod="A"}[$__rate_interval])');
|
||||
});
|
||||
@ -115,9 +115,9 @@ describe('PromQueryModeller', () => {
|
||||
modeller.renderQuery({
|
||||
metric: 'metric',
|
||||
labels: [{ label: 'pod', op: '=', value: 'A' }],
|
||||
operations: [{ id: PromOperationId.Increase, params: ['auto'] }],
|
||||
operations: [{ id: PromOperationId.Increase, params: ['$__interval'] }],
|
||||
})
|
||||
).toBe('increase(metric{pod="A"}[$__rate_interval])');
|
||||
).toBe('increase(metric{pod="A"}[$__interval])');
|
||||
});
|
||||
|
||||
it('Can render rate with custom range-vector', () => {
|
||||
@ -283,18 +283,18 @@ describe('PromQueryModeller', () => {
|
||||
modeller.renderQuery({
|
||||
metric: 'metric_a',
|
||||
labels: [],
|
||||
operations: [{ id: 'holt_winters', params: ['auto', 0.5, 0.5] }],
|
||||
operations: [{ id: 'holt_winters', params: ['5m', 0.5, 0.5] }],
|
||||
})
|
||||
).toBe('holt_winters(metric_a[$__rate_interval], 0.5, 0.5)');
|
||||
).toBe('holt_winters(metric_a[5m], 0.5, 0.5)');
|
||||
});
|
||||
it('Can render functions that require parameters left of a range', () => {
|
||||
expect(
|
||||
modeller.renderQuery({
|
||||
metric: 'metric_a',
|
||||
labels: [],
|
||||
operations: [{ id: 'quantile_over_time', params: ['auto', 1] }],
|
||||
operations: [{ id: 'quantile_over_time', params: ['5m', 1] }],
|
||||
})
|
||||
).toBe('quantile_over_time(1, metric_a[$__rate_interval])');
|
||||
).toBe('quantile_over_time(1, metric_a[5m])');
|
||||
});
|
||||
it('Can render the label_join function', () => {
|
||||
expect(
|
||||
|
@ -5,6 +5,7 @@ import {
|
||||
defaultAddOperationHandler,
|
||||
functionRendererLeft,
|
||||
getPromAndLokiOperationDisplayName,
|
||||
getRangeVectorParamDef,
|
||||
} from './shared/operationUtils';
|
||||
import { QueryBuilderOperation, QueryBuilderOperationDef, QueryBuilderOperationParamDef } from './shared/types';
|
||||
import { PromVisualQueryOperationCategory, PromOperationId } from './types';
|
||||
@ -25,6 +26,7 @@ export function getAggregationOperations(): QueryBuilderOperationDef[] {
|
||||
createAggregationOverTime(PromOperationId.CountOverTime),
|
||||
createAggregationOverTime(PromOperationId.LastOverTime),
|
||||
createAggregationOverTime(PromOperationId.PresentOverTime),
|
||||
createAggregationOverTime(PromOperationId.AbsentOverTime),
|
||||
createAggregationOverTime(PromOperationId.StddevOverTime),
|
||||
];
|
||||
}
|
||||
@ -175,8 +177,8 @@ function createAggregationOverTime(name: string): QueryBuilderOperationDef {
|
||||
return {
|
||||
id: name,
|
||||
name: getPromAndLokiOperationDisplayName(name),
|
||||
params: [getAggregationOverTimeRangeVector()],
|
||||
defaultParams: ['auto'],
|
||||
params: [getRangeVectorParamDef()],
|
||||
defaultParams: ['$__interval'],
|
||||
alternativesKey: 'overtime function',
|
||||
category: PromVisualQueryOperationCategory.RangeFunctions,
|
||||
renderer: operationWithRangeVectorRenderer,
|
||||
@ -184,24 +186,11 @@ function createAggregationOverTime(name: string): QueryBuilderOperationDef {
|
||||
};
|
||||
}
|
||||
|
||||
function getAggregationOverTimeRangeVector(): QueryBuilderOperationParamDef {
|
||||
return {
|
||||
name: 'Range vector',
|
||||
type: 'string',
|
||||
options: ['auto', '$__interval', '$__range', '1m', '5m', '10m', '1h', '24h'],
|
||||
};
|
||||
}
|
||||
|
||||
function operationWithRangeVectorRenderer(
|
||||
model: QueryBuilderOperation,
|
||||
def: QueryBuilderOperationDef,
|
||||
innerExpr: string
|
||||
) {
|
||||
let rangeVector = (model.params ?? [])[0] ?? 'auto';
|
||||
|
||||
if (rangeVector === 'auto') {
|
||||
rangeVector = '$__interval';
|
||||
}
|
||||
|
||||
let rangeVector = (model.params ?? [])[0] ?? '$__interval';
|
||||
return `${def.id}(${innerExpr}[${rangeVector}])`;
|
||||
}
|
||||
|
@ -4,13 +4,13 @@ import {
|
||||
functionRendererLeft,
|
||||
functionRendererRight,
|
||||
getPromAndLokiOperationDisplayName,
|
||||
getRangeVectorParamDef,
|
||||
rangeRendererLeftWithParams,
|
||||
rangeRendererRightWithParams,
|
||||
} from './shared/operationUtils';
|
||||
import {
|
||||
QueryBuilderOperation,
|
||||
QueryBuilderOperationDef,
|
||||
QueryBuilderOperationParamDef,
|
||||
QueryWithOperations,
|
||||
VisualQueryModeller,
|
||||
} from './shared/types';
|
||||
@ -51,10 +51,45 @@ export function getOperationDefinitions(): QueryBuilderOperationDef[] {
|
||||
addOperationHandler: defaultAddOperationHandler,
|
||||
},
|
||||
createRangeFunction(PromOperationId.Changes),
|
||||
createRangeFunction(PromOperationId.Rate),
|
||||
createRangeFunction(PromOperationId.Rate, true),
|
||||
createRangeFunction(PromOperationId.Irate),
|
||||
createRangeFunction(PromOperationId.Increase),
|
||||
createRangeFunction(PromOperationId.Increase, true),
|
||||
createRangeFunction(PromOperationId.Idelta),
|
||||
createRangeFunction(PromOperationId.Delta),
|
||||
createFunction({
|
||||
id: PromOperationId.HoltWinters,
|
||||
params: [
|
||||
getRangeVectorParamDef(),
|
||||
{ name: 'Smoothing Factor', type: 'number' },
|
||||
{ name: 'Trend Factor', type: 'number' },
|
||||
],
|
||||
defaultParams: ['$__interval', 0.5, 0.5],
|
||||
alternativesKey: 'range function',
|
||||
category: PromVisualQueryOperationCategory.RangeFunctions,
|
||||
renderer: rangeRendererRightWithParams,
|
||||
addOperationHandler: addOperationWithRangeVector,
|
||||
changeTypeHandler: operationTypeChangedHandlerForRangeFunction,
|
||||
}),
|
||||
createFunction({
|
||||
id: PromOperationId.PredictLinear,
|
||||
params: [getRangeVectorParamDef(), { name: 'Seconds from now', type: 'number' }],
|
||||
defaultParams: ['$__interval', 60],
|
||||
alternativesKey: 'range function',
|
||||
category: PromVisualQueryOperationCategory.RangeFunctions,
|
||||
renderer: rangeRendererRightWithParams,
|
||||
addOperationHandler: addOperationWithRangeVector,
|
||||
changeTypeHandler: operationTypeChangedHandlerForRangeFunction,
|
||||
}),
|
||||
createFunction({
|
||||
id: PromOperationId.QuantileOverTime,
|
||||
params: [getRangeVectorParamDef(), { name: 'Quantile', type: 'number' }],
|
||||
defaultParams: ['$__interval', 0.5],
|
||||
alternativesKey: 'overtime function',
|
||||
category: PromVisualQueryOperationCategory.RangeFunctions,
|
||||
renderer: rangeRendererLeftWithParams,
|
||||
addOperationHandler: addOperationWithRangeVector,
|
||||
changeTypeHandler: operationTypeChangedHandlerForRangeFunction,
|
||||
}),
|
||||
// Not sure about this one. It could also be a more generic 'Simple math operation' where user specifies
|
||||
// both the operator and the operand in a single input
|
||||
{
|
||||
@ -85,7 +120,6 @@ export function getOperationDefinitions(): QueryBuilderOperationDef[] {
|
||||
addOperationHandler: addNestedQueryHandler,
|
||||
},
|
||||
createFunction({ id: PromOperationId.Absent }),
|
||||
createRangeFunction(PromOperationId.AbsentOverTime),
|
||||
createFunction({
|
||||
id: PromOperationId.Acos,
|
||||
category: PromVisualQueryOperationCategory.Trigonometric,
|
||||
@ -163,20 +197,7 @@ export function getOperationDefinitions(): QueryBuilderOperationDef[] {
|
||||
createFunction({ id: PromOperationId.Exp }),
|
||||
createFunction({ id: PromOperationId.Floor }),
|
||||
createFunction({ id: PromOperationId.Group }),
|
||||
createFunction({
|
||||
id: PromOperationId.HoltWinters,
|
||||
params: [
|
||||
getRangeVectorParamDef(),
|
||||
{ name: 'Smoothing Factor', type: 'number' },
|
||||
{ name: 'Trend Factor', type: 'number' },
|
||||
],
|
||||
defaultParams: ['auto', 0.5, 0.5],
|
||||
alternativesKey: 'range function',
|
||||
category: PromVisualQueryOperationCategory.RangeFunctions,
|
||||
renderer: rangeRendererRightWithParams,
|
||||
}),
|
||||
createFunction({ id: PromOperationId.Hour }),
|
||||
createRangeFunction(PromOperationId.Idelta),
|
||||
createFunction({
|
||||
id: PromOperationId.LabelJoin,
|
||||
params: [
|
||||
@ -209,28 +230,12 @@ export function getOperationDefinitions(): QueryBuilderOperationDef[] {
|
||||
id: PromOperationId.Pi,
|
||||
renderer: (model) => `${model.id}()`,
|
||||
}),
|
||||
createFunction({
|
||||
id: PromOperationId.PredictLinear,
|
||||
params: [getRangeVectorParamDef(), { name: 'Seconds from now', type: 'number' }],
|
||||
defaultParams: ['auto', 60],
|
||||
alternativesKey: 'range function',
|
||||
category: PromVisualQueryOperationCategory.RangeFunctions,
|
||||
renderer: rangeRendererRightWithParams,
|
||||
}),
|
||||
createFunction({
|
||||
id: PromOperationId.Quantile,
|
||||
params: [{ name: 'Value', type: 'number' }],
|
||||
defaultParams: [1],
|
||||
renderer: functionRendererLeft,
|
||||
}),
|
||||
createFunction({
|
||||
id: PromOperationId.QuantileOverTime,
|
||||
params: [getRangeVectorParamDef(), { name: 'Quantile', type: 'number' }],
|
||||
defaultParams: ['auto', 0.5],
|
||||
alternativesKey: 'range function',
|
||||
category: PromVisualQueryOperationCategory.RangeFunctions,
|
||||
renderer: rangeRendererLeftWithParams,
|
||||
}),
|
||||
createFunction({ id: PromOperationId.Rad }),
|
||||
createRangeFunction(PromOperationId.Resets),
|
||||
createFunction({
|
||||
@ -288,30 +293,40 @@ export function createFunction(definition: Partial<QueryBuilderOperationDef>): Q
|
||||
};
|
||||
}
|
||||
|
||||
export function createRangeFunction(name: string): QueryBuilderOperationDef {
|
||||
export function createRangeFunction(name: string, withRateInterval = false): QueryBuilderOperationDef {
|
||||
return {
|
||||
id: name,
|
||||
name: getPromAndLokiOperationDisplayName(name),
|
||||
params: [getRangeVectorParamDef()],
|
||||
defaultParams: ['auto'],
|
||||
params: [getRangeVectorParamDef(withRateInterval)],
|
||||
defaultParams: [withRateInterval ? '$__rate_interval' : '$__interval'],
|
||||
alternativesKey: 'range function',
|
||||
category: PromVisualQueryOperationCategory.RangeFunctions,
|
||||
renderer: operationWithRangeVectorRenderer,
|
||||
addOperationHandler: addOperationWithRangeVector,
|
||||
changeTypeHandler: operationTypeChangedHandlerForRangeFunction,
|
||||
};
|
||||
}
|
||||
|
||||
function operationTypeChangedHandlerForRangeFunction(
|
||||
operation: QueryBuilderOperation,
|
||||
newDef: QueryBuilderOperationDef
|
||||
) {
|
||||
// validate current parameter
|
||||
if (operation.params[0] === '$__rate_interval' && newDef.defaultParams[0] !== '$__rate_interval') {
|
||||
operation.params = newDef.defaultParams;
|
||||
} else if (operation.params[0] === '$__interval' && newDef.defaultParams[0] !== '$__interval') {
|
||||
operation.params = newDef.defaultParams;
|
||||
}
|
||||
|
||||
return operation;
|
||||
}
|
||||
|
||||
export function operationWithRangeVectorRenderer(
|
||||
model: QueryBuilderOperation,
|
||||
def: QueryBuilderOperationDef,
|
||||
innerExpr: string
|
||||
) {
|
||||
let rangeVector = (model.params ?? [])[0] ?? 'auto';
|
||||
|
||||
if (rangeVector === 'auto') {
|
||||
rangeVector = '$__rate_interval';
|
||||
}
|
||||
|
||||
let rangeVector = (model.params ?? [])[0] ?? '5m';
|
||||
return `${def.id}(${innerExpr}[${rangeVector}])`;
|
||||
}
|
||||
|
||||
@ -321,14 +336,6 @@ function getSimpleBinaryRenderer(operator: string) {
|
||||
};
|
||||
}
|
||||
|
||||
function getRangeVectorParamDef(): QueryBuilderOperationParamDef {
|
||||
return {
|
||||
name: 'Range vector',
|
||||
type: 'string',
|
||||
options: ['auto', '$__rate_interval', '$__interval', '$__range', '1m', '5m', '10m', '1h', '24h'],
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Since there can only be one operation with range vector this will replace the current one (if one was added )
|
||||
*/
|
||||
@ -337,28 +344,22 @@ export function addOperationWithRangeVector(
|
||||
query: PromVisualQuery,
|
||||
modeller: VisualQueryModeller
|
||||
) {
|
||||
const newOperation: QueryBuilderOperation = {
|
||||
id: def.id,
|
||||
params: def.defaultParams,
|
||||
};
|
||||
|
||||
if (query.operations.length > 0) {
|
||||
const firstOp = modeller.getOperationDef(query.operations[0].id);
|
||||
|
||||
if (firstOp.addOperationHandler === addOperationWithRangeVector) {
|
||||
return {
|
||||
...query,
|
||||
operations: [
|
||||
{
|
||||
...query.operations[0],
|
||||
id: def.id,
|
||||
},
|
||||
...query.operations.slice(1),
|
||||
],
|
||||
operations: [newOperation, ...query.operations.slice(1)],
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
const newOperation: QueryBuilderOperation = {
|
||||
id: def.id,
|
||||
params: def.defaultParams,
|
||||
};
|
||||
|
||||
return {
|
||||
...query,
|
||||
operations: [newOperation, ...query.operations],
|
||||
|
@ -60,10 +60,9 @@ export const OperationName = React.memo<Props>(({ operation, def, index, onChang
|
||||
onCloseMenu={onToggleSwitcher}
|
||||
onChange={(value) => {
|
||||
if (value.value) {
|
||||
onChange(index, {
|
||||
...operation,
|
||||
id: value.value.id,
|
||||
});
|
||||
const newDef = queryModeller.getOperationDef(value.value.id);
|
||||
let changedOp = { ...operation, id: value.value.id };
|
||||
onChange(index, def.changeTypeHandler ? def.changeTypeHandler(changedOp, newDef) : changedOp);
|
||||
}
|
||||
}}
|
||||
/>
|
||||
|
@ -1,4 +1,4 @@
|
||||
import { toOption } from '@grafana/data';
|
||||
import { SelectableValue, toOption } from '@grafana/data';
|
||||
import { Input, Select } from '@grafana/ui';
|
||||
import React, { ComponentType } from 'react';
|
||||
import { QueryBuilderOperationParamDef, QueryBuilderOperationParamEditorProps } from '../shared/types';
|
||||
@ -45,16 +45,22 @@ function SelectInputParamEditor({
|
||||
operationIndex,
|
||||
onChange,
|
||||
}: QueryBuilderOperationParamEditorProps) {
|
||||
const selectOptions = paramDef.options!.map((option) => ({
|
||||
label: option as string,
|
||||
value: option as string,
|
||||
}));
|
||||
let selectOptions = paramDef.options as Array<SelectableValue<any>>;
|
||||
|
||||
if (!selectOptions[0]?.label) {
|
||||
selectOptions = paramDef.options!.map((option) => ({
|
||||
label: option.toString(),
|
||||
value: option as string,
|
||||
}));
|
||||
}
|
||||
|
||||
let valueOption = selectOptions.find((x) => x.value === value) ?? toOption(value as string);
|
||||
|
||||
return (
|
||||
<Select
|
||||
id={getOperationParamId(operationIndex, index)}
|
||||
menuShouldPortal
|
||||
value={toOption(value as string)}
|
||||
value={valueOption}
|
||||
options={selectOptions}
|
||||
onChange={(value) => onChange(index, value.value!)}
|
||||
/>
|
||||
|
@ -1,5 +1,10 @@
|
||||
import { capitalize } from 'lodash';
|
||||
import { QueryBuilderOperation, QueryBuilderOperationDef, QueryWithOperations } from './types';
|
||||
import {
|
||||
QueryBuilderOperation,
|
||||
QueryBuilderOperationDef,
|
||||
QueryBuilderOperationParamDef,
|
||||
QueryWithOperations,
|
||||
} from './types';
|
||||
|
||||
export function functionRendererLeft(model: QueryBuilderOperation, def: QueryBuilderOperationDef, innerExpr: string) {
|
||||
const params = renderParams(model, def, innerExpr);
|
||||
@ -33,12 +38,7 @@ function rangeRendererWithParams(
|
||||
throw `Cannot render a function with params of length [${def.params.length}]`;
|
||||
}
|
||||
|
||||
// First, make sure the first parameter (that is the range vector) is translated if the user selected 'auto'
|
||||
let rangeVector = (model.params ?? [])[0] ?? 'auto';
|
||||
|
||||
if (rangeVector === 'auto') {
|
||||
rangeVector = '$__rate_interval';
|
||||
}
|
||||
let rangeVector = (model.params ?? [])[0] ?? '5m';
|
||||
|
||||
// Next frame the remaining parameters, but get rid of the first one because it's used to move the
|
||||
// instant vector into a range vector.
|
||||
@ -114,3 +114,32 @@ export function getPromAndLokiOperationDisplayName(funcName: string) {
|
||||
export function getOperationParamId(operationIndex: number, paramIndex: number) {
|
||||
return `operations.${operationIndex}.param.${paramIndex}`;
|
||||
}
|
||||
|
||||
export function getRangeVectorParamDef(withRateInterval = false): QueryBuilderOperationParamDef {
|
||||
const param = {
|
||||
name: 'Range',
|
||||
type: 'string',
|
||||
options: [
|
||||
{
|
||||
label: '$__interval',
|
||||
value: '$__interval',
|
||||
// tooltip: 'Dynamic interval based on max data points, scrape and min interval',
|
||||
},
|
||||
{ label: '1m', value: '1m' },
|
||||
{ label: '5m', value: '5m' },
|
||||
{ label: '10m', value: '10m' },
|
||||
{ label: '1h', value: '1h' },
|
||||
{ label: '24h', value: '24h' },
|
||||
],
|
||||
};
|
||||
|
||||
if (withRateInterval) {
|
||||
param.options.unshift({
|
||||
label: '$__rate_interval',
|
||||
value: '$__rate_interval',
|
||||
// tooltip: 'Always above 4x scrape interval',
|
||||
});
|
||||
}
|
||||
|
||||
return param;
|
||||
}
|
||||
|
@ -31,6 +31,7 @@ export interface QueryBuilderOperationDef<T = any> extends RegistryItem {
|
||||
addOperationHandler: QueryBuilderAddOperationHandler<T>;
|
||||
paramChangedHandler?: QueryBuilderOnParamChangedHandler;
|
||||
explainHandler?: (op: QueryBuilderOperation, def: QueryBuilderOperationDef<T>) => string;
|
||||
changeTypeHandler?: (op: QueryBuilderOperation, newDef: QueryBuilderOperationDef<T>) => QueryBuilderOperation;
|
||||
}
|
||||
|
||||
export type QueryBuilderAddOperationHandler<T> = (
|
||||
|
Loading…
Reference in New Issue
Block a user