CloudWatch Logsを手元にダウンロードするpythonコード

# 概要
- CloudWatchの ログストリームをマネジメントコンソールで見ているととても疲れるので手元にダウンロードして見たりgrepしたい
- AWS CLI(logs)でも取得できるのですが
    - 1リクエストで取得できる上限があります（全体を取得するためにはnext tokenを使って次のブロックを読みつなぐ必要があります）
    - 出力がjson
- スクリプト化します(python3.7)

# コード

```python
import boto3
from datetime import datetime


def get_events(log_group_name, log_stream_name, region_name=None):
    client = boto3.client('logs', region_name=region_name)

    # first request
    response = client.get_log_events(
        logGroupName=log_group_name,
        logStreamName=log_stream_name,
        startFromHead=True)
    yield response['events']

    # second and later
    while True:
        prev_token = response['nextForwardToken']
        response = client.get_log_events(
            logGroupName=log_group_name,
            logStreamName=log_stream_name,
            nextToken=prev_token)
        # same token then break
        if response['nextForwardToken'] == prev_token:
            break
        yield response['events']


# 利用例
log_group = '/aws/lambda/hogeprocedure'
log_stream = '2018/10/10/[$LATEST]7673b1e6c7f233ae9dbebcfe494f5836'
for events in get_events(log_group, log_stream):
    for e in events:
        print('{} {}'.format(
            datetime.fromtimestamp(int(e['timestamp']) / 1000),
            e['message']))
```

# ポイント
- 初回リクエストと2回目以降のリクエストは別に記述
    - 初回は先頭から取得(startFromHead=True)
    - 2回目以降は継続トークン(nextToken=～)
    - nextForwardTokenに同じ内容が返されたらログの終端
    - つまり小さなログでも最低2回リクエストします
- 1回のリクエストで1MB(10,000ログイベント)に収まるようにレスポンスされるとのこと
    - 実際にやってみた感じだと1リクエストで7000~8000ログぐらい、メッセージ部分だけの文字数だと800KBぐらい取得できました。ログの内容（量）によるのだと思います。
- 取得できる要素
    - timestamp
        - UNIXタイムスタンプ(UTC)、ミリ秒のためサンプルでは1000で割って表示しています
    - message
        - ログ文字列
    - ingestionTime
        - timestampと同様、ミリ秒のUNIXタイムスタンプ
        - CloudWatch Logsがログを受信した時刻のようです。timestampより少し(0～数秒程度？)大きい値になる（＝遅れている）ようです

# リンク
- https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/logs.html#CloudWatchLogs.Client.get_log_events

# 実際の実行例
- 後で見返してみたらわかりにくい記事だったので、AWS CLIの実行結果と本コードの実行結果を載せてみます

## AWS CLIの実行結果

```
$ aws --region ap-northeast-1 logs get-log-events --log-group-name '/aws/lambda/hello' --log-stream-name '2018/02/23/[$LATEST]27f890d355104940b6d8dcecba6c138f'
{
    "events": [
        {
            "timestamp": 1519362465349,
            "message": "hello\n",
            "ingestionTime": 1519362480690
        },
        {
            "timestamp": 1519362465349,
            "message": "END RequestId: 7bce02f9-1857-11e8-8d2a-17d131c3cab4\n",
            "ingestionTime": 1519362480690
        },
        {
            "timestamp": 1519362465349,
            "message": "REPORT RequestId: 7bce02f9-1857-11e8-8d2a-17d131c3cab4\tDuration: 0.51 ms\tBilled Duration: 100 ms \tMemory Size: 128 MB\tMax Memory Used: 22 MB\t\n",
            "ingestionTime": 1519362480690
        }
    ],
    "nextForwardToken": "f/33882915203959362030433736808932961647933286990084177922",
    "nextBackwardToken": "b/33882915203959362030433736808932961647933286990084177920"
}
```

## 本コードの実行結果

```
$ python logs.py
2018-02-23 14:07:45.349000 hello

2018-02-23 14:07:45.349000 END RequestId: 7bce02f9-1857-11e8-8d2a-17d131c3cab4

2018-02-23 14:07:45.349000 REPORT RequestId: 7bce02f9-1857-11e8-8d2a-17d131c3cab4       Duration: 0.51 ms       Billed Duration: 100 ms         Memory Size: 128 MB     Max Memory Used: 22 MB
```