CloudWatch Logsのイベントを期間指定で取得する

# CloudWatch Logs
CloudWatchに保存されたログはAWSのコンソールで確認する事ができて便利ですが、ログを解析する場合にS3にエクスポートするなど一手間かかります。ログの解析には、私はPythonスクリプトで行う事が多いので、PythonスクリプトでCloudWatchからログを取得するスクリプトの作成を目指します。なお、以下のコードはpython3(3.7.5)で動作させています。

```bash
$ python3 --version
Python 3.7.5
```

# PythonでのCloudWatch Logsの取得方法
他のAWSの制御と同様でboto3を利用します。boto3が入っていない場合は、インストールをして下さい。

```bash
$ pip3 install boto3
```

boto3を利用するためには、AWSのIAMアカウントのアクセスキーとシークレットを利用する必要があります。そちらについては、aws configureで事前に設定しておいて下さい。設定されていれば、boto3が環境変数を読み取リますので、pythonスクリプトでアクセスキー、シークレットに指定は必要ありません。
https://docs.aws.amazon.com/ja_jp/cli/latest/userguide/cli-chap-configure.html

CloudWatchのログを取得する場合は、'logs'を指定してboto3のクライアントを取得します。

```python
client = boto3.client('logs')
```

CloudWatch Logsのboto3のクライアントのI/Fは以下に記述されています。
https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/logs.html#CloudWatchLogs.Client.get_log_events

CloudWatch Logsはロググループがあり、その中にログストリームが複数存在する構成となっています。get_log_events()ではロググループとログストリームを指定してログイベントを取得します。
https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/logs.html#CloudWatchLogs.Client.get_log_events

今回はロググループの指定だけで、ログイベントを取得したいので、filter_log_events()を利用します。全てのデータを取得したいので、フィルターは指定しません。startTime, endTimeで期間を指定する事ができます。こちらの時間はUNIX時間になっています。

https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/logs.html#CloudWatchLogs.Client.filter_log_events

```python
response = client.filter_log_events(
                logGroupName=log_group_name,
                startTime=start_time,
                endTime=end_time
            )
```
ログイベントは最大1Mbyte分まで一度の呼び出しで取得できます。続きを取得する場合は、responseに含まれるnextTokenを利用して再度呼び出す必要があります。

```python
next_token = response['nextToken']
response = client.filter_log_events(
                logGroupName=log_group_name,
                startTime=start_time,
                endTime=end_time,
                nextToken=next_token
            )
```

# サンプルコード
現在の時間の日付だけを取り出し、昨日から今日までの24時間のログを取得するサンプルになります。retrieve_eventsではyieldを使って、取得したログイベントを随時返却します。main関数では、取得したログイベントをfor文で随時取得して、ログイベントの数を表示しています。

```python
def retrieve_events(log_group_name, start_time, end_time):
    client = boto3.client('logs')
    next_token = ''
    response = {}
    while True:
        if next_token == '':
            response = client.filter_log_events(
                logGroupName=log_group_name,
                startTime=start_time,
                endTime=end_time
            )
        else:
            response = client.filter_log_events(
                logGroupName=log_group_name,
                startTime=start_time,
                endTime=end_time,
                nextToken=next_token
            )
        if 'nextToken' in response:
            next_token = response['nextToken']
            yield response['events']
        else:
            break

if __name__ == '__main__':
    now = datetime.datetime.now()
    today = datetime.datetime(now.year, now.month, now.day, 0, 0, 0, 0)
    yesterday = today - datetime.timedelta(days=1)
    today_unix = int(today.timestamp()*1000)
    yesterday_unix = int(yesterday.timestamp()*1000)

    for events in retrieve_events(LOG_GROUP_NAME, yesterday_unix, today_unix):
        print(len(events))
```