From 6dbf1f830a1ba4d297360ebf186ddcaed8394220 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Zolt=C3=A1n=20Bedi?= Date: Thu, 29 Oct 2020 17:05:36 +0100 Subject: [PATCH] Cloudwatch: Fix duplicate metric data (#28642) * Cloudwatch: Fix duplicate metric data * Refactor reduce function to for of --- .../datasource/cloudwatch/datasource.test.ts | 33 ++++++++- .../datasource/cloudwatch/datasource.ts | 73 ++++++++++--------- 2 files changed, 67 insertions(+), 39 deletions(-) diff --git a/public/app/plugins/datasource/cloudwatch/datasource.test.ts b/public/app/plugins/datasource/cloudwatch/datasource.test.ts index f6b030ae711..926ce3f16e9 100644 --- a/public/app/plugins/datasource/cloudwatch/datasource.test.ts +++ b/public/app/plugins/datasource/cloudwatch/datasource.test.ts @@ -1,7 +1,7 @@ -import { CloudWatchDatasource } from './datasource'; -import { TemplateSrv } from '../../../features/templating/template_srv'; +import { DataQueryResponse, dateTime, DefaultTimeRange } from '@grafana/data'; import { setBackendSrv } from '@grafana/runtime'; -import { DataQueryResponse, DefaultTimeRange } from '@grafana/data'; +import { TemplateSrv } from '../../../features/templating/template_srv'; +import { CloudWatchDatasource } from './datasource'; describe('datasource', () => { describe('query', () => { @@ -35,6 +35,33 @@ describe('datasource', () => { }); }); + describe('performTimeSeriesQuery', () => { + it('should return the same length of data as result', async () => { + const { datasource } = setup(); + const awsRequestMock = jest.spyOn(datasource, 'awsRequest'); + const buildCloudwatchConsoleUrlMock = jest.spyOn(datasource, 'buildCloudwatchConsoleUrl'); + buildCloudwatchConsoleUrlMock.mockImplementation(() => ''); + awsRequestMock.mockImplementation(async () => { + return { + results: { + a: { refId: 'a', series: [{ name: 'cpu', points: [1, 1] }], meta: { gmdMeta: '' } }, + b: { refId: 'b', series: [{ name: 'memory', points: [2, 2] }], meta: { gmdMeta: '' } }, + }, + }; + }); + const response: DataQueryResponse = await datasource.performTimeSeriesQuery( + { + queries: [ + { datasourceId: 1, refId: 'a' }, + { datasourceId: 1, refId: 'b' }, + ], + } as any, + { from: dateTime(), to: dateTime() } as any + ); + expect(response.data.length).toEqual(2); + }); + }); + describe('describeLogGroup', () => { it('replaces region correctly in the query', async () => { const { datasource, datasourceRequestMock } = setup(); diff --git a/public/app/plugins/datasource/cloudwatch/datasource.ts b/public/app/plugins/datasource/cloudwatch/datasource.ts index a82dfd1c120..7b859d4df15 100644 --- a/public/app/plugins/datasource/cloudwatch/datasource.ts +++ b/public/app/plugins/datasource/cloudwatch/datasource.ts @@ -595,44 +595,45 @@ export class CloudWatchDatasource extends DataSourceApi { - const queryResult = res.results[queryRequest.refId]; - if (!queryResult) { - return { data, error }; + const data = dataframes.map(frame => { + const queryResult = res.results[frame.refId!]; + const error = queryResult.error ? { message: queryResult.error } : null; + if (!queryResult) { + return { frame, error }; + } + + const requestQuery = request.queries.find(q => q.refId === frame.refId!) as any; + + const link = this.buildCloudwatchConsoleUrl( + requestQuery!, + from.toISOString(), + to.toISOString(), + frame.refId!, + queryResult.meta.gmdMeta + ); + + if (link) { + for (const field of frame.fields) { + field.config.links = [ + { + url: link, + title: 'View in CloudWatch console', + targetBlank: true, + }, + ]; } + } + return { frame, error }; + }); - const link = this.buildCloudwatchConsoleUrl( - queryRequest, - from.toISOString(), - to.toISOString(), - queryRequest.refId, - queryResult.meta.gmdMeta - ); - - return { - error: error || queryResult.error ? { message: queryResult.error } : null, - data: [ - ...data, - ...dataframes.map(frame => { - if (link) { - for (const field of frame.fields) { - field.config.links = [ - { - url: link, - title: 'View in CloudWatch console', - targetBlank: true, - }, - ]; - } - } - return frame; - }), - ], - }; - }, - { data: [], error: null } - ); + return { + data: data.map(o => o.frame), + error: data + .map(o => o.error) + .reduce((err, error) => { + return err || error; + }, null), + }; } catch (err) { if (/^Throttling:.*/.test(err.data.message)) { const failedRedIds = Object.keys(err.data.results);