diff --git a/public/app/plugins/datasource/prometheus/datasource.test.ts b/public/app/plugins/datasource/prometheus/datasource.test.ts index f3b20c84710..5a423957ff8 100644 --- a/public/app/plugins/datasource/prometheus/datasource.test.ts +++ b/public/app/plugins/datasource/prometheus/datasource.test.ts @@ -571,6 +571,13 @@ describe('PrometheusDatasource', () => { }); describe('applyTemplateVariables', () => { + const originalAdhocFiltersMock = templateSrvStub.getAdhocFilters(); + const originalReplaceMock = jest.fn((a: string, ...rest: any) => a); + afterAll(() => { + templateSrvStub.getAdhocFilters.mockReturnValue(originalAdhocFiltersMock); + templateSrvStub.replace = originalReplaceMock; + }); + it('should call replace function for legendFormat', () => { const query = { expr: 'test{job="bar"}', @@ -608,7 +615,32 @@ describe('PrometheusDatasource', () => { const interpolatedQuery = ds.applyTemplateVariables(query, { interval: { text: interval, value: interval } }); expect(interpolatedQuery.interval).not.toBe(interval); }); + + it('should add ad-hoc filters to expr', () => { + templateSrvStub.replace = jest.fn((a: string) => a); + templateSrvStub.getAdhocFilters.mockReturnValue([ + { + key: 'k1', + operator: '=', + value: 'v1', + }, + { + key: 'k2', + operator: '!=', + value: 'v2', + }, + ]); + + const query = { + expr: 'test{job="bar"}', + refId: 'A', + }; + + const result = ds.applyTemplateVariables(query, {}); + expect(result).toMatchObject({ expr: 'test{job="bar",k1="v1",k2!="v2"}' }); + }); }); + describe('metricFindQuery', () => { beforeEach(() => { const query = 'query_result(topk(5,rate(http_request_duration_microseconds_count[$__interval])))'; diff --git a/public/app/plugins/datasource/prometheus/datasource.ts b/public/app/plugins/datasource/prometheus/datasource.ts index bff676357bb..28b034dfb70 100644 --- a/public/app/plugins/datasource/prometheus/datasource.ts +++ b/public/app/plugins/datasource/prometheus/datasource.ts @@ -503,15 +503,7 @@ export class PrometheusDatasource extends DataSourceWithBackend { - const { key, operator } = filter; - let { value } = filter; - if (operator === '=~' || operator === '!~') { - value = prometheusRegularEscape(value); - } - return addLabelToQuery(acc, key, value, operator); - }, expr); + expr = this.enhanceExprWithAdHocFilters(expr); // Only replace vars in expression after having (possibly) updated interval vars query.expr = this.templateSrv.replace(expr, scopedVars, this.interpolateQueryExpr); @@ -909,6 +901,20 @@ export class PrometheusDatasource extends DataSourceWithBackend { + const { key, operator } = filter; + let { value } = filter; + if (operator === '=~' || operator === '!~') { + value = prometheusRegularEscape(value); + } + return addLabelToQuery(acc, key, value, operator); + }, finalQuery); + return finalQuery; + } + // Used when running queries trough backend filterQuery(query: PromQuery): boolean { if (query.hide || !query.expr) { @@ -920,14 +926,18 @@ export class PrometheusDatasource extends DataSourceWithBackend { const variables = cloneDeep(scopedVars); + // We want to interpolate these variables on backend delete variables.__interval; delete variables.__interval_ms; + //Add ad hoc filters + const expr = this.enhanceExprWithAdHocFilters(target.expr); + return { ...target, legendFormat: this.templateSrv.replace(target.legendFormat, variables), - expr: this.templateSrv.replace(target.expr, variables, this.interpolateQueryExpr), + expr: this.templateSrv.replace(expr, variables, this.interpolateQueryExpr), }; } }