【Lambda】CloudWatch ログの保存期間を自動で設定する

#はじめに
以前、[CloudWatchのログをS3にエクスポートするLambdaを作成](https://qiita.com/chii-08/items/04baf8109c3b42ae65ea)しました。
CloudWatchLogsはロググループごとに保持期間を設定できるため、これを任意の期間に設定すればCloudWatchLogsにログが大量に蓄積...ということはないのですが、ロググループが作成される度に手動で設定するのがかなり面倒に感じました。ということで、こちらもLambdaで自動で設定されるようにしました。

#構成
今回は、CloudWatchEventsでLambdaを定期的に動かし保持期間が異なるものは変更するようにしました。
本当はロググループが新規に作成されるイベントをトリガーにしたかったのですが、できなさそうだったので。。。
<img width="576" alt="スクリーンショット 2019-08-24 13.20.37.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/429159/c2d347d1-a65c-015d-d539-8fae7695193e.png">

#事前準備
##IAMロールの作成
Lambdaに割り当てるIAMロールを作成します。

IAMロールのポリシードキュメントは、以下。

```json:IAMロールポリシードキュメント
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Principal": {
        "Service": "lambda.amazonaws.com"
      },
      "Action": "sts:AssumeRole"
    }
  ]
}

```

IAMロールは以下。
大きく分けると2つの権限が必要です。
**1.LambdaのログをCloudwatchLogsに書き込む権限**
CreateLogStream
CreateLogGroup
PutLogEvents

**2.CloudWatchLogsの保存期間を変更する権限**
DescribeLogGroups
PutRetentionPolicy


```json:IAMポリシー
{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "VisualEditor0",
            "Effect": "Allow",
            "Action": [
                "logs:CreateLogStream",
                "logs:DescribeLogGroups",
                "logs:PutRetentionPolicy",
                "logs:CreateLogGroup",
                "logs:PutLogEvents"
            ],
            "Resource": "*"
        }
    ]
}
```



#Lambdaの設定
ランタイムはPython3.7を使用、さらに以下の環境変数を設定しました。
**EXCEPT_LOGGROUPS**　：対象外とするロググループをカンマ区切りで指定。
**RETENTION_DAYS**　　　：ログの保持期間を日数で指定。

成功すれば以下のようなログが表示されるようにしています(保持期間を14日に設定)。
*successfully change /aws/lambda/cloudwatchlogs-retentionpolicy retention days : 14 days*

作成したLambdaに、先ほど作成したIAMロールを割り当てます。
作成したコードは以下。

```Python:cloudwatchLogs-retentionpolicy.py
import boto3
import os

client = boto3.client('logs')
except_loggroups = os.environ.get("EXCEPT_LOGGROUPS").split(",")
retention_days = os.environ.get("RETENTION_DAYS")


def lambda_handler(event, context):
    log_group_retention_days = {}
    for log_group_des in get_log_group_des(next_token=None):
        log_group_retention_days.update(
            get_log_group_retention_days(log_group_des))
    for log_group in log_group_retention_days:
        if log_group_des['logGroupName'] not in except_loggroups and log_group_retention_days[log_group] != int(retention_days):
            response = client.put_retention_policy(
                logGroupName=log_group,
                retentionInDays=int(retention_days)
            )
            print(
                f"successfully change {log_group} retention days : {retention_days} days")


def get_log_group_des(next_token):
    if next_token is not None and next_token != '':
        response = client.describe_log_groups(
            limit=50,
            nextToken=next_token
        )
    else:
        response = client.describe_log_groups(limit=50)
    if 'logGroups' in response:
        yield from response['logGroups']
    # ロググループが多くて50件(最大)を超えるようなら再帰呼出し
    if 'nextToken' in response:
        yield from get_log_group_des(next_token=response['nextToken'])

# {ロググループ名：保持期間}を取得
def get_log_group_retention_days(log_group_des):
    try:
        log_group_retention_days = {
            log_group_des['logGroupName']: log_group_des['retentionInDays']}
    except KeyError:
        log_group_retention_days = {log_group_des['logGroupName']: 'NotExpire'}
    return log_group_retention_days
```

#CloudWatch Eventsの設定
あとは、任意のタイミングでLambdaが動くようCloudWatchEventsの設定をしてください。
ちなみに私はcronで毎日1回動かす設定にしたので、cron式は以下のようになります。

```shell:毎日10時に動かすcron式
0 10 * * ? * 
```


以上です。最後までお読みいただきありがとうございます。

#参考文献
[Boto 3 Documentation](https://boto3.amazonaws.com/v1/documentation/api/latest/index.html?id=docs_gateway)
[Step FunctionsでCloudWatch LogsのロググループをS3へエクスポートする](https://www.soudegesu.com/aws/export-cloudwatchlogs-to-s3/)