mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
prometheus: query field: better handle label-values with unusual characters (#41457)
This commit is contained in:
parent
16578b0af0
commit
5c40865547
@ -2,6 +2,7 @@ import type { Situation, Label } from './situation';
|
|||||||
import { NeverCaseError } from './util';
|
import { NeverCaseError } from './util';
|
||||||
// FIXME: we should not load this from the "outside", but we cannot do that while we have the "old" query-field too
|
// FIXME: we should not load this from the "outside", but we cannot do that while we have the "old" query-field too
|
||||||
import { FUNCTIONS } from '../../../promql';
|
import { FUNCTIONS } from '../../../promql';
|
||||||
|
import { escapeLabelValueInExactSelector } from '../../../language_utils';
|
||||||
|
|
||||||
export type CompletionType = 'HISTORY' | 'FUNCTION' | 'METRIC_NAME' | 'DURATION' | 'LABEL_NAME' | 'LABEL_VALUE';
|
export type CompletionType = 'HISTORY' | 'FUNCTION' | 'METRIC_NAME' | 'DURATION' | 'LABEL_NAME' | 'LABEL_VALUE';
|
||||||
|
|
||||||
@ -90,7 +91,9 @@ function makeSelector(metricName: string | undefined, labels: Label[]): string {
|
|||||||
allLabels.push({ name: '__name__', value: metricName, op: '=' });
|
allLabels.push({ name: '__name__', value: metricName, op: '=' });
|
||||||
}
|
}
|
||||||
|
|
||||||
const allLabelTexts = allLabels.map((label) => `${label.name}${label.op}"${label.value}"`);
|
const allLabelTexts = allLabels.map(
|
||||||
|
(label) => `${label.name}${label.op}"${escapeLabelValueInExactSelector(label.value)}"`
|
||||||
|
);
|
||||||
|
|
||||||
return `{${allLabelTexts.join(',')}}`;
|
return `{${allLabelTexts.join(',')}}`;
|
||||||
}
|
}
|
||||||
|
@ -89,6 +89,24 @@ describe('situation', () => {
|
|||||||
type: 'IN_LABEL_SELECTOR_NO_LABEL_NAME',
|
type: 'IN_LABEL_SELECTOR_NO_LABEL_NAME',
|
||||||
otherLabels: [{ name: 'one', value: 'val1', op: '=' }],
|
otherLabels: [{ name: 'one', value: 'val1', op: '=' }],
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// single-quoted label-values with escape
|
||||||
|
assertSituation("{one='val\\'1',^}", {
|
||||||
|
type: 'IN_LABEL_SELECTOR_NO_LABEL_NAME',
|
||||||
|
otherLabels: [{ name: 'one', value: "val'1", op: '=' }],
|
||||||
|
});
|
||||||
|
|
||||||
|
// double-quoted label-values with escape
|
||||||
|
assertSituation('{one="val\\"1",^}', {
|
||||||
|
type: 'IN_LABEL_SELECTOR_NO_LABEL_NAME',
|
||||||
|
otherLabels: [{ name: 'one', value: 'val"1', op: '=' }],
|
||||||
|
});
|
||||||
|
|
||||||
|
// backticked label-values with escape (the escape should not be interpreted)
|
||||||
|
assertSituation('{one=`val\\"1`,^}', {
|
||||||
|
type: 'IN_LABEL_SELECTOR_NO_LABEL_NAME',
|
||||||
|
otherLabels: [{ name: 'one', value: 'val\\"1', op: '=' }],
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it('handles label values', () => {
|
it('handles label values', () => {
|
||||||
|
@ -63,17 +63,34 @@ function getNodeText(node: SyntaxNode, text: string): string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function parsePromQLStringLiteral(text: string): string {
|
function parsePromQLStringLiteral(text: string): string {
|
||||||
|
// if it is a string-literal, it is inside quotes of some kind
|
||||||
|
const inside = text.slice(1, text.length - 1);
|
||||||
|
|
||||||
// FIXME: support https://prometheus.io/docs/prometheus/latest/querying/basics/#string-literals
|
// FIXME: support https://prometheus.io/docs/prometheus/latest/querying/basics/#string-literals
|
||||||
// FIXME: maybe check other promql code, if all is supported or not
|
// FIXME: maybe check other promql code, if all is supported or not
|
||||||
|
|
||||||
|
// for now we do only some very simple un-escaping
|
||||||
|
|
||||||
// we start with double-quotes
|
// we start with double-quotes
|
||||||
if (text.startsWith('"') && text.endsWith('"')) {
|
if (text.startsWith('"') && text.endsWith('"')) {
|
||||||
if (text.indexOf('\\') !== -1) {
|
// NOTE: this is not 100% perfect, we only unescape the double-quote,
|
||||||
throw new Error('FIXME: escape-sequences not supported in label-values');
|
// there might be other characters too
|
||||||
}
|
return inside.replace(/\\"/, '"');
|
||||||
return text.slice(1, text.length - 1);
|
|
||||||
} else {
|
|
||||||
throw new Error('FIXME: invalid string literal');
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// then single-quote
|
||||||
|
if (text.startsWith("'") && text.endsWith("'")) {
|
||||||
|
// NOTE: this is not 100% perfect, we only unescape the single-quote,
|
||||||
|
// there might be other characters too
|
||||||
|
return inside.replace(/\\'/, "'");
|
||||||
|
}
|
||||||
|
|
||||||
|
// then backticks
|
||||||
|
if (text.startsWith('`') && text.endsWith('`')) {
|
||||||
|
return inside;
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new Error('FIXME: invalid string literal');
|
||||||
}
|
}
|
||||||
|
|
||||||
type LabelOperator = '=' | '!=' | '=~' | '!~';
|
type LabelOperator = '=' | '!=' | '=~' | '!~';
|
||||||
|
Loading…
Reference in New Issue
Block a user