お疲れさまです。とーちです。
CloudWatch Logs には指定したロググループのログを S3 にエクスポートする機能があります。便利な機能なのですが、下記の記事にも記載のある通り、大量のログを一度にエクスポートしようとするとエクスポートに失敗することがあります。
S3 バケットへのエクスポートに失敗する CloudWatch Logs のトラブルシューティング
作成後に失敗したタスクをトラブルシューティングするには、[時間範囲] 設定を確認します。大量のデータを含むログストリームをエクスポートし、長い時間範囲を指定すると、エクスポートタスクが失敗することがあります。その場合、短い時間範囲を指定します。
上記の通り、 大量のデータを一度にエクスポートするのではなく、短い時間範囲を指定 すると S3 へのエクスポートが失敗しにくくなるとのことなので、あるロググループ内の全ログを「指定した時間範囲に区切って」エクスポートする、といった処理をスクリプトで書いてみました。
CloudWatch Logs の S3 エクスポートについて
前提としてお伝えしておきたいのですが、CloudWatch Logs の S3 エクスポート機能はあくまでも スポット(一時的な作業用途) で CloudWatch Logs のログを S3 にコピーしたいというときに使うもので、以下の理由から日常的に(例えばバッチとして)使う用途には不向きだと思います。
- エクスポートタスクは同一アカウント内で、一度に 1 つしか動かせない
- ログ量が多いとエクスポートに失敗することがある
CloudWatch Logs のログを常に S3 にも送りたいという要件の場合は、以下記事のようにサブスクリプションフィルターと Kinesis Data Firehose を併用する構成がオススメです。
作成したスクリプト
想定しているユースケースとしては以下です。
- CloudWatch Logs のログを S3 に手動で退避する(一度限りの作業を想定)
- ロググループ内のログ量が大きいため、大きな時間範囲を指定してエクスポートすると失敗する可能性がある
- でも、一つずつ時間範囲を指定してエクスポートするのは面倒
以下が作成したスクリプトになります。 なお、動作確認は macOS 13.1 にて行っております。
cwlogstos3.sh
#!/bin/sh
S3BucketName=<エクスポート先バケット名を記載>
LogGroupName=$1
Interval_sec=$2
Interval_msec="${Interval_sec}000"
wait_for_export() {
# エクスポートタスクの完了確認間隔。
# デフォルト値10秒
# wait_for_export関数を呼ぶ際に第二引数を指定するとその値を使用
local sleep_time=${2:-10}
# エクスポートタスクのジョブステータスがCOMPLETEDまたはFAILEDになるまで続ける
while true; do
job_status=$(aws logs describe-export-tasks \
--task-id ${1} \
--query "exportTasks[0].status.code" \
--output text)
echo ${job_status}
if [ "$job_status" == "COMPLETED" ]; then
break
elif [ "$job_status" == "FAILED" ]; then
echo "--- The following export task failed ---"
aws logs describe-export-tasks --task-id ${1}
break
fi
sleep ${sleep_time}
done
}
# ロググループ内の最初のイベント時刻を取得
Loggroup_FirstEventTime=$(aws logs describe-log-streams \
--log-group-name "${LogGroupName}" \
--query "min(logStreams[*].firstEventTimestamp)" --output json)
# ロググループ内の最後のイベント時刻を取得
Loggroup_LastEventTime=$(aws logs describe-log-streams \
--log-group-name "${LogGroupName}" \
--query "max(logStreams[*].lastEventTimestamp)" --output json)
# Interval_msecの単位でエクスポートタスクを作成。
# 最初のイベント時刻から最後のイベント時刻までエクスポートする
TimeFrom=$Loggroup_FirstEventTime
while [ $TimeFrom -lt $Loggroup_LastEventTime ]
do
TimeTo=$(($TimeFrom+$Interval_msec))
task_id1=$(aws logs create-export-task \
--task-name "cloudwatch-log-group-export1" \
--log-group-name "${LogGroupName}" \
--from $TimeFrom --to $TimeTo \
--destination "${S3BucketName}" \
--query 'taskId' --output text)
wait_for_export ${task_id1}
TimeFrom=$(($TimeTo+1))
done
使い方は以下の通りです。
bash -x ./cwlogstos3.sh <エクスポートしたいロググループ名> <エクスポート時の時間範囲を区切る間隔(秒)>
まとめ
以上となります。
この記事が誰かのお役に立てばなによりです。
以上、とーちでした。