/
log-retention.ts
116 lines (104 loc) · 3.66 KB
/
log-retention.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
import * as iam from '@aws-cdk/aws-iam';
import * as logs from '@aws-cdk/aws-logs';
import * as cdk from '@aws-cdk/core';
import * as path from 'path';
import { Code } from './code';
import { Runtime } from './runtime';
import { SingletonFunction } from './singleton-lambda';
/**
* Construction properties for a LogRetention.
*/
export interface LogRetentionProps {
/**
* The log group name.
*/
readonly logGroupName: string;
/**
* The number of days log events are kept in CloudWatch Logs.
*/
readonly retention: logs.RetentionDays;
/**
* The IAM role for the Lambda function associated with the custom resource.
*
* @default - A new role is created
*/
readonly role?: iam.IRole;
/**
* Retry options for all AWS API calls.
*
* @default - AWS SDK default retry options
*/
readonly logRetentionRetryOptions?: LogRetentionRetryOptions;
}
/**
* Retry options for all AWS API calls.
*/
export interface LogRetentionRetryOptions {
/**
* The maximum amount of retries.
*
* @default 3 (AWS SDK default)
*/
readonly maxRetries?: number;
/**
* The base duration to use in the exponential backoff for operation retries.
*
* @default Duration.millis(100) (AWS SDK default)
*/
readonly base?: cdk.Duration;
}
/**
* Creates a custom resource to control the retention policy of a CloudWatch Logs
* log group. The log group is created if it doesn't already exist. The policy
* is removed when `retentionDays` is `undefined` or equal to `Infinity`.
*/
export class LogRetention extends cdk.Construct {
/**
* The ARN of the LogGroup.
*/
public readonly logGroupArn: string;
constructor(scope: cdk.Construct, id: string, props: LogRetentionProps) {
super(scope, id);
// Custom resource provider
const provider = new SingletonFunction(this, 'Provider', {
code: Code.fromAsset(path.join(__dirname, 'log-retention-provider')),
runtime: Runtime.NODEJS_10_X,
handler: 'index.handler',
uuid: 'aae0aa3c-5b4d-4f87-b02d-85b201efdd8a',
lambdaPurpose: 'LogRetention',
role: props.role,
});
// Duplicate statements will be deduplicated by `PolicyDocument`
provider.addToRolePolicy(new iam.PolicyStatement({
actions: ['logs:PutRetentionPolicy', 'logs:DeleteRetentionPolicy'],
// We need '*' here because we will also put a retention policy on
// the log group of the provider function. Referencing it's name
// creates a CF circular dependency.
resources: ['*'],
}));
// Need to use a CfnResource here to prevent lerna dependency cycles
// @aws-cdk/aws-cloudformation -> @aws-cdk/aws-lambda -> @aws-cdk/aws-cloudformation
const retryOptions = props.logRetentionRetryOptions;
const resource = new cdk.CfnResource(this, 'Resource', {
type: 'Custom::LogRetention',
properties: {
ServiceToken: provider.functionArn,
LogGroupName: props.logGroupName,
SdkRetry: retryOptions ? {
maxRetries: retryOptions.maxRetries,
base: retryOptions.base?.toMilliseconds(),
} : undefined,
RetentionInDays: props.retention === logs.RetentionDays.INFINITE ? undefined : props.retention,
},
});
const logGroupName = resource.getAtt('LogGroupName').toString();
// Append ':*' at the end of the ARN to match with how CloudFormation does this for LogGroup ARNs
// See https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-logs-loggroup.html#aws-resource-logs-loggroup-return-values
this.logGroupArn = cdk.Stack.of(this).formatArn({
service: 'logs',
resource: 'log-group',
resourceName: `${logGroupName}:*`,
sep: ':',
});
}
}