CloudWatchのログって3ヶ月くらいで消えるらしいので。。
後々グラフ化とかして活用していきたいのでメモ。
(1) aws-cliの環境を整える。
後々jq
コマンドも使用するのでインストールしておく。
$ pip install awscli
$ aws configure
AWS Access Key ID [NONE]: ********************
AWS Secret Access Key [NONE]: ********************
Default region name [NONE]: ap-northeast-1
Default output format [NONE]: json
$ brew install jq
設定は$ aws configure list
で確認できる。
(2) get-metric-statisticsを使ってみる。
まずはローカルで試す。get-metric-statisticsの結果を変数に格納。
RESULT=`aws cloudwatch get-metric-statistics \
--namespace AWS/ApiGateway \
--metric-name Count \
--start-time 2019-07-14T00:00:00Z \
--end-time 2019-07-15T00:00:00Z \
--period 300 \
--statistics Sum`
namespaceには暗黙の了解でAWS/
をつける。
取得したいmetric-nameと取得したい期間を指定する。
periodはどの単位でデータを集計するか(ここでは300秒を指定)、集計方法は何か(Sum、Averageなど)。
なお、指定の仕方(特に大文字小文字)を失敗するとデータポイントが空のリストとなって返ってくる。
{
"Label": "count",
"Datapoints": []
}
(3) 整形してファイルに書き込む。
ファイルを作成し、RESULT
を書き込む。
touch tmp_log.txt
touch log.csv
echo $RESULT > tmp_log.txt
cat tmp_log.txt | jq -c -r '.Datapoints[] | [.Timestamp, .Sum, .Unit] | @csv' | sort -t , -k 1 > log.csv
jq
はJSONデータを加工・整形するためのツール。
.Datapoints[]
→Datapointsに対応する値の配列を外す。
| [.Timestamp, .Sum, .Unit]
→フィルタ(パイプ)を用いて再整形。
| @csv
→csv形式を指定
jq
コマンドのオプション
-
-c
(--compact-output):インデントをつけた表示をしない。 -
-r
(--raw-output):ダブルクオートを外して表示。
jqの詳細はこの記事を参照した。
なお、get-metric-statisticsで返されるデータはタイムスタンプ順にはなっていないのでソートする必要がある。
sort
コマンドのオプション
-t
→区切り文字を指定。
-k
→何列目の値を元にソートするかの指定。
(4) S3へアップ。
S3の指定のバケットへコピーする。
S3に適当なバケットを用意する。
aws s3 cp ./log.csv s3://test-bucket
(5) ある程度機能するようになったのでEC2に配置してみたい。
$ chmod 777 fuga.sh
$ ssh -i ~/.ssh/hoge_key.pem ec2-user@***.***.***.***
Last login: Tue Jul 30 01:09:31 2019 from kd106180011244.au-net.ne.jp
__| __|_ )
_| ( / Amazon Linux 2 AMI
___|\___|___|
https://aws.amazon.com/amazon-linux-2/
$ scp -i ~/.ssh/hoge_key.pem ~/fuga.sh ec2-user@***.***.***.***:/home/ec2-user/test/
fuga.sh 100% 416 2.8KB/s 00:00
転送するファイルのアクセス権によってはPermdission deniedとなり失敗する。送るファイルと送り先の両方の権限に注意する。なお、間違ってもec2-userの権限を777にしないこと。インスタンスに二度と接続できなくなり死亡する。
なお、ec2においてもaws configureの設定とjqのインストールをしておく必要がある。
$ sudo yum install jq
(6) メトリクスの日時・時刻を自動で反映。ファイル名にも。
TODAY=`date "+%Y%m%d"`
START_TIME=`date -v-1d "+%Y-%m-%dT00:00:00Z"`
END_TIME=`date -v-1d "+%Y-%m-%dT23:59:59Z"`
RESULT=`aws cloudwatch get-metric-statistics --namespace AWS/ApiGateway --metric-name Count --start-time ${START_TIME} --end-time ${END_TIME} --period 300 --statistics Sum`
touch tmp_log_${TODAY}.txt
touch log_${TODAY}.csv
ここで残念な問題が発生。
開発環境のMacはBSD、作成したインスタンスはGNU。。。dateコマンドのオプションが若干違うらしい??(この辺今度勉強しよう)
なので修正。
START_TIME=`date -d "1 days ago" "+%Y-%m-%dT00:00:00Z"`
END_TIME=`date -d "1 days ago" "+%Y-%m-%dT23:59:59Z"`
(7) crontabの設定。
そもそも時刻あってる?
$ date
2019年 7月 31日 水曜日 13:57:27 UTC
やっぱり違った。時刻の設定。→ここを参考に
$ sudo vi /etc/sysconfig/clock
ZONE="Japan"
UTC=true
$ sudo ln -sf /usr/share/zoneinfo/Japan /etc/localtime
$ sudo reboot
これでUTCからJSTになったので、cron設定。テストでは2時に実行で。
なお、対象のfuga.shファイルのPermissionが実行可能であることは確認しておく。
$ cd /etc/cron.d
$ sudo cp /etc/crontab /etc/cron.d/test_cron
$ sudo vi test_cron
0 2 * * * ec2-user sh /home/ec2-user/test/fuga.sh
cronの起動
$ sudo service crond restart
$ sudo systemctl status crond.service
● crond.service - Command Scheduler
Loaded: loaded (/usr/lib/systemd/system/crond.service; enabled; vendor preset: enabled)
Active: active (running) since 木 2019-08-01 01:44:53 JST; 7s ago
Main PID: 1234 (crond)
CGroup: /system.slice/crond.service
└─1234 /usr/sbin/crond -n
8月 01 01:44:53 ip-***-**-**-***.ap-northeast-1.compute.internal systemd[1]: Started Command Scheduler.
8月 01 01:44:53 ip-***-**-**-***.ap-northeast-1.compute.internal systemd[1]: Starting Command Scheduler...
8月 01 01:44:53 ip-***-**-**-***.ap-northeast-1.compute.internal crond[1234]: (CRON) INFO (RANDOM_DELAY will be scaled with factor 17% if used.)
8月 01 01:44:53 ip-***-**-**-***.ap-northeast-1.compute.internal crond[1234]: (CRON) INFO (running with inotify support)
8月 01 01:44:53 ip-***-**-**-***.ap-northeast-1.compute.internal crond[1234]: (CRON) INFO (@reboot jobs will be run at computer's startup.)
S3に正しい日付のファイルができていた。成功。
あとは、cronの実行時刻をJSTで9時に設定しなおせば0時から1日刻みでログを集められそう。(結局9時に設定するならはじめにJSTに時刻を揃えた意味が無いようだけど・・・)
コード全部
#!/bin/sh
TODAY=`date "+%Y%m%d"`
START_TIME=`date -v-1d "+%Y-%m-%dT00:00:00Z"`
END_TIME=`date -v-1d "+%Y-%m-%dT23:59:59Z"`
echo ${START_TIME}
echo ${END_TIME}
RESULT=`aws cloudwatch get-metric-statistics --namespace AWS/ApiGateway --metric-name Count --start-time ${START_TIME} --end-time ${END_TIME} --period 300 --statistics Sum`
touch tmp_log_${TODAY}.txt
touch log_${TODAY}.csv
echo $RESULT
echo $RESULT > tmp_log_${TODAY}.txt
cat tmp_log_${TODAY}.txt | jq -c -r '.Datapoints[] | [.Timestamp, .Sum, .Unit] | @csv' | sort -t , -k 1 > log_${TODAY}.csv
aws s3 cp ./log_${TODAY}.csv s3://test-bucket
rm tmp_log_${TODAY}.txt
rm log_${TODAY}.csv