diff --git a/public/app/plugins/datasource/loki/datasource.test.ts b/public/app/plugins/datasource/loki/datasource.test.ts index 273622cc082..78643f1c3ae 100644 --- a/public/app/plugins/datasource/loki/datasource.test.ts +++ b/public/app/plugins/datasource/loki/datasource.test.ts @@ -19,6 +19,7 @@ import { ToggleFilterAction, DataQueryRequest, ScopedVars, + AdHocVariableFilter, } from '@grafana/data'; import { BackendSrv, @@ -1701,6 +1702,67 @@ describe('LokiDatasource', () => { expect(ds.applyTemplateVariables).toHaveBeenCalledWith(expect.objectContaining(query), scopedVars, filters); }); }); + + describe('getTagKeys', () => { + it('should pass timeRange and filters to the request', async () => { + const ds = createLokiDatasource(); + const filters = [ + { key: 'foo', operator: '=', value: 'bar' }, + { key: 'foo2', operator: '=', value: 'bar2' }, + ]; + const spy = jest.spyOn(ds.languageProvider, 'fetchLabels').mockResolvedValue([]); + + await ds.getTagKeys({ filters, timeRange: mockTimeRange }); + expect(spy).toHaveBeenCalledWith({ streamSelector: '{foo="bar", foo2="bar2"}', timeRange: mockTimeRange }); + }); + + it('should pass regex filters', async () => { + const ds = createLokiDatasource(); + const filters = [ + { key: 'foo', operator: '=~', value: 'abc|def' }, + { key: 'foo2', operator: '=', value: 'bar2' }, + ]; + const spy = jest.spyOn(ds.languageProvider, 'fetchLabels').mockResolvedValue([]); + + await ds.getTagKeys({ filters, timeRange: mockTimeRange }); + expect(spy).toHaveBeenCalledWith({ streamSelector: '{foo=~"abc|def", foo2="bar2"}', timeRange: mockTimeRange }); + }); + + it('should pass empty stream selector when no filters', async () => { + const ds = createLokiDatasource(); + const filters: AdHocVariableFilter[] = []; + const spy = jest.spyOn(ds.languageProvider, 'fetchLabels').mockResolvedValue([]); + + await ds.getTagKeys({ filters, timeRange: mockTimeRange }); + expect(spy).toHaveBeenCalledWith({ streamSelector: '{}', timeRange: mockTimeRange }); + }); + }); + + describe('getTagValues', () => { + it('should pass timeRange and filters to the request', async () => { + const ds = createLokiDatasource(); + const filters = [ + { key: 'foo', operator: '=', value: 'bar' }, + { key: 'foo2', operator: '=', value: 'bar2' }, + ]; + const spy = jest.spyOn(ds.languageProvider, 'fetchLabelValues').mockResolvedValue([]); + + await ds.getTagValues({ key: 'label1', filters, timeRange: mockTimeRange }); + expect(spy).toHaveBeenCalledWith('label1', { + streamSelector: '{foo="bar", foo2="bar2"}', + timeRange: mockTimeRange, + }); + }); + + it('should pass empty stream selector when no filters', async () => { + const ds = createLokiDatasource(); + const filters: AdHocVariableFilter[] = []; + const spy = jest.spyOn(ds.languageProvider, 'fetchLabelValues').mockResolvedValue([]); + + await ds.getTagValues({ key: 'label1', filters, timeRange: mockTimeRange }); + expect(spy).toHaveBeenCalledWith('label1', { streamSelector: '{}', timeRange: mockTimeRange }); + }); + }); }); describe('applyTemplateVariables', () => { diff --git a/public/app/plugins/datasource/loki/datasource.ts b/public/app/plugins/datasource/loki/datasource.ts index c6fcbd565da..5c25286fc3a 100644 --- a/public/app/plugins/datasource/loki/datasource.ts +++ b/public/app/plugins/datasource/loki/datasource.ts @@ -743,7 +743,11 @@ export class LokiDatasource * @returns A Promise that resolves to an array of label names represented as MetricFindValue objects. */ async getTagKeys(options?: DataSourceGetTagKeysOptions): Promise { - const result = await this.languageProvider.fetchLabels({ timeRange: options?.timeRange }); + let streamSelector = '{}'; + for (const filter of options?.filters ?? []) { + streamSelector = addLabelToQuery(streamSelector, filter.key, filter.operator, filter.value); + } + const result = await this.languageProvider.fetchLabels({ timeRange: options?.timeRange, streamSelector }); return result.map((value: string) => ({ text: value })); } @@ -752,7 +756,14 @@ export class LokiDatasource * @returns A Promise that resolves to an array of label values represented as MetricFindValue objects */ async getTagValues(options: DataSourceGetTagValuesOptions): Promise { - const result = await this.languageProvider.fetchLabelValues(options.key, { timeRange: options.timeRange }); + let streamSelector = '{}'; + for (const filter of options?.filters ?? []) { + streamSelector = addLabelToQuery(streamSelector, filter.key, filter.operator, filter.value); + } + const result = await this.languageProvider.fetchLabelValues(options.key, { + timeRange: options.timeRange, + streamSelector, + }); return result.map((value: string) => ({ text: value })); }