CloudWatchLogsロググループ不定期エクスポートの凡ミス防止のため手順をバッチ化してみた

手作業で行っていたCloudWatchLogsロググループエクスポートを、手動操作時ミス防止としてバッチ化してみました。個人的に分かりづらかったcreate-export-taskのオプションについても少しふれました。
2020.03.23

この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。

はじめに

CloudWatchLogs ロググループのS3エクスポートを手動で行う必要があり、似通った手続きが既にまとまっていないか探してみたものの、LambdaにてS3への定期出力というケースがほとんどです。

  • 毎日定期的に実行する必要はない
  • 全ログ保全の必要はない
  • 実行時に直近何日か分は保存しておきたい
  • 古い日付のものは必要なければ削除しても問題なし
  • サーバレス実行環境維持にコストをかけたくない

という状況にて、aws-cliを使ったローカル環境上で行うロググループエクスポートについてバッチ処理化してみました。

必要となる操作

CloudWatchLogsからS3へのエクスポートとなり、以下の操作をaws-cliで実施します。

  • エクスポート用S3バケット作成
  • S3バケットへLogs出力を受け入れるバケットポリシー設定
  • エクスポートの実行

定期的な実施をしないため、一目でわかりやすくすることを優先してバケット名末尾に実行日付をいれておきます。

エクスポート用S3バケット作成〜バケットポリシー設定

3つのロググループをエクスポートする前提で書いていますが、一つだけならforで回す必要はありません。

create-export-taskは並行進行数に制限があり、制限数以上に実行すると失敗するためステータスを確認しながらsleepさせています。

export_logs.sh

#/bin/sh
bucket_name="exported-logs-$(date +%Y%m%d%H%M%S)"
aws s3 mb s3://${bucket_name}

# put policy
json=$(cat $(pwd)/logs_backup_bucket_policy.json | sed "s/%%bucket_name%%/${bucket_name}/g")
echo $json > $(pwd)/logs_backup_bucket_policy.json
aws s3api put-bucket-policy --bucket ${bucket_name} --policy file://$(pwd)/logs_backup_bucket_policy.json
git checkout $(pwd)/logs_backup_bucket_policy.json

from_time=$(python -c "import datetime;print(int((datetime.datetime.now() - datetime.timedelta(30)).timestamp() * 1000))")
to_time=$(python -c "import time;print(int(time.time() * 1000))")
for task in <group1> <group2> <group3>
do
  echo "aws logs create-export-task --task-name ${bucket_name}-${task} --log-group-name \"/${task}\" --from ${from_time} --to ${to_time} --destination ${bucket_name} --destination-prefix ${task}-${from_time}-${to_time}"
  aws logs create-export-task --task-name ${bucket_name}-${task} --log-group-name "/${task}" --from ${from_time} --to ${to_time} --destination ${bucket_name} --destination-prefix ${task}-${from_time}-${to_time}
  while [ "$(aws logs describe-export-tasks | jq '.exportTasks[].status | select(.code | contains("RUNNING"))')" != "" ]
  do
    sleep 5
  done
done

logs_backup_bucket_policy.json

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Principal": {
                "Service": "logs.ap-northeast-1.amazonaws.com"
            },
            "Action": [
                "s3:GetBucketAcl",
                "s3:PutObject"
            ],
            "Resource": [
                "arn:aws:s3:::%%bucket_name%%",
                "arn:aws:s3:::%%bucket_name%%/*"
            ]
        }
    ]
}

実行する

$ export_logs.sh 
make_bucket: exported-logs-20200319113249
Updated 1 path from the index
aws logs create-export-task --task-name exported-logs-20200319113249-scheduler --log-group-name "/scheduler" --from 1581993667813 --to 1584585667875 --destination exported-logs-20200319113249 --destination-prefix scheduler-1581993667813-1584585667875
{
    "taskId": "00000000-0000-0000-0000-000000000000"
}
aws logs create-export-task --task-name exported-logs-20200319113249-webserver --log-group-name "/webserver" --from 1581993667813 --to 1584585667875 --destination exported-logs-20200319113249 --destination-prefix webserver-1581993667813-1584585667875
{
    "taskId": "11111111-1111-1111-1111-111111111111"
}
aws logs create-export-task --task-name exported-logs-20200319113249-worker --log-group-name "/worker" --from 1581993667813 --to 1584585667875 --destination exported-logs-20200319113249 --destination-prefix worker-1581993667813-1584585667875
{
    "taskId": "22222222-2222-2222-2222-222222222222"
}

あとがき

create-export-taskの設定で一番迷ったのは--destination-prefixでした。今回の例のように複数のロググループエクスポートの場合は各グループネームを指定すると、グループネームで分類されて振り返りやすくなります。指定していない場合はexportedlogsに固定されます。必要に応じての設定をおすすめします。

% aws s3 ls s3://exported-logs-20200319113249 --recursive
2020-03-19 11:41:27       1208 worker-1581993667813-1584585667875/22222222-2222-2222-2222-222222222222/worker-000000000000000000000000000/000000.gz
2020-03-19 11:41:19      38903 webserver-1581993667813-1584585667875/11111111-1111-1111-1111-111111111111/webserver-000000000000000000000000000/000000.gz
2020-03-19 11:41:10        868 scheduler-1581993667813-1584585667875/00000000-0000-0000-0000-000000000000/scheduler-000000000000000000000000000/000000.gz