From 0871b6aea9588080324cb6dc719ea42762c5fdfb Mon Sep 17 00:00:00 2001 From: Kevin Yu Date: Thu, 23 Mar 2023 13:11:12 -0700 Subject: [PATCH] CloudWatch Logs: Fix to make log queries use a relative time if available (#65236) --- .../cloudwatch/__mocks__/LogsQueryRunner.ts | 24 ++++++++-- .../CloudWatchLogsQueryRunner.test.ts | 47 +++++++++++++++++-- .../query-runner/CloudWatchLogsQueryRunner.ts | 10 ++-- 3 files changed, 72 insertions(+), 9 deletions(-) diff --git a/public/app/plugins/datasource/cloudwatch/__mocks__/LogsQueryRunner.ts b/public/app/plugins/datasource/cloudwatch/__mocks__/LogsQueryRunner.ts index 2b13ce17ce4..8761a78236c 100644 --- a/public/app/plugins/datasource/cloudwatch/__mocks__/LogsQueryRunner.ts +++ b/public/app/plugins/datasource/cloudwatch/__mocks__/LogsQueryRunner.ts @@ -2,11 +2,11 @@ import { of } from 'rxjs'; import { CustomVariableModel, DataFrame, DataSourceInstanceSettings } from '@grafana/data'; import { BackendDataSourceResponse, getBackendSrv, setBackendSrv } from '@grafana/runtime'; -import { getTimeSrv } from 'app/features/dashboard/services/TimeSrv'; +import { getTimeSrv, TimeSrv } from 'app/features/dashboard/services/TimeSrv'; import { TemplateSrv } from 'app/features/templating/template_srv'; import { CloudWatchLogsQueryRunner } from '../query-runner/CloudWatchLogsQueryRunner'; -import { CloudWatchJsonData, CloudWatchLogsQueryStatus } from '../types'; +import { CloudWatchJsonData, CloudWatchLogsQueryStatus, CloudWatchLogsRequest } from '../types'; import { CloudWatchSettings, setupMockedTemplateService } from './CloudWatchDataSource'; @@ -17,11 +17,13 @@ export function setupMockedLogsQueryRunner({ variables, mockGetVariableName = true, settings = CloudWatchSettings, + timeSrv = getTimeSrv(), }: { data?: BackendDataSourceResponse; variables?: CustomVariableModel[]; mockGetVariableName?: boolean; settings?: DataSourceInstanceSettings; + timeSrv?: TimeSrv; } = {}) { let templateService = new TemplateSrv(); if (variables) { @@ -31,7 +33,7 @@ export function setupMockedLogsQueryRunner({ } } - const runner = new CloudWatchLogsQueryRunner(settings, templateService, getTimeSrv()); + const runner = new CloudWatchLogsQueryRunner(settings, templateService, timeSrv); const fetchMock = jest.fn().mockReturnValue(of({ data })); setBackendSrv({ ...getBackendSrv(), @@ -66,3 +68,19 @@ export function genMockFrames(numResponses: number): DataFrame[] { return mockFrames; } + +export function genMockCloudWatchLogsRequest(overrides: Partial = {}) { + const request: CloudWatchLogsRequest = { + queryString: 'fields @timestamp, @message | sort @timestamp desc', + logGroupNames: ['log-group-name-1', 'log-group-name-2'], + logGroups: [ + { arn: 'log-group-arn-1', name: 'log-group-name-1' }, + { arn: 'log-group-arn-2', name: 'log-group-name-2' }, + ], + refId: 'A', + region: 'us-east-1', + ...overrides, + }; + + return request; +} diff --git a/public/app/plugins/datasource/cloudwatch/query-runner/CloudWatchLogsQueryRunner.test.ts b/public/app/plugins/datasource/cloudwatch/query-runner/CloudWatchLogsQueryRunner.test.ts index f1770514826..7dd13f85b22 100644 --- a/public/app/plugins/datasource/cloudwatch/query-runner/CloudWatchLogsQueryRunner.test.ts +++ b/public/app/plugins/datasource/cloudwatch/query-runner/CloudWatchLogsQueryRunner.test.ts @@ -1,6 +1,15 @@ import { interval, lastValueFrom, of } from 'rxjs'; -import { DataQueryErrorType, FieldType, LogLevel, LogRowModel, MutableDataFrame } from '@grafana/data'; +import { + DataQueryErrorType, + FieldType, + LogLevel, + LogRowModel, + MutableDataFrame, + dateTime, + DataQueryRequest, +} from '@grafana/data'; +import { getTimeSrv } from 'app/features/dashboard/services/TimeSrv'; import { CloudWatchSettings, @@ -8,7 +17,7 @@ import { logGroupNamesVariable, regionVariable, } from '../__mocks__/CloudWatchDataSource'; -import { genMockFrames, setupMockedLogsQueryRunner } from '../__mocks__/LogsQueryRunner'; +import { genMockFrames, genMockCloudWatchLogsRequest, setupMockedLogsQueryRunner } from '../__mocks__/LogsQueryRunner'; import { LogsRequestMock } from '../__mocks__/Request'; import { validLogsQuery } from '../__mocks__/queries'; import { CloudWatchLogsQuery, LogAction, StartQueryRequest } from '../types'; @@ -272,7 +281,39 @@ describe('CloudWatchLogsQueryRunner', () => { region: regionVariable.current.value as string, }, ]; - expect(spy).toHaveBeenNthCalledWith(1, 'StartQuery', startQueryRequests); + expect(spy).toHaveBeenNthCalledWith(1, 'StartQuery', startQueryRequests, LogsRequestMock); + }); + }); + + describe('makeLogActionRequest', () => { + it('should use the time range from the options if it is available', async () => { + const { runner } = setupMockedLogsQueryRunner(); + const spy = jest.spyOn(runner, 'awsRequest'); + const from = dateTime(0); + const to = dateTime(1000); + const options: DataQueryRequest = { + ...LogsRequestMock, + range: { from, to, raw: { from, to } }, + }; + await lastValueFrom(runner.makeLogActionRequest('StartQuery', [genMockCloudWatchLogsRequest()], options)); + expect(spy).toHaveBeenNthCalledWith(1, '/api/ds/query', expect.objectContaining({ from: '0', to: '1000' }), { + 'X-Cache-Skip': 'true', + }); + }); + + it('should use the time range from the timeSrv if the time range in the options is not available', async () => { + const timeSrv = getTimeSrv(); + timeSrv.timeRange = jest.fn().mockReturnValue({ + from: dateTime(1111), + to: dateTime(2222), + raw: { from: dateTime(1111), to: dateTime(2222) }, + }); + const { runner } = setupMockedLogsQueryRunner({ timeSrv }); + const spy = jest.spyOn(runner, 'awsRequest'); + await lastValueFrom(runner.makeLogActionRequest('StartQuery', [genMockCloudWatchLogsRequest()])); + expect(spy).toHaveBeenNthCalledWith(1, '/api/ds/query', expect.objectContaining({ from: '1111', to: '2222' }), { + 'X-Cache-Skip': 'true', + }); }); }); }); diff --git a/public/app/plugins/datasource/cloudwatch/query-runner/CloudWatchLogsQueryRunner.ts b/public/app/plugins/datasource/cloudwatch/query-runner/CloudWatchLogsQueryRunner.ts index 59b0d1a852c..81d90f26900 100644 --- a/public/app/plugins/datasource/cloudwatch/query-runner/CloudWatchLogsQueryRunner.ts +++ b/public/app/plugins/datasource/cloudwatch/query-runner/CloudWatchLogsQueryRunner.ts @@ -118,7 +118,7 @@ export class CloudWatchLogsQueryRunner extends CloudWatchRequest { return runWithRetry( (targets: StartQueryRequest[]) => { - return this.makeLogActionRequest('StartQuery', targets); + return this.makeLogActionRequest('StartQuery', targets, options); }, startQueryRequests, timeoutFunc @@ -269,8 +269,12 @@ export class CloudWatchLogsQueryRunner extends CloudWatchRequest { } } - makeLogActionRequest(subtype: LogAction, queryParams: CloudWatchLogsRequest[]): Observable { - const range = this.timeSrv.timeRange(); + makeLogActionRequest( + subtype: LogAction, + queryParams: CloudWatchLogsRequest[], + options?: DataQueryRequest + ): Observable { + const range = options?.range || this.timeSrv.timeRange(); const requestParams = { from: range.from.valueOf().toString(),