CloudWatchメトリクスを定期的に取得するログ監視システムの構築

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の結果を変数に格納。

```shell
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`を書き込む。

```shell
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の詳細は[この記事](https://qiita.com/takeshinoda@github/items/2dec7a72930ec1f658af)を参照した。

なお、get-metric-statisticsで返されるデータはタイムスタンプ順にはなっていないのでソートする必要がある。

`sort`コマンドのオプション
`-t`→区切り文字を指定。
`-k`→何列目の値を元にソートするかの指定。

## (4) S3へアップ。
S3の指定のバケットへコピーする。
S3に適当なバケットを用意する。

```shell
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) メトリクスの日時・時刻を自動で反映。ファイル名にも。

```shell
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コマンドのオプションが若干違うらしい？？（この辺今度勉強しよう）

なので修正。

```shell
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
```

やっぱり違った。時刻の設定。→[ここ](https://dev.classmethod.jp/cloud/time-sync-service-ec2-ntp/)を参考に

```
$ 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
```

```: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に時刻を揃えた意味が無いようだけど・・・）


## コード全部

````shell:fuga.sh
#!/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
````