From 17ad7af3b883c8ac5e22a257cc21d6d74af2cd1a Mon Sep 17 00:00:00 2001 From: ismail simsek Date: Wed, 18 Jun 2025 20:57:16 +0200 Subject: [PATCH] Prometheus: Use new language provider methods for code completions and query hints (#106383) * refactor language provider * update tests * more tests * betterer and api endpoints * copilot updates * betterer * remove default value * prettier * introduce new methods * provide unit tests for labelValues * update metadata fetch * move all cache related stuff in caching.ts * provide interface * provide deprecation messages * unit tests for new interface * separation of concerns * update tests * fix unit test * fix some types * Revert "fix some types" This reverts commit 7e64b93b5faf253bbde62e9b9ce330a63d07aebd. * revert interface usage * betterer * use PrometheusLanguageProviderInterface in everywhere * introduce resource clients * unit tests * act accordingly with the feature toggle * some more unit tests * add feature toggle * Revert "add feature toggle" This reverts commit 5c93ac324f9bba37a0da26d59c7b1d6d63ab9fd3. * remove feature toggle * update tests * backward compatibility * fix scope issues * comment update * stronger types * prettier * betterer * use new methods in metrics browser and query field * always return data * Revert "always return data" This reverts commit 38e493c189d627ee7fd1ef9b551059ea64d6eff0. * Revert "Revert "always return data"" This reverts commit b5d3b5d2b0e915a510a5cf044177e57277669ce2. * handle error * lint * use new method in query builder * fix metrics modal tests too * use labelValues method while searching in combobox * update metrics modal regex search * lint * fix unit test * introduce resource clients and better refactoring * prettier * type fixes * betterer * no empty matcher for series calls * better matchers * add additional tests * proper match string for series * introduce series cache * introduce series cache for series label values * lint * cache values too * utf8 safe label values query with series endpoint * fix unit tests * caching for labels api client * betterer * support new language provider methods in variable editor * use queries and adhoc filters to extract matchers * filter out __name__ * improve match string in series query label value calls * update unit tests * betterer * use new language provider methods in completions and query hints * betterer --- .../completions.test.ts | 4 ++++ .../monaco-completion-provider/completions.ts | 8 +++++++- .../data_provider.ts | 20 +++++++++---------- .../src/language_provider.mock.ts | 4 +++- .../src/query_hints.test.ts | 6 +++--- .../grafana-prometheus/src/query_hints.ts | 2 +- 6 files changed, 28 insertions(+), 16 deletions(-) diff --git a/packages/grafana-prometheus/src/components/monaco-query-field/monaco-completion-provider/completions.test.ts b/packages/grafana-prometheus/src/components/monaco-query-field/monaco-completion-provider/completions.test.ts index 832d8e518a3..600777343ea 100644 --- a/packages/grafana-prometheus/src/components/monaco-query-field/monaco-completion-provider/completions.test.ts +++ b/packages/grafana-prometheus/src/components/monaco-query-field/monaco-completion-provider/completions.test.ts @@ -16,6 +16,10 @@ const dataProviderSettings = { }, getLabelKeys: jest.fn(), getLabelValues: jest.fn(), + queryLabelKeys: jest.fn(), + queryLabelValues: jest.fn(), + retrieveLabelKeys: jest.fn(), + retrieveMetricsMetadata: jest.fn(), getSeriesLabels: jest.fn(), getSeriesValues: jest.fn(), metrics: [], diff --git a/packages/grafana-prometheus/src/components/monaco-query-field/monaco-completion-provider/completions.ts b/packages/grafana-prometheus/src/components/monaco-query-field/monaco-completion-provider/completions.ts index 51165e10a35..def4cd7eaaa 100644 --- a/packages/grafana-prometheus/src/components/monaco-query-field/monaco-completion-provider/completions.ts +++ b/packages/grafana-prometheus/src/components/monaco-query-field/monaco-completion-provider/completions.ts @@ -168,7 +168,13 @@ async function getLabelNames( return Promise.resolve(dataProvider.getAllLabelNames()); } else { const selector = makeSelector(metric, otherLabels); - return await dataProvider.getSeriesLabels(timeRange, selector, otherLabels); + const labelNames = await dataProvider.getSeriesLabels(timeRange, selector); + + // Exclude __name__ from output + otherLabels.push({ name: '__name__', value: '', op: '!=' }); + const usedLabelNames = new Set(otherLabels.map((l) => l.name)); + // names used in the query + return labelNames.filter((l) => !usedLabelNames.has(l)); } } diff --git a/packages/grafana-prometheus/src/components/monaco-query-field/monaco-completion-provider/data_provider.ts b/packages/grafana-prometheus/src/components/monaco-query-field/monaco-completion-provider/data_provider.ts index fe43b03958a..a651f761292 100644 --- a/packages/grafana-prometheus/src/components/monaco-query-field/monaco-completion-provider/data_provider.ts +++ b/packages/grafana-prometheus/src/components/monaco-query-field/monaco-completion-provider/data_provider.ts @@ -38,10 +38,10 @@ export interface DataProviderParams { export class DataProvider { readonly languageProvider: PrometheusLanguageProviderInterface; readonly historyProvider: Array>; - readonly getSeriesLabels: typeof this.languageProvider.getSeriesLabels; - readonly getSeriesValues: typeof this.languageProvider.getSeriesValues; - readonly getAllLabelNames: typeof this.languageProvider.getLabelKeys; - readonly getLabelValues: typeof this.languageProvider.getLabelValues; + readonly getSeriesLabels: typeof this.languageProvider.queryLabelKeys; + readonly getSeriesValues: typeof this.languageProvider.queryLabelValues; + readonly getAllLabelNames: typeof this.languageProvider.retrieveLabelKeys; + readonly getLabelValues: typeof this.languageProvider.queryLabelValues; readonly metricNamesSuggestionLimit: number; /** * The text that's been typed so far within the current {@link Monaco.Range | Range}. @@ -58,10 +58,10 @@ export class DataProvider { this.inputInRange = ''; this.metricNamesSuggestionLimit = this.languageProvider.datasource.metricNamesAutocompleteSuggestionLimit; this.suggestionsIncomplete = false; - this.getSeriesLabels = this.languageProvider.getSeriesLabels.bind(this.languageProvider); - this.getSeriesValues = this.languageProvider.getSeriesValues.bind(this.languageProvider); - this.getAllLabelNames = this.languageProvider.getLabelKeys.bind(this.languageProvider); - this.getLabelValues = this.languageProvider.getLabelValues.bind(this.languageProvider); + this.getSeriesLabels = this.languageProvider.queryLabelKeys.bind(this.languageProvider); + this.getSeriesValues = this.languageProvider.queryLabelValues.bind(this.languageProvider); + this.getAllLabelNames = this.languageProvider.retrieveLabelKeys.bind(this.languageProvider); + this.getLabelValues = this.languageProvider.queryLabelValues.bind(this.languageProvider); } getHistory(): string[] { @@ -69,11 +69,11 @@ export class DataProvider { } getAllMetricNames(): string[] { - return this.languageProvider.metrics; + return this.languageProvider.retrieveMetrics(); } metricNamesToMetrics(metricNames: string[]): Metric[] { - const { metricsMetadata } = this.languageProvider; + const metricsMetadata = this.languageProvider.retrieveMetricsMetadata(); const result: Metric[] = metricNames.map((m) => { const metaItem = metricsMetadata?.[m]; return { diff --git a/packages/grafana-prometheus/src/language_provider.mock.ts b/packages/grafana-prometheus/src/language_provider.mock.ts index e66c7b4de92..09e16e5a9af 100644 --- a/packages/grafana-prometheus/src/language_provider.mock.ts +++ b/packages/grafana-prometheus/src/language_provider.mock.ts @@ -24,6 +24,8 @@ export class EmptyLanguageProviderMock { queryLabelKeys = jest.fn().mockResolvedValue([]); queryLabelValues = jest.fn().mockResolvedValue([]); retrieveLabelKeys = jest.fn().mockReturnValue([]); - retrieveMetricsMetadata = jest.fn().mockReturnValue({}); + retrieveMetricsMetadata = jest + .fn() + .mockReturnValue({ histogram_metric_sum: { type: 'counter', help: '', unit: 'sum' } }); queryMetricsMetadata = jest.fn().mockResolvedValue({}); } diff --git a/packages/grafana-prometheus/src/query_hints.test.ts b/packages/grafana-prometheus/src/query_hints.test.ts index af2e9eee01a..f76c3ec7d3a 100644 --- a/packages/grafana-prometheus/src/query_hints.test.ts +++ b/packages/grafana-prometheus/src/query_hints.test.ts @@ -55,7 +55,7 @@ describe('getQueryHints()', () => { ], }, ]; - const mock: unknown = { languageProvider: { metricsMetadata: { foo: { type: 'counter' } } } }; + const mock: unknown = { languageProvider: { retrieveMetricsMetadata: () => ({ foo: { type: 'counter' } }) } }; const datasource = mock as PrometheusDatasource; let hints = getQueryHints('foo', series, datasource); @@ -213,7 +213,7 @@ describe('getQueryHints()', () => { ], }, ]; - const mock: unknown = { languageProvider: { metricsMetadata: { foo: { type: 'histogram' } } } }; + const mock: unknown = { languageProvider: { retrieveMetricsMetadata: () => ({ foo: { type: 'histogram' } }) } }; const datasource = mock as PrometheusDatasource; let hints = getQueryHints('foo', series, datasource); @@ -234,7 +234,7 @@ describe('getQueryHints()', () => { ], }, ]; - const mock: unknown = { languageProvider: { metricsMetadata: { foo: { type: 'histogram' } } } }; + const mock: unknown = { languageProvider: { retrieveMetricsMetadata: () => ({ foo: { type: 'histogram' } }) } }; const datasource = mock as PrometheusDatasource; let hints = getQueryHints(queryWithNativeHistogramFunction, series, datasource); diff --git a/packages/grafana-prometheus/src/query_hints.ts b/packages/grafana-prometheus/src/query_hints.ts index 73c3e90960e..2433c8ae5c6 100644 --- a/packages/grafana-prometheus/src/query_hints.ts +++ b/packages/grafana-prometheus/src/query_hints.ts @@ -17,7 +17,7 @@ export const SUM_HINT_THRESHOLD_COUNT = 20; export function getQueryHints(query: string, series?: unknown[], datasource?: PrometheusDatasource): QueryHint[] { const hints = []; - const metricsMetadata = datasource?.languageProvider?.metricsMetadata; + const metricsMetadata = datasource?.languageProvider?.retrieveMetricsMetadata(); // ..._bucket metric needs a histogram_quantile() // this regex also prevents hints from being shown when a query already has a function