私と私の猫の他は誰でも隠し事を持っている

野良プログラマ発、日々のアウトプット

CloudWatch ログをダンプしたり空ログストリーム削除したりするスクリプト書いた

AWS Lambda 関数開発をしてると CloudWatch ログを参照することが多いので、書いたスクリプトを備忘録的に公開。

CloudWatch ログは、ロググループ→ログストリーム→ログレコード という階層構造になっており、Web コンソールからログレコードを参照する場合はいちいちこの階層を辿らなきゃならず、ウザったいです。という訳で、ロググループ名と期間を指定して、ログレコードをダンプするスクリプトを書きますた↓。jq が要ります。

#!/bin/sh

if [ $# -ne 3 ]; then
	echo "usage: "`basename $0`" <ロググループ名> <開始期間(YYYY-MM-DD hh:mm:ss)> <終了期間(YYYY-MM-DD hh:mm:ss)>"
	exit
fi

# パラメタ
LOGGROUP=$1
DT_FROM=$2
DT_TO=$3

# 指定期間を Unixtime [ms] に
UT_FROM=`date -d "$DT_FROM" +%s`000
UT_TO=`date -d "$DT_TO" +%s`000

# jq の select 条件 
COND="(($UT_FROM <= .firstEventTimestamp) and (.firstEventTimestamp <= $UT_TO))"
COND="$COND or (($UT_FROM <= .lastEventTimestamp) and (.lastEventTimestamp <= $UT_TO))"
COND="$COND or ((.firstEventTimestamp <= $UT_FROM) and ($UT_TO <= .lastEventTimestamp))"

# 指定ロググループ名のログストリーム一覧をげとして、指定期間に重複するものだけフィルタリング
aws logs describe-log-streams --log-group-name $LOGGROUP --order-by LastEventTime --no-descending | jq -r ".logStreams[] | select($COND) | .logStreamName" | while read LOGSTREAM; do
	# ログストリームのログレコードを、タイムスタンプとメッセージのタブ区切りに整形して出力
	aws logs get-log-events --log-group-name $LOGGROUP --log-stream-name $LOGSTREAM | jq -r '.events[] | [(.timestamp/1000+32400 | strftime("%Y-%m-%d %H:%M:%S")), .message] | @tsv' | sed 's/\\n$//'
done

【註記】describe-log-streams ではページングを nextToken で制御するらしいのですが、今回要件では nextToken が返されることは無く、常にいちレスポンスで足りてしまっていたので、ページング処理はネグってあります。

もうひとつは、ロググループで一定期間後にイベント失効するように設定した時に、空のログストリームが残ってしまうので(大量に残るとかなりウザいw)、これを見つけて削除するスクリプト↓。

if [ $# -ne 1 ]; then
	echo "usage: "`basename $0`" <ロググループ名>"
	exit
fi

LOGGROUP=$1

# 指定ロググループ名のログストリーム一覧をげとして、開始タイムスタンプが無い(=ログレコードが無い)ものだけフィルタリング
aws logs describe-log-streams --log-group-name $LOGGROUP --order-by LastEventTime | jq -r ".logStreams[] | select(.firstEventTimestamp == null) | .logStreamName" | while read LOGSTREAM ; do
	# ログストリーム削除
	echo "delete "$LOGSTREAM
	aws logs delete-log-stream --log-group-name $LOGGROUP --log-stream-name $LOGSTREAM
done

jq は今まで JSON の整形や要素の抜き取りくらいにしか使ってなかったのですが、今回初めてフィルタや演算・関数等についてちゃんと勉強しました。チョー便利っすね。クラスメソッドさんのマニュアル和訳が大助かりでした。

dev.classmethod.jp