diff --git a/public/app/plugins/datasource/prometheus/datasource.test.ts b/public/app/plugins/datasource/prometheus/datasource.test.ts index 6deac1daeb9..778bfadd18a 100644 --- a/public/app/plugins/datasource/prometheus/datasource.test.ts +++ b/public/app/plugins/datasource/prometheus/datasource.test.ts @@ -1667,6 +1667,35 @@ describe('PrometheusDatasource', () => { templateSrvStub.replace = jest.fn((a: string) => a); }); }); + + it('should give back 1 exemplar target when multiple queries with exemplar enabled and same metric', () => { + const targetA: PromQuery = { + refId: 'A', + expr: 'histogram_quantile(0.95, sum(rate(tns_request_duration_seconds_bucket[5m])) by (le))', + exemplar: true, + }; + const targetB: PromQuery = { + refId: 'B', + expr: 'histogram_quantile(0.5, sum(rate(tns_request_duration_seconds_bucket[5m])) by (le))', + exemplar: true, + }; + + ds.languageProvider = { + histogramMetrics: ['tns_request_duration_seconds_bucket'], + } as any; + + const request = ({ + targets: [targetA, targetB], + interval: '1s', + panelId: '', + } as any) as DataQueryRequest; + + const Aexemplars = ds.shouldRunExemplarQuery(targetA, request); + const BExpemplars = ds.shouldRunExemplarQuery(targetB, request); + + expect(Aexemplars).toBe(true); + expect(BExpemplars).toBe(false); + }); }); describe('PrometheusDatasource for POST', () => { diff --git a/public/app/plugins/datasource/prometheus/datasource.ts b/public/app/plugins/datasource/prometheus/datasource.ts index 8ba35a561b5..d727b2378ca 100644 --- a/public/app/plugins/datasource/prometheus/datasource.ts +++ b/public/app/plugins/datasource/prometheus/datasource.ts @@ -300,21 +300,19 @@ export class PrometheusDatasource extends DataSourceWithBackend): boolean { if (target.exemplar) { - const histogramMetrics = this.languageProvider.histogramMetrics; + // We check all already processed targets and only create exemplar target for not used metric names + const metricName = this.languageProvider.histogramMetrics.find((m) => target.expr.includes(m)); + // Remove targets that weren't processed yet (in targets array they are after current target) + const currentTargetIdx = request.targets.findIndex((t) => t.refId === target.refId); + const targets = request.targets.slice(0, currentTargetIdx); - if (histogramMetrics.length > 0) { - return !!histogramMetrics.find((metric) => target.expr.includes(metric)); - } else { - return target.expr.includes('_bucket'); + if (!metricName || (metricName && !targets.some((t) => t.expr.includes(metricName)))) { + return true; } + return false; } - return false; } @@ -322,7 +320,7 @@ export class PrometheusDatasource extends DataSourceWithBackend