AWS Lambda + Python + Slack でサイトの監視・アラート通知

運用中のサイトがたまに落ちていることがあったので、
簡易的にですがサイト監視を用意してみました。
（世の中にはサーバーのメトリクス取得含め手厚い監視サービスが様々ありますが、今回は低コストかつSlackとも簡単に連携できる方法という位置づけで作っています）

## サイトのstatusをチェックしてSlackに通知する
では、サイトチェックをするコードを書いていきます。
おおまかな流れとしては、指定されたURLのHTTP statusをチェックし、200以外のサイトがあれば、Slackに通知するというようになっています。
（逆に問題が無ければ、Slackには何も通知されません。テストの際には404ページのURLなどを含めてあげてください。） 
全体は以下のようになります。

```health_checker.py
# -*- coding: utf-8 -*-
import requests
import json

# 監視したいサイトのURLを配列で指定
urls = ['https://www.rakuten.co.jp/']


def post_slack_h(c):
    # SlackでIncoming Webhooksを有効にして取得したWebhook URLを記載
    post_url = 'SlackのWebhook URL'
    requests.post(post_url, data=json.dumps({
        "username": "サイト見守るくん",
        'text': c
    }))


targets = []


def status_check(a="", b=""):
    content = ""
    for url in urls:
        try:
            s = requests.get(url, timeout=10).status_code
        except requests.exceptions.ReadTimeout:
            content += url + " Time out(10s)\n"
            targets.append(url)
        except requests.exceptions.ConnectionError:
            content += url + " Connection error\n"
            targets.append(url)
        else:
            if s == 200:
                content += url + " " + str(s) + "\n"
            else:
                content += url + " " + str(s) + "\n"
                targets.append(url)

    if not targets:
        print("All Green!!")
        pass
    else:
        post_slack_h(content)


if __name__ == '__main__':
    status_check()

```

### Slackへの通知はIncoming webhookを利用
Incoming webhookの利用の手順は、以下の公式サポートをご確認ください。
https://slack.com/intl/ja-jp/help/articles/115005265063

## コードのzipファイルを準備
AWS Lambda上で外部パッケージもimportするには外部パッケージのコードもあわせてアップロードする必要があります。
今回使用しているrequestsは外部パッケージなので、メインのコードと一緒にzipファイルにまとめてしまいます。

```shell
# メインコードのあるディレクトリにパッケージファイルを保存
$ pip install requests -t ./
# 圧縮してzipファイルにします
$ zip -r health_checker ./*
```

これでコードと外部パッケージを内包した「health_checker.zip」というzipファイルが出来上がります。

## AWS Lambdaで関数を作成する
AWSでLambdaのリンクをクリックすると、関数一覧の画面に遷移します。
ここの画面から、「関数の作成」をクリックします。
<img width="919" alt="スクリーンショット 2020-03-23 0.05.13.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/8222/93360584-c01a-8803-e866-b9a9fb265646.png">

作成時の初期設定画面では、以下のように設定します

オプション: **一から作成**
関数名: **任意**
ランタイム: **Python 3.7**

<img width="1083" alt="スクリーンショット 2020-03-23 0.06.59.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/8222/81e162a0-5838-316c-8fab-e2198a6f4e95.png">

続いて、関数の編集画面にある「関数コード」という項目からファイルのアップロードをおこないます。
設定は以下の画面のようにします。
特に注意したいポイントは、「ハンドラ」です。
ハンドラは、Lambdaで実行する関数を指定する箇所です。
指定の仕方は**ファイル名(拡張子無し).(指定したファイル内の)関数名**となります。
ですので、ここでは「health_checker.status_check」となります。

<img width="1052" alt="スクリーンショット 2020-03-23 0.31.15.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/8222/1c3dcc7d-5d6f-870d-9807-89f8caf2b89c.png">


## 定期実行の設定
ここまでで作成したコードをLambda上で実行するまでは整いました。
最後にコードを定期的に実行するように設定します。

関数の編集画面から「**＋トリガーを追加**」をクリックします。
（下の画像は既に追加済みの完成形です）
<img width="1060" alt="スクリーンショット 2020-03-23 0.42.36.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/8222/95ef06be-736f-30e7-8ca8-1c206d48d203.png">

トリガーの作成画面では以下のように設定します。
スケジュールは、Cronで1時間毎に実行という指定をしてみます。
`cron(0 0/1 * * ? *)`
0/1の部分を0/2, 0/5などとすれば2時間毎、5時間毎と間隔を変更することができます。
<img width="741" alt="スクリーンショット 2020-03-23 0.52.30.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/8222/9ad70890-5d40-353e-204a-c2c62079ba1c.png">

## 備考：エラー「time out after 3.00 seconds」への対策
複数のサイトや読み込みに時間のかかるサイトを監視すると、Lambdaのデフォルト設定のタイムアウト時間3秒を超えてしまうことがあります。

それを回避するために、Lambda関数編集画面の中ほどより少し下の「基本設定」からタイムアウト時間を調整します。
<img width="763" alt="スクリーンショット 2020-03-23 1.02.24.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/8222/5942ecec-7bb5-5854-2f50-c4f6158c4d96.png">

## 最後に
Slackの通知内容の見た目にもこだわりたい方は、attachmentの書式なども活用すると表現の幅が広がります！

参考にどうぞ
https://qiita.com/m-nakada/items/643909ca14f306a74999

以上、お疲れ様でした