From f1ea04288142ad1e886a90c69183cc66596c1c6b Mon Sep 17 00:00:00 2001 From: Sarah Zinger Date: Fri, 18 Aug 2023 15:50:47 -0400 Subject: [PATCH 1/4] Cloudwatch: Add back support for old Log Group picker --- pkg/tsdb/cloudwatch/metric_find_query.go | 37 +++++ pkg/tsdb/cloudwatch/resource_handler.go | 3 + .../ConfigEditor/ConfigEditor.test.tsx | 14 +- .../components/ConfigEditor/ConfigEditor.tsx | 78 +++++----- .../LogsQueryEditor/LogsQueryField.tsx | 8 +- .../LogsQueryEditor/LogsQueryFieldOld.tsx | 12 +- .../LegacyLogGroupNamesSelection.tsx | 30 ++++ .../LogGroups/LegacyLogGroupSelector.tsx | 144 ++++++++++++++++++ .../shared/LogGroups/LogGroupsField.tsx | 34 ++++- .../datasource/cloudwatch/datasource.ts | 1 + .../cloudwatch/resources/ResourcesAPI.ts | 7 + 11 files changed, 319 insertions(+), 49 deletions(-) create mode 100644 public/app/plugins/datasource/cloudwatch/components/shared/LogGroups/LegacyLogGroupNamesSelection.tsx create mode 100644 public/app/plugins/datasource/cloudwatch/components/shared/LogGroups/LegacyLogGroupSelector.tsx diff --git a/pkg/tsdb/cloudwatch/metric_find_query.go b/pkg/tsdb/cloudwatch/metric_find_query.go index 518a0742f28f..fc172ed62150 100644 --- a/pkg/tsdb/cloudwatch/metric_find_query.go +++ b/pkg/tsdb/cloudwatch/metric_find_query.go @@ -8,10 +8,12 @@ import ( "net/url" "reflect" "sort" + "strconv" "strings" "time" "github.com/aws/aws-sdk-go/aws" + "github.com/aws/aws-sdk-go/service/cloudwatchlogs" "github.com/aws/aws-sdk-go/service/ec2" "github.com/aws/aws-sdk-go/service/resourcegroupstaggingapi" "github.com/grafana/grafana-plugin-sdk-go/backend" @@ -282,3 +284,38 @@ func (e *cloudWatchExecutor) resourceGroupsGetResources(ctx context.Context, plu return &resp, nil } + +// legacy route, will be removed once GovCloud supports Cross Account Observability +func (e *cloudWatchExecutor) handleGetLogGroups(ctx context.Context, pluginCtx backend.PluginContext, parameters url.Values) ([]suggestData, error) { + region := parameters.Get("region") + limit := parameters.Get("limit") + logGroupNamePrefix := parameters.Get("logGroupNamePrefix") + + logsClient, err := e.getCWLogsClient(ctx, pluginCtx, region) + if err != nil { + return nil, err + } + + logGroupLimit := defaultLogGroupLimit + intLimit, err := strconv.ParseInt(limit, 10, 64) + if err == nil && intLimit > 0 { + logGroupLimit = intLimit + } + + var response *cloudwatchlogs.DescribeLogGroupsOutput = nil + input := &cloudwatchlogs.DescribeLogGroupsInput{Limit: aws.Int64(logGroupLimit)} + if len(logGroupNamePrefix) > 0 { + input.LogGroupNamePrefix = aws.String(logGroupNamePrefix) + } + response, err = logsClient.DescribeLogGroups(input) + if err != nil || response == nil { + return nil, err + } + result := make([]suggestData, 0) + for _, logGroup := range response.LogGroups { + logGroupName := *logGroup.LogGroupName + result = append(result, suggestData{Text: logGroupName, Value: logGroupName, Label: logGroupName}) + } + + return result, nil +} diff --git a/pkg/tsdb/cloudwatch/resource_handler.go b/pkg/tsdb/cloudwatch/resource_handler.go index a6e03c1ea90b..4dd73f21fc2b 100644 --- a/pkg/tsdb/cloudwatch/resource_handler.go +++ b/pkg/tsdb/cloudwatch/resource_handler.go @@ -28,6 +28,9 @@ func (e *cloudWatchExecutor) newResourceMux() *http.ServeMux { mux.HandleFunc("/log-group-fields", routes.ResourceRequestMiddleware(routes.LogGroupFieldsHandler, logger, e.getRequestContext)) mux.HandleFunc("/external-id", routes.ResourceRequestMiddleware(routes.ExternalIdHandler, logger, e.getRequestContext)) + // remove this once AWS's Cross Account Observability is supported in GovCloud + mux.HandleFunc("/legacy-log-groups", handleResourceReq(e.handleGetLogGroups)) + return mux } diff --git a/public/app/plugins/datasource/cloudwatch/components/ConfigEditor/ConfigEditor.test.tsx b/public/app/plugins/datasource/cloudwatch/components/ConfigEditor/ConfigEditor.test.tsx index 52ff24374982..ebcab303759c 100644 --- a/public/app/plugins/datasource/cloudwatch/components/ConfigEditor/ConfigEditor.test.tsx +++ b/public/app/plugins/datasource/cloudwatch/components/ConfigEditor/ConfigEditor.test.tsx @@ -39,6 +39,9 @@ jest.mock('@grafana/runtime', () => ({ config: { ...jest.requireActual('@grafana/runtime').config, awsAssumeRoleEnabled: true, + featureToggles: { + cloudWatchCrossAccountQuerying: true, + }, }, })); @@ -166,7 +169,7 @@ describe('Render', () => { it('should display log group selector field', async () => { setup(); - await waitFor(async () => expect(await screen.getByText('Select log groups')).toBeInTheDocument()); + await waitFor(async () => expect(screen.getByText('Select log groups')).toBeInTheDocument()); }); it('should only display the first two default log groups and show all of them when clicking "Show all" button', async () => { @@ -204,9 +207,7 @@ describe('Render', () => { }); it('should show error message if Select log group button is clicked when data source is never saved', async () => { - const SAVED_VERSION = undefined; - setup({ version: SAVED_VERSION }); - + setup({ version: 1 }); await waitFor(() => expect(screen.getByText('Select log groups')).toBeInTheDocument()); await userEvent.click(screen.getByText('Select log groups')); await waitFor(() => @@ -265,12 +266,11 @@ describe('Render', () => { }); it('should open log group selector if Select log group button is clicked when data source has saved changes', async () => { - const SAVED_VERSION = undefined; const newProps = { ...props, options: { ...props.options, - version: SAVED_VERSION, + version: 1, }, }; const meta: PluginMeta = { @@ -291,7 +291,7 @@ describe('Render', () => { ...newProps, options: { ...newProps.options, - version: 1, + version: 2, }, }; rerender( diff --git a/public/app/plugins/datasource/cloudwatch/components/ConfigEditor/ConfigEditor.tsx b/public/app/plugins/datasource/cloudwatch/components/ConfigEditor/ConfigEditor.tsx index e3c9a1400751..9c5e38ced238 100644 --- a/public/app/plugins/datasource/cloudwatch/components/ConfigEditor/ConfigEditor.tsx +++ b/public/app/plugins/datasource/cloudwatch/components/ConfigEditor/ConfigEditor.tsx @@ -21,7 +21,7 @@ import { store } from 'app/store/store'; import { CloudWatchDatasource } from '../../datasource'; import { SelectableResourceValue } from '../../resources/types'; import { CloudWatchJsonData, CloudWatchSecureJsonData } from '../../types'; -import { LogGroupsField } from '../shared/LogGroups/LogGroupsField'; +import { LogGroupsFieldWrapper } from '../shared/LogGroups/LogGroupsField'; import { XrayLinkConfig } from './XrayLinkConfig'; @@ -124,39 +124,47 @@ export const ConfigEditor = (props: Props) => { shrink={true} {...logGroupFieldState} > - { - if (saved) { - return; - } - - let error = 'You need to save the data source before adding log groups.'; - if (props.options.version && props.options.version > 1) { - error = - 'You have unsaved connection detail changes. You need to save the data source before adding log groups.'; - } - setLogGroupFieldState({ - invalid: true, - error, - }); - throw new Error(error); - }} - legacyLogGroupNames={defaultLogGroups} - logGroups={logGroups} - onChange={(updatedLogGroups) => { - onOptionsChange({ - ...props.options, - jsonData: { - ...props.options.jsonData, - logGroups: updatedLogGroups, - defaultLogGroups: undefined, - }, - }); - }} - maxNoOfVisibleLogGroups={2} - /> + {datasource ? ( + { + if (saved) { + return; + } + + let error = 'You need to save the data source before adding log groups.'; + if (props.options.version && props.options.version > 1) { + error = + 'You have unsaved connection detail changes. You need to save the data source before adding log groups.'; + } + setLogGroupFieldState({ + invalid: true, + error, + }); + throw new Error(error); + }} + legacyLogGroupNames={defaultLogGroups} + logGroups={logGroups} + onChange={(updatedLogGroups) => { + onOptionsChange({ + ...props.options, + jsonData: { + ...props.options.jsonData, + logGroups: updatedLogGroups, + defaultLogGroups: undefined, + }, + }); + }} + maxNoOfVisibleLogGroups={2} + //legacy props + legacyOnChange={(logGroups) => { + updateDatasourcePluginJsonDataOption(props, 'defaultLogGroups', logGroups); + }} + /> + ) : ( + <> + )} { - props.options.version && setSaved(true); + props.options.version && props.options.version > 1 && setSaved(true); }, [props.options.version]); return saved; diff --git a/public/app/plugins/datasource/cloudwatch/components/QueryEditor/LogsQueryEditor/LogsQueryField.tsx b/public/app/plugins/datasource/cloudwatch/components/QueryEditor/LogsQueryEditor/LogsQueryField.tsx index a4dd667af179..e3c2d301bba1 100644 --- a/public/app/plugins/datasource/cloudwatch/components/QueryEditor/LogsQueryEditor/LogsQueryField.tsx +++ b/public/app/plugins/datasource/cloudwatch/components/QueryEditor/LogsQueryEditor/LogsQueryField.tsx @@ -10,7 +10,7 @@ import { TRIGGER_SUGGEST } from '../../../language/monarch/commands'; import { registerLanguage } from '../../../language/monarch/register'; import { CloudWatchJsonData, CloudWatchLogsQuery, CloudWatchQuery } from '../../../types'; import { getStatsGroups } from '../../../utils/query/getStatsGroups'; -import { LogGroupsField } from '../../shared/LogGroups/LogGroupsField'; +import { LogGroupsFieldWrapper } from '../../shared/LogGroups/LogGroupsField'; export interface CloudWatchLogsQueryFieldProps extends QueryEditorProps, @@ -47,7 +47,7 @@ export const CloudWatchLogsQueryFieldMonaco = (props: CloudWatchLogsQueryFieldPr return ( <> - { onChange({ ...query, logGroups, logGroupNames: undefined }); }} + //legacy props + legacyOnChange={(logGroupNames) => { + onChange({ ...query, logGroupNames }); + }} />
diff --git a/public/app/plugins/datasource/cloudwatch/components/QueryEditor/LogsQueryEditor/LogsQueryFieldOld.tsx b/public/app/plugins/datasource/cloudwatch/components/QueryEditor/LogsQueryEditor/LogsQueryFieldOld.tsx index 16601fabb531..b4f9fca3e2b1 100644 --- a/public/app/plugins/datasource/cloudwatch/components/QueryEditor/LogsQueryEditor/LogsQueryFieldOld.tsx +++ b/public/app/plugins/datasource/cloudwatch/components/QueryEditor/LogsQueryEditor/LogsQueryFieldOld.tsx @@ -18,9 +18,9 @@ import { // dom also includes Element polyfills import { CloudWatchDatasource } from '../../../datasource'; import syntax from '../../../language/cloudwatch-logs/syntax'; -import { CloudWatchJsonData, CloudWatchLogsQuery, CloudWatchQuery } from '../../../types'; +import { CloudWatchJsonData, CloudWatchLogsQuery, CloudWatchQuery, LogGroup } from '../../../types'; import { getStatsGroups } from '../../../utils/query/getStatsGroups'; -import { LogGroupsField } from '../../shared/LogGroups/LogGroupsField'; +import { LogGroupsFieldWrapper } from '../../shared/LogGroups/LogGroupsField'; export interface CloudWatchLogsQueryFieldProps extends QueryEditorProps, @@ -81,14 +81,18 @@ export const CloudWatchLogsQueryField = (props: CloudWatchLogsQueryFieldProps) = return ( <> - { + onChange={(logGroups: LogGroup[]) => { onChange({ ...query, logGroups, logGroupNames: undefined }); }} + //legacy props can be removed once we remove support for Legacy Log Group Selector + legacyOnChange={(logGroups: string[]) => { + onChange({ ...query, logGroupNames: logGroups }); + }} />
diff --git a/public/app/plugins/datasource/cloudwatch/components/shared/LogGroups/LegacyLogGroupNamesSelection.tsx b/public/app/plugins/datasource/cloudwatch/components/shared/LogGroups/LegacyLogGroupNamesSelection.tsx new file mode 100644 index 000000000000..020e123b9dde --- /dev/null +++ b/public/app/plugins/datasource/cloudwatch/components/shared/LogGroups/LegacyLogGroupNamesSelection.tsx @@ -0,0 +1,30 @@ +import { css } from '@emotion/css'; +import React from 'react'; + +import { CloudWatchDatasource } from '../../../datasource'; + +import { LogGroupSelector } from './LegacyLogGroupSelector'; + +type Props = { + datasource: CloudWatchDatasource; + onChange: (logGroups: string[]) => void; + region: string; + legacyLogGroupNames: string[]; +}; + +const rowGap = css` + gap: 3px; +`; + +export const LegacyLogGroupSelection = ({ datasource, region, legacyLogGroupNames, onChange }: Props) => { + return ( +
+ +
+ ); +}; diff --git a/public/app/plugins/datasource/cloudwatch/components/shared/LogGroups/LegacyLogGroupSelector.tsx b/public/app/plugins/datasource/cloudwatch/components/shared/LogGroups/LegacyLogGroupSelector.tsx new file mode 100644 index 000000000000..3b3048c0125b --- /dev/null +++ b/public/app/plugins/datasource/cloudwatch/components/shared/LogGroups/LegacyLogGroupSelector.tsx @@ -0,0 +1,144 @@ +import { debounce, unionBy } from 'lodash'; +import React, { useCallback, useEffect, useMemo, useState } from 'react'; + +import { SelectableValue, toOption } from '@grafana/data'; +import { MultiSelect } from '@grafana/ui'; +import { InputActionMeta } from '@grafana/ui/src/components/Select/types'; +import { notifyApp } from 'app/core/actions'; +import { createErrorNotification } from 'app/core/copy/appNotification'; +import { dispatch } from 'app/store/store'; + +import { CloudWatchDatasource } from '../../../datasource'; +import { appendTemplateVariables } from '../../../utils/utils'; + +const MAX_LOG_GROUPS = 20; +const MAX_VISIBLE_LOG_GROUPS = 4; +const DEBOUNCE_TIMER = 300; + +export interface LogGroupSelectorProps { + region: string; + selectedLogGroups: string[]; + onChange: (logGroups: string[]) => void; + + datasource?: CloudWatchDatasource; + onOpenMenu?: () => Promise; + width?: number | 'auto'; + saved?: boolean; // is only used in the config editor +} + +export const LogGroupSelector: React.FC = ({ + region, + selectedLogGroups, + onChange, + datasource, + onOpenMenu, + width, + saved = true, +}) => { + const [loadingLogGroups, setLoadingLogGroups] = useState(false); + const [availableLogGroups, setAvailableLogGroups] = useState>>([]); + const logGroupOptions = useMemo( + () => unionBy(availableLogGroups, selectedLogGroups?.map(toOption), 'value'), + [availableLogGroups, selectedLogGroups] + ); + + const fetchLogGroupOptions = useCallback( + async (region: string, logGroupNamePrefix?: string) => { + if (!datasource) { + return []; + } + try { + const logGroups = await datasource.resources.legacyDescribeLogGroups(region, logGroupNamePrefix); + return logGroups; + } catch (err) { + dispatch(notifyApp(createErrorNotification(typeof err === 'string' ? err : JSON.stringify(err)))); + return []; + } + }, + [datasource] + ); + + const onLogGroupSearch = async (searchTerm: string, region: string, actionMeta: InputActionMeta) => { + if (actionMeta.action !== 'input-change' || !datasource) { + return; + } + + // No need to fetch matching log groups if the search term isn't valid + // This is also useful for preventing searches when a user is typing out a log group with template vars + // See https://docs.aws.amazon.com/AmazonCloudWatchLogs/latest/APIReference/API_LogGroup.html for the source of the pattern below + const logGroupNamePattern = /^[\.\-_/#A-Za-z0-9]+$/; + if (!logGroupNamePattern.test(searchTerm)) { + if (searchTerm !== '') { + dispatch(notifyApp(createErrorNotification('Invalid Log Group name: ' + searchTerm))); + } + return; + } + + setLoadingLogGroups(true); + const matchingLogGroups = await fetchLogGroupOptions(region, searchTerm); + setAvailableLogGroups(unionBy(availableLogGroups, matchingLogGroups, 'value')); + setLoadingLogGroups(false); + }; + + // Reset the log group options if the datasource or region change and are saved + useEffect(() => { + async function getAvailableLogGroupOptions() { + // Don't call describeLogGroups if datasource or region is undefined + if (!datasource || !datasource.getActualRegion(region)) { + setAvailableLogGroups([]); + return; + } + + setLoadingLogGroups(true); + return fetchLogGroupOptions(datasource.getActualRegion(region)) + .then((logGroups) => { + setAvailableLogGroups(logGroups); + }) + .finally(() => { + setLoadingLogGroups(false); + }); + } + + // Config editor does not fetch new log group options unless changes have been saved + saved && getAvailableLogGroupOptions(); + + // if component unmounts in the middle of setting state, we reset state and unsubscribe from fetchLogGroupOptions + return () => { + setAvailableLogGroups([]); + setLoadingLogGroups(false); + }; + // this hook shouldn't get called every time selectedLogGroups or onChange updates + // eslint-disable-next-line react-hooks/exhaustive-deps + }, [datasource, region, saved]); + + const onOpenLogGroupMenu = async () => { + if (onOpenMenu) { + await onOpenMenu(); + } + }; + + const onLogGroupSearchDebounced = debounce(onLogGroupSearch, DEBOUNCE_TIMER); + + return ( + onChange(v.filter(({ value }) => value).map(({ value }) => value))} + closeMenuOnSelect={false} + isClearable + isOptionDisabled={() => selectedLogGroups.length >= MAX_LOG_GROUPS} + placeholder="Choose Log Groups" + maxVisibleValues={MAX_VISIBLE_LOG_GROUPS} + noOptionsMessage="No log groups available" + isLoading={loadingLogGroups} + onOpenMenu={onOpenLogGroupMenu} + onInputChange={(value, actionMeta) => { + onLogGroupSearchDebounced(value, region, actionMeta); + }} + width={width} + /> + ); +}; diff --git a/public/app/plugins/datasource/cloudwatch/components/shared/LogGroups/LogGroupsField.tsx b/public/app/plugins/datasource/cloudwatch/components/shared/LogGroups/LogGroupsField.tsx index acb7b7b2ac9d..40263d388241 100644 --- a/public/app/plugins/datasource/cloudwatch/components/shared/LogGroups/LogGroupsField.tsx +++ b/public/app/plugins/datasource/cloudwatch/components/shared/LogGroups/LogGroupsField.tsx @@ -1,17 +1,20 @@ import { css } from '@emotion/css'; import React, { useEffect, useState } from 'react'; +import { config } from '@grafana/runtime'; + import { CloudWatchDatasource } from '../../../datasource'; import { useAccountOptions } from '../../../hooks'; import { DescribeLogGroupsRequest } from '../../../resources/types'; import { LogGroup } from '../../../types'; import { isTemplateVariable } from '../../../utils/templateVariableUtils'; +import { LegacyLogGroupSelection } from './LegacyLogGroupNamesSelection'; import { LogGroupsSelector } from './LogGroupsSelector'; import { SelectedLogGroups } from './SelectedLogGroups'; type Props = { - datasource?: CloudWatchDatasource; + datasource: CloudWatchDatasource; onChange: (logGroups: LogGroup[]) => void; legacyLogGroupNames?: string[]; logGroups?: LogGroup[]; @@ -90,3 +93,32 @@ export const LogGroupsField = ({
); }; + +// We had to bring back the Legacy Log Group selector to support due to an issue where GovClouds do not support the new Log Group API +// when that is fixed we can get rid of this wrapper component and just export the LogGroupsField +type WrapperProps = { + datasource: CloudWatchDatasource; + onChange: (logGroups: LogGroup[]) => void; + legacyLogGroupNames?: string[]; // will need this for a while for migration purposes + logGroups?: LogGroup[]; + region: string; + maxNoOfVisibleLogGroups?: number; + onBeforeOpen?: () => void; + + // Legacy Props, can remove once we remove support for Legacy Log Group Selector + legacyOnChange: (logGroups: string[]) => void; +}; + +export const LogGroupsFieldWrapper = (props: WrapperProps) => { + if (!config.featureToggles.cloudWatchCrossAccountQuerying) { + return ( + + ); + } + + return ; +}; diff --git a/public/app/plugins/datasource/cloudwatch/datasource.ts b/public/app/plugins/datasource/cloudwatch/datasource.ts index 34b95790a3b7..787b24d596d0 100644 --- a/public/app/plugins/datasource/cloudwatch/datasource.ts +++ b/public/app/plugins/datasource/cloudwatch/datasource.ts @@ -72,6 +72,7 @@ export class CloudWatchDatasource this.annotationQueryRunner = new CloudWatchAnnotationQueryRunner(instanceSettings, templateSrv); this.variables = new CloudWatchVariableSupport(this.resources); this.annotations = CloudWatchAnnotationSupport; + this.defaultLogGroups = instanceSettings.jsonData.defaultLogGroups; } filterQuery(query: CloudWatchQuery) { diff --git a/public/app/plugins/datasource/cloudwatch/resources/ResourcesAPI.ts b/public/app/plugins/datasource/cloudwatch/resources/ResourcesAPI.ts index fc542af45845..bd284d5503f0 100644 --- a/public/app/plugins/datasource/cloudwatch/resources/ResourcesAPI.ts +++ b/public/app/plugins/datasource/cloudwatch/resources/ResourcesAPI.ts @@ -164,4 +164,11 @@ export class ResourcesAPI extends CloudWatchRequest { tags: JSON.stringify(this.convertMultiFilterFormat(tags, 'tag name')), }); } + + legacyDescribeLogGroups(region: string, logGroupNamePrefix?: string) { + return this.memoizedGetRequest('legacy-log-groups', { + region: this.templateSrv.replace(this.getActualRegion(region)), + logGroupNamePrefix: logGroupNamePrefix || '', + }); + } } From 0c1f66ad2d3c3608ed37cdd66a00f0708b80b648 Mon Sep 17 00:00:00 2001 From: Sarah Zinger Date: Mon, 21 Aug 2023 09:07:48 -0400 Subject: [PATCH 2/4] Fix broken tests --- .../components/QueryEditor/QueryEditor.test.tsx | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/public/app/plugins/datasource/cloudwatch/components/QueryEditor/QueryEditor.test.tsx b/public/app/plugins/datasource/cloudwatch/components/QueryEditor/QueryEditor.test.tsx index 03747a4c4728..0027ecbb75d2 100644 --- a/public/app/plugins/datasource/cloudwatch/components/QueryEditor/QueryEditor.test.tsx +++ b/public/app/plugins/datasource/cloudwatch/components/QueryEditor/QueryEditor.test.tsx @@ -45,6 +45,16 @@ jest.mock('./MetricsQueryEditor/SQLCodeEditor', () => ({ }, })); +jest.mock('@grafana/runtime', () => ({ + ...jest.requireActual('@grafana/runtime'), + config: { + ...jest.requireActual('@grafana/runtime').config, + featureToggles: { + cloudWatchCrossAccountQuerying: true, + }, + }, +})); + export { SQLCodeEditor } from './MetricsQueryEditor/SQLCodeEditor'; describe('QueryEditor should render right editor', () => { From de4ee7f157c2d0b1ca77592386a55f3c227dc884 Mon Sep 17 00:00:00 2001 From: Sarah Zinger Date: Wed, 23 Aug 2023 10:10:49 -0400 Subject: [PATCH 3/4] Moving response around for clarity --- pkg/tsdb/cloudwatch/metric_find_query.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/tsdb/cloudwatch/metric_find_query.go b/pkg/tsdb/cloudwatch/metric_find_query.go index fc172ed62150..8a431bc6c37f 100644 --- a/pkg/tsdb/cloudwatch/metric_find_query.go +++ b/pkg/tsdb/cloudwatch/metric_find_query.go @@ -302,11 +302,11 @@ func (e *cloudWatchExecutor) handleGetLogGroups(ctx context.Context, pluginCtx b logGroupLimit = intLimit } - var response *cloudwatchlogs.DescribeLogGroupsOutput = nil input := &cloudwatchlogs.DescribeLogGroupsInput{Limit: aws.Int64(logGroupLimit)} if len(logGroupNamePrefix) > 0 { input.LogGroupNamePrefix = aws.String(logGroupNamePrefix) } + var response *cloudwatchlogs.DescribeLogGroupsOutput = nil response, err = logsClient.DescribeLogGroups(input) if err != nil || response == nil { return nil, err From 991da3b92c8f2adcf609e80a4ddbe1732596ae5f Mon Sep 17 00:00:00 2001 From: Sarah Zinger Date: Thu, 31 Aug 2023 09:42:55 -0400 Subject: [PATCH 4/4] Lint --- pkg/tsdb/cloudwatch/metric_find_query.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/tsdb/cloudwatch/metric_find_query.go b/pkg/tsdb/cloudwatch/metric_find_query.go index 8a431bc6c37f..2c01b44715d5 100644 --- a/pkg/tsdb/cloudwatch/metric_find_query.go +++ b/pkg/tsdb/cloudwatch/metric_find_query.go @@ -306,7 +306,7 @@ func (e *cloudWatchExecutor) handleGetLogGroups(ctx context.Context, pluginCtx b if len(logGroupNamePrefix) > 0 { input.LogGroupNamePrefix = aws.String(logGroupNamePrefix) } - var response *cloudwatchlogs.DescribeLogGroupsOutput = nil + var response *cloudwatchlogs.DescribeLogGroupsOutput response, err = logsClient.DescribeLogGroups(input) if err != nil || response == nil { return nil, err