From 91da1bbb79586466495b11a31825b784cabb094c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?G=C3=A1bor=20Farkas?= Date: Wed, 3 Nov 2021 11:20:04 +0100 Subject: [PATCH] prometheus: monaco: allow listing label names + values without a metric (#41233) * prometheus: monaco: allow listing label names + values without a metric * removed comment --- .../monaco-query-field/MonacoQueryField.tsx | 6 ++- .../monaco-completion-provider/completions.ts | 45 +++++++++++++++---- 2 files changed, 42 insertions(+), 9 deletions(-) diff --git a/public/app/plugins/datasource/prometheus/components/monaco-query-field/MonacoQueryField.tsx b/public/app/plugins/datasource/prometheus/components/monaco-query-field/MonacoQueryField.tsx index f62b079a35b..24989fa9ab7 100644 --- a/public/app/plugins/datasource/prometheus/components/monaco-query-field/MonacoQueryField.tsx +++ b/public/app/plugins/datasource/prometheus/components/monaco-query-field/MonacoQueryField.tsx @@ -138,7 +138,11 @@ const MonacoQueryField = (props: Props) => { return Promise.resolve(result); }; - const dataProvider = { getSeries, getHistory, getAllMetricNames }; + const getAllLabelNames = () => Promise.resolve(lpRef.current.getLabelKeys()); + + const getLabelValues = (labelName: string) => lpRef.current.getLabelValues(labelName); + + const dataProvider = { getSeries, getHistory, getAllMetricNames, getAllLabelNames, getLabelValues }; const completionProvider = getCompletionProvider(monaco, dataProvider); // completion-providers in monaco are not registered directly to editor-instances, diff --git a/public/app/plugins/datasource/prometheus/components/monaco-query-field/monaco-completion-provider/completions.ts b/public/app/plugins/datasource/prometheus/components/monaco-query-field/monaco-completion-provider/completions.ts index add020ebb4e..9d1b9394fbe 100644 --- a/public/app/plugins/datasource/prometheus/components/monaco-query-field/monaco-completion-provider/completions.ts +++ b/public/app/plugins/datasource/prometheus/components/monaco-query-field/monaco-completion-provider/completions.ts @@ -23,6 +23,8 @@ type Metric = { export type DataProvider = { getHistory: () => Promise; getAllMetricNames: () => Promise; + getAllLabelNames: () => Promise; + getLabelValues: (labelName: string) => Promise; getSeries: (selector: string) => Promise>; }; @@ -93,6 +95,23 @@ function makeSelector(metricName: string | undefined, labels: Label[]): string { return `{${allLabelTexts.join(',')}}`; } +async function getLabelNames( + metric: string | undefined, + otherLabels: Label[], + dataProvider: DataProvider +): Promise { + if (metric === undefined && otherLabels.length === 0) { + // if there is no filtering, we have to use a special endpoint + return dataProvider.getAllLabelNames(); + } else { + const selector = makeSelector(metric, otherLabels); + const data = await dataProvider.getSeries(selector); + const possibleLabelNames = Object.keys(data); // all names from prometheus + const usedLabelNames = new Set(otherLabels.map((l) => l.name)); // names used in the query + return possibleLabelNames.filter((l) => !usedLabelNames.has(l)); + } +} + async function getLabelNamesForCompletions( metric: string | undefined, suffix: string, @@ -100,11 +119,7 @@ async function getLabelNamesForCompletions( otherLabels: Label[], dataProvider: DataProvider ): Promise { - const selector = makeSelector(metric, otherLabels); - const data = await dataProvider.getSeries(selector); - const possibleLabelNames = Object.keys(data); // all names from prometheus - const usedLabelNames = new Set(otherLabels.map((l) => l.name)); // names used in the query - const labelNames = possibleLabelNames.filter((l) => !usedLabelNames.has(l)); + const labelNames = await getLabelNames(metric, otherLabels, dataProvider); return labelNames.map((text) => ({ type: 'LABEL_NAME', label: text, @@ -128,15 +143,29 @@ async function getLabelNamesForByCompletions( return getLabelNamesForCompletions(metric, '', false, otherLabels, dataProvider); } +async function getLabelValues( + metric: string | undefined, + labelName: string, + otherLabels: Label[], + dataProvider: DataProvider +): Promise { + if (metric === undefined && otherLabels.length === 0) { + // if there is no filtering, we have to use a special endpoint + return dataProvider.getLabelValues(labelName); + } else { + const selector = makeSelector(metric, otherLabels); + const data = await dataProvider.getSeries(selector); + return data[labelName] ?? []; + } +} + async function getLabelValuesForMetricCompletions( metric: string | undefined, labelName: string, otherLabels: Label[], dataProvider: DataProvider ): Promise { - const selector = makeSelector(metric, otherLabels); - const data = await dataProvider.getSeries(selector); - const values = data[labelName] ?? []; + const values = await getLabelValues(metric, labelName, otherLabels, dataProvider); return values.map((text) => ({ type: 'LABEL_VALUE', label: text,