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

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」をクリック

slack1

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

slack2

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

slack3

slack4-1

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

slack6

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

slack7

(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に移動

slack14

新しく関数を作成

slack15

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

slack16

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

slack17

(5)テスト

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

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

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

slack18

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

slack22

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

slack23

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

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

slack11

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

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

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

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

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

slack31

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

slack32

完了!

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

slack34

おまけ

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

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