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


概要

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

コード

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~数秒程度?)大きい値になる(=遅れている)ようです

リンク

実際の実行例

  • 後で見返してみたらわかりにくい記事だったので、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