import { CloudWatchLogsClient, PutRetentionPolicyCommand } from '@aws-sdk/client-cloudwatch-logs'; import createDebug from 'debug'; const debug = createDebug('artillery:aws-cloudwatch'); const allowedRetentionDays = [ 1, 3, 5, 7, 14, 30, 60, 90, 120, 150, 180, 365, 400, 545, 731, 1096, 1827, 2192, 2557, 2922, 3288, 3653 ]; async function _putCloudwatchRetentionPolicy( logGroupName: string, retentionInDays: number, region: string ) { const cloudwatchlogs = new CloudWatchLogsClient({ apiVersion: '2014-11-06', region }); const putRetentionPolicyParams = { logGroupName, retentionInDays }; return cloudwatchlogs.send( new PutRetentionPolicyCommand(putRetentionPolicyParams) ); } interface RetentionRetryOptions { maxRetries: number; waitPerRetry: number; incr?: number; } function setCloudwatchRetention( logGroupName: string, // NOTE: pre-existing quirk: when set via the // ARTILLERY_LOGGROUP_RETENTION_DAYS env var this arrives as a // string, which never matches the numeric allowlist below - the // retention policy is then skipped with a warning. retentionInDays: number | string, region: string, options: RetentionRetryOptions = { maxRetries: 5, waitPerRetry: 1000 } ) { if (!allowedRetentionDays.includes(retentionInDays as number)) { console.log( `WARNING: Skipping setting CloudWatch retention, as invalid value specified: ${retentionInDays}. Allowed values are: ${allowedRetentionDays.join( ', ' )}` ); return; } const interval = setInterval( async (opts: RetentionRetryOptions) => { debug( `Trying to set CloudWatch Log group ${logGroupName} retention policy to ${retentionInDays} days` ); opts.incr = (opts.incr || 0) + 1; try { const _res = await _putCloudwatchRetentionPolicy( logGroupName, retentionInDays as number, region ); debug( `Successfully set CloudWatch Logs retention policy to ${retentionInDays} days` ); clearInterval(interval); } catch (err) { const error = err as NodeJS.ErrnoException; const resumeTestMessage = 'The test will continue without setting the retention policy.'; if (error?.code === 'AccessDeniedException') { console.log(`\n${error.message}`); console.log( '\nWARNING: Missing logs:PutRetentionPolicy permission to set CloudWatch retention policy. Please ensure the IAM role has the necessary permissions:\nhttps://docs.art/fargate#iam-permissions' ); console.log(`${resumeTestMessage}\n`); clearInterval(interval); return; } if (error?.code !== 'ResourceNotFoundException') { console.log(`\n${error.message}`); console.log( '\nWARNING: Unexpected error setting CloudWatch retention policy\n' ); console.log(`${resumeTestMessage}\n`); clearInterval(interval); return; } if ((opts.incr as number) >= opts.maxRetries) { console.log(`\n${error.message}`); console.log( `\nWARNING: Cannot find log group ${logGroupName}\nMax retries exceeded setting CloudWatch retention policy:` ); console.log(`${resumeTestMessage}\n`); clearInterval(interval); return; } } }, options.waitPerRetry, options ); return interval; } export { setCloudwatchRetention };