diff --git a/packages/grafana-prometheus/src/language_provider.test.ts b/packages/grafana-prometheus/src/language_provider.test.ts index 26307532aff..53d52902433 100644 --- a/packages/grafana-prometheus/src/language_provider.test.ts +++ b/packages/grafana-prometheus/src/language_provider.test.ts @@ -611,37 +611,6 @@ describe('Prometheus Language Provider', () => { }); }); - describe('Query transformation', () => { - describe('importFromAbstractQuery', () => { - it('should handle empty queries', async () => { - const result = importFromAbstractQuery({ refId: 'bar', labelMatchers: [] }); - expect(result).toEqual({ refId: 'bar', expr: '', range: true }); - }); - }); - - describe('exportToAbstractQuery', () => { - it('should extract labels and metric name from PromQL', async () => { - const abstractQuery = exportToAbstractQuery({ - refId: 'bar', - expr: 'metric_name{label1="value1", label2!="value2", label3=~"value3", label4!~"value4"}', - instant: true, - range: false, - }); - - expect(abstractQuery).toMatchObject({ - refId: 'bar', - labelMatchers: [ - { name: 'label1', operator: AbstractLabelOperator.Equal, value: 'value1' }, - { name: 'label2', operator: AbstractLabelOperator.NotEqual, value: 'value2' }, - { name: 'label3', operator: AbstractLabelOperator.EqualRegEx, value: 'value3' }, - { name: 'label4', operator: AbstractLabelOperator.NotEqualRegEx, value: 'value4' }, - { name: '__name__', operator: AbstractLabelOperator.Equal, value: 'metric_name' }, - ], - }); - }); - }); - }); - describe('fetchSuggestions', () => { it('should send POST request with correct parameters', async () => { const timeRange = getMockTimeRange(); @@ -726,6 +695,37 @@ describe('Prometheus Language Provider', () => { }); }); +describe('Query transformation', () => { + describe('importFromAbstractQuery', () => { + it('should handle empty queries', async () => { + const result = importFromAbstractQuery({ refId: 'bar', labelMatchers: [] }); + expect(result).toEqual({ refId: 'bar', expr: '', range: true }); + }); + }); + + describe('exportToAbstractQuery', () => { + it('should extract labels and metric name from PromQL', async () => { + const abstractQuery = exportToAbstractQuery({ + refId: 'bar', + expr: 'metric_name{label1="value1", label2!="value2", label3=~"value3", label4!~"value4"}', + instant: true, + range: false, + }); + + expect(abstractQuery).toMatchObject({ + refId: 'bar', + labelMatchers: [ + { name: 'label1', operator: AbstractLabelOperator.Equal, value: 'value1' }, + { name: 'label2', operator: AbstractLabelOperator.NotEqual, value: 'value2' }, + { name: 'label3', operator: AbstractLabelOperator.EqualRegEx, value: 'value3' }, + { name: 'label4', operator: AbstractLabelOperator.NotEqualRegEx, value: 'value4' }, + { name: '__name__', operator: AbstractLabelOperator.Equal, value: 'metric_name' }, + ], + }); + }); + }); +}); + describe('removeQuotesIfExist', () => { it('removes quotes from a string with double quotes', () => { const input = '"hello"'; diff --git a/packages/grafana-prometheus/src/language_provider.ts b/packages/grafana-prometheus/src/language_provider.ts index 8316ae7c03a..37b09f1e9dc 100644 --- a/packages/grafana-prometheus/src/language_provider.ts +++ b/packages/grafana-prometheus/src/language_provider.ts @@ -48,12 +48,7 @@ const API_V1 = { LABELS_VALUES: (labelKey: string) => `/api/v1/label/${labelKey}/values`, }; -type UrlParamsType = { - start?: string; - end?: string; - 'match[]'?: string; - limit?: string; -}; +const MATCH_ALL_LABELS = '{__name__!=""}'; export interface PrometheusBaseLanguageProvider { datasource: PrometheusDatasource; @@ -97,14 +92,36 @@ export interface PrometheusLegacyLanguageProvider { labelKeys: string[]; /** - * @deprecated Use queryMetricsMetadata() method instead. If you want existing metadata use retrieveMetricsMetadata() method. + * @deprecated Use queryMetricsMetadata() method instead. */ loadMetricsMetadata: () => void; + /** + * @deprecated Use retrieveMetricsMetadata() method instead + */ getLabelKeys: () => string[]; + /** + * @deprecated If you need labelKeys or labelValues please use queryLabelKeys() or queryLabelValues() functions + */ getSeries: (timeRange: TimeRange, selector: string, withName?: boolean) => Promise>; + /** + * @deprecated Use queryLabelValues() method insteadIt'll determine the right endpoint based on the datasource settings + */ fetchLabelValues: (range: TimeRange, key: string, limit?: string) => Promise; + /** + * @deprecated Use queryLabelValues() method insteadIt'll determine the right endpoint based on the datasource settings + */ + getLabelValues: (range: TimeRange, key: string) => Promise; + /** + * @deprecated If you need labelKeys or labelValues please use queryLabelKeys() or queryLabelValues() functions + */ fetchLabels: (timeRange: TimeRange, queries?: PromQuery[], limit?: string) => Promise; + /** + * @deprecated Use queryLabelValues() method insteadIt'll determine the right endpoint based on the datasource settings + */ getSeriesValues: (timeRange: TimeRange, labelName: string, selector: string) => Promise; + /** + * @deprecated Use queryLabelValues() method insteadIt'll determine the right endpoint based on the datasource settings + */ fetchSeriesValuesWithMatch: ( timeRange: TimeRange, name: string, @@ -112,21 +129,39 @@ export interface PrometheusLegacyLanguageProvider { requestId?: string, withLimit?: string ) => Promise; + /** + * @deprecated Use queryLabelKeys() method instead. It'll determine the right endpoint based on the datasource settings + */ getSeriesLabels: (timeRange: TimeRange, selector: string, otherLabels: Label[]) => Promise; + /** + * @deprecated Use queryLabelKeys() method instead. It'll determine the right endpoint based on the datasource settings + */ fetchLabelsWithMatch: ( timeRange: TimeRange, name: string, withName?: boolean, withLimit?: string ) => Promise>; + /** + * @deprecated Use queryLabelKeys() method instead. It'll determine the right endpoint based on the datasource settings + */ fetchSeriesLabels: ( timeRange: TimeRange, name: string, withName?: boolean, withLimit?: string ) => Promise>; + /** + * @deprecated Use queryLabelKeys() method instead. It'll determine the right endpoint based on the datasource settings + */ fetchSeriesLabelsMatch: (timeRange: TimeRange, name: string, withLimit?: string) => Promise>; + /** + * @deprecated If you need labelKeys or labelValues please use queryLabelKeys() or queryLabelValues() functions + */ fetchSeries: (timeRange: TimeRange, match: string) => Promise>>; + /** + * @deprecated If you need labelKeys or labelValues please use queryLabelKeys() or queryLabelValues() functions + */ fetchDefaultSeries: (timeRange: TimeRange) => Promise<{}>; } @@ -137,8 +172,8 @@ export interface PrometheusLanguageProvider extends PrometheusBaseLanguageProvid retrieveLabelKeys: () => string[]; queryMetricsMetadata: () => Promise; - queryLabelKeys: (timeRange: TimeRange, match?: string, limit?: string) => string[]; - queryLabelValues: (timeRange: TimeRange, labelKey: string, match?: string, limit?: string) => string[]; + queryLabelKeys: (timeRange: TimeRange, match?: string, limit?: string) => Promise; + queryLabelValues: (timeRange: TimeRange, labelKey: string, match?: string, limit?: string) => Promise; } export default class PromQlLanguageProvider extends LanguageProvider implements PrometheusLanguageProvider { @@ -185,15 +220,6 @@ export default class PromQlLanguageProvider extends LanguageProvider implements return []; } - // Prevent ts yelling - console.log( - this._withLabelsApiFetchLabelKeys, - this._withLabelsApiFetchLabelValues, - this._withSeriesApiFetchAllSeries, - this._withSeriesApiFetchLabelKeys, - this._withSeriesApiFetchLabelValues - ); - this.metrics = (await this.fetchLabelValues(timeRange, '__name__')) || []; this.histogramMetrics = processHistogramMetrics(this.metrics).sort(); return Promise.all([this.loadMetricsMetadata(), this.fetchLabels(timeRange)]); @@ -341,12 +367,25 @@ export default class PromQlLanguageProvider extends LanguageProvider implements return this._metricsMetadata; }; - public queryLabelKeys = (timeRange: TimeRange, match?: string, limit?: string): string[] => { - return []; + public queryLabelKeys = async (timeRange: TimeRange, match?: string, limit?: string): Promise => { + if (this.datasource.hasLabelsMatchAPISupport()) { + return await this._withLabelsApiFetchLabelKeys(timeRange, match, limit); + } + + return await this._withSeriesApiFetchLabelKeys(timeRange, match ?? MATCH_ALL_LABELS, limit); }; - public queryLabelValues = (timeRange: TimeRange, labelKey: string, match?: string, limit?: string): string[] => { - return []; + public queryLabelValues = async ( + timeRange: TimeRange, + labelKey: string, + match?: string, + limit?: string + ): Promise => { + if (this.datasource.hasLabelsMatchAPISupport()) { + return await this._withLabelsApiFetchLabelValues(timeRange, labelKey, match, limit); + } + + return await this._withSeriesApiFetchLabelValues(timeRange, labelKey, match ?? MATCH_ALL_LABELS, limit); }; // ====================================================================== @@ -536,15 +575,12 @@ export default class PromQlLanguageProvider extends LanguageProvider implements ): Promise> => { const interpolatedName = this.datasource.interpolateString(name); const range = this.datasource.getAdjustedInterval(timeRange); - let urlParams: UrlParamsType = { + let urlParams = { ...range, 'match[]': interpolatedName, + ...(withLimit !== 'none' ? { limit: withLimit ?? DEFAULT_SERIES_LIMIT } : {}), }; - if (withLimit !== 'none') { - urlParams = { ...urlParams, limit: withLimit ?? DEFAULT_SERIES_LIMIT }; - } - const data = await this.request(API_V1.SERIES, urlParams, getDefaultCacheHeaders(this.datasource.cacheLevel)); const { values } = processLabels(data, withName); return values;