PythonとSlackでサイトの監視アラートを流す[AWS Lambda & CloudWatch]

Slack, AWS Lambda, Python alive monitoring

Slackは色々hackできるから楽しい。

Python3で、WEBサイトのステータスを自動かつ定期的にチェックして、200(正常)以外ならその結果をSlackに流す、という死活監視Botを作ってみた。その備忘録です。

自動で実行したいので、Python3のソースコードをAWSのLambdaに置き、CloudWatchのcronで二時間に一度、定期実行するようにする。

こんな人向けの記事

すでにAWSとSlackアカウントを持っていて、かつPythonの開発環境がすでに構築されている人が対象です。僕自身はWeb Analystなのでピュアなエンジニアではないけれど、そんな人でもSlackを便利にできるよというTipsのつもり。

(1)SlackのWebhook URLを取得する

まずSlackに自動投稿するための設定をする。

SlackのApps管理画面にアクセスする(SlackのAPI管理画面って導線が結構分かりづらい)。

https://api.slack.com/apps

「Create New App」をクリック


作成するApp Nameは何でもOK。「Development Slack Workspace」ではBotをPostするWorkspaceを選ぶ


Incoming Webhooksの設定画面に進んで「ON」にすると「Add New Webhook to Workspace」ボタンが出るので次に進む



BotがPostするチャンネルを選んで「Allow」


Allowすると先ほどのページに戻ってくるので、生成されたWebhook URLをcopyする(後ほど書くPythonコードで使う)


(2)Pythonコードの準備

Python3でコード書きます。

# -*- coding: utf-8 -*-

import requests
import json

urls = ['https://www.example.com']

def post_slack_h(c):
  post_url = 'SLACK_WEB_HOOK_URL'
  requests.post(post_url, data = json.dumps({
    'text': c,
  }))

targets = []

def status_check(a="",b=""):
  content = "*Alive monitoring*"   "\n\n"
  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)
  content  = "\n\nThis notification is sent only if the result involves the off-normal status. This bot is scheduled every two hour.\n"

  if not targets:
    pass
  else:
    post_slack_h(content)

9行目のSLACK_WEB_HOOK_URLには先ほど生成したURLを使う。

20行目ではタイムアウトを10秒に指定している。

status_check関数に適当な引数を設定している理由は、AWS Lambda実行の際に引数がないとエラーになったから(確か)。

どの関数を実行するかはAWS Lambda上で指定するので、ソース自体はシンプルな形にしておく。

(3)Pythonコードのzipファイルを準備(AWS Lambdaへのアップロード用)

AWS Lambda上でPythonを直接書いて動かしたりするだけなら簡単だけど、外部パッケージもimportするには一手間必要

上記のソースではrequestsjsonというパッケージをimportしているが、requestsは外部パッケージなので、インストールしてソースと一緒にzipファイルにまとめる必要がある(jsonは標準ライブラリ)。

ちなみにパッケージインストーラーはpip(なのでpipが動く環境という前提でおなしゃす)。

$ cd /{pythonコードを実行するディレクトリ}
$ pip install requests -t ./
$ zip -r py_health_check ./*

これでPythonコードや外部パッケージを内包した「py_health_check.zip」というzipファイルが同じディレクトリに出来上がっているはず。

(4)AWS Lambdaにアップロード

AWS管理画面を開いて、Lambdaに移動


新しく関数を作成


関数作成画面では、
「一から作成」を選択、
「関数名」は何でもOK、
「ランタイム」は「Python3.6」を選択


作成された関数の編集画面に遷移するので、
「コードエントリタイプ」から「.zipファイルをアップロード」を選択して先ほどのzipをアップロード(成功すると下のフォームにソースコードが展開される)、
「ランタイム」が「Python 3.6」であることを確認、
「ハンドラ」は「{ファイル名}.{実行する関数名}」というフォーマットなのでhealthcheck.status_checkにする


(5)テスト

正しく動くかテストする。

ちなみに今回初めて知ったんだけど、example.comはステータスコード200を返すみたいなのでチェックするURLは適当にhttps://www.exampleddddddddddddddddd.comみたいなのにしましょう。

Lambda右上の「テスト」をクリック


「イベント名」は適当でいいのでそのままテストを「作成」し、もう一度右上の「テスト」をクリック


すると、実行ログが出力されます。グリーンは成功やね


さてSlackのチャンネルを見てみよう。

無事投稿されておりました。


ちなみに上述のPythonコードでは、試したWEBサイトのURLが200を返してしまう(=正常)とSlackには何もPostされない。テスト時に注意。

(6)AWSのCloudWatchを使ってCron処理化

やっと!終わりに近い!(スクショ撮るの大変だった。世のブロガーすごい)

「あるURLのステータスをチェックして200以外ならSlackにアラートをPostする」という処理自体は完成したので、あとはこれを定期処理化する。

AWSの関数編集画面で「トリガーを追加」


「トリガー」ではCloudwatch Eventを選択
「ルール」は新規ルールの作成
「ルール名」は適当に。「」スペースは使えないので「every_2_hour」とか無難
「ルールタイプ」は「スケジュール式」で、式はcron(0 0/2 * * ? *)と記述


完了!

下のような表示になったらOK。これで二時間に一度、死活監視Botが仕事をしてくれるはず。おつかれさまー。


おまけ

Lambdaはソースコードのzipファイルをアップロードし直すのが中々しんどいので、Webhook URLやWEBサイトURLなどはLambda環境変数を使ってAWS管理画面から編集できるようにしておくといいと思う。

また、Slackに投稿するアプリ名やアイコン画像はSlackのAppsページのBasic Informationから変えられる。

Written by Ryo Konishi