このブログはmixhostのレンタルサーバーで運営してますが、サポートの対応は良いものの設立して1年未満の会社なのでサーバーの安定には少し不安があったので、RaspberryPiでサーバーを監視して落ちたらメールで通知するプログラムを作ろことにしました。
mixhostは2017年6月22日で会社設立1年を迎えたそうです。
サーバー監視と言ってもHTTPステータス値を監視するだけのプログラムです。始め(5月頃)はシェルスクリプトで5秒間隔で監視してましたが、記録してるログ確認するとHTTPステータス値が取得できてなくても、アクセスするとサイトが表示されてるらしいので、RaspberryPiで外部ネットワークに接続できていないのではと疑問があったので、今度はPythonでサイトが落ちてたらメールで通知サーバー監視プログラムを作り6月19日から運用してます。
今まではサイトが落ちた時間しか分からなかったので、落ちてから再開した時間もログに記録できるようにしました。また、ラズベリーパイが外部ネットワークに接続してるかを確認するために、新たにGoogleのHTTPステータスをチェックするようにもしました。
サーバー監視プログラムと言うと立派なように聞こえますが、一個人が自サイトが落ちたかチェックするだけのプログラムなので効率が悪かったり見苦しい点もいくつかあります。
まあ僕のメモ用に書いていきます。
サーバー監視プログラムの流れ
数回プログラムを修正していますが、基本的な流れです。cronで1分間隔で実行してます。
まず始めにサイトのHTTPステータスをチェックします(以後、HTTP値)。
- 自サイトのHTTP値を取得
- GoogleのHTTP値を取得
- RaspberryPiの現在時刻取得
自サイトのHTTP値が200以外かつGoogleのHTTP値が200の場合
- 自サイトのHTTP値をTMPファイルに書き込み
- CSVファイルにログを記録(現在時刻、自サイトHTTP値、GoogleHTTP値)
- 自サイトが落ちたとメールで通知(現在時刻、自サイトHTTP値)
自サイトのHTTP値が200以外かつGoogleのHTTP値も200以外の場合
- RaspberryPiでネットワーク(外部)に繋がらないと判断して何もしない
自サイトのHTTP値が200の場合
- HTTP値を記録したTMPファイルを読み込み
TMPファイルに記録したHTTP値が200以外の場合
- 接続再開としてCSVファイルに記録(現在時刻、自サイトHTTP値、GoogleHTTP値)
- 再接続したとメールで通知(現在時刻、自サイトHTTP値)
TMPファイルに記録したHTTP値が200の場合
- 何もしない
GoogleのサイトのHTTP値をチェックするのは外部ネットワークに繋がってるか判断するためです。
サイトが落ちて再開した時にもメールで通知するようにしましたが、落ちてる時間は1分間隔でしか分かりません。
最初はこれで監視してたんだけど、監視する間隔を5秒から1分に変更にしても一瞬HTTP値が取得できない状態は変わらず続いて、ラズパイでサイトが落ちたと判断してもサイトにアクセス出来ていたのでプログラムを修正しました。
- 自サイト(1度目)のHTTP値を取得
- GoogleのHTTP値を取得
- 自サイト(2度目)のHTTP値を取得
- RaspberryPiの現在時刻取得
自サイトのHTTP値を2度取得して、GoogleのHTTP値が正常で自サイトが2回とも落ちてたらログを記録して、メールを通知するように変更しました。
連続して2回取得すと外部ネットワークに繋がらないままかもしれないので、間にGoogleのHTTP値を取得して少し時間を置いてチェックしてます。これがいい方法か分かりませんが、2回チェックしてエラーならサイトが落ちたと判断することにします。
しかし、ラズベリーパイで外部ネットワークにアクセスできない原因が分からないです。回線のモデムの電源落としたり存在しないURLでHTTPステータスコードを取得しようとするとエラーで取得できなくなるのですが、通常インターネットにつながる状態でも同じ症状になります。
この時パソコンからラズベリーパイにTera TermでSSH接続しても繋がったままなので何処で接続できなくなるのか不明です。レンタルサーバーにSSH接続してても接続が切れないのも謎です。
プログラムのコード
とりあえずプログラムのコードを残しておきます。プログラムを実行して直後に3回HTTPステータスをチェックするのも効率悪いので「自サイト(1度目)のHTTP値が200以外かつGoogleのHTTP値が200の場合」の時のみ自サイト(2度目)のHTTP値を取得してます。
ソースコードそのままですが、メールアカウントやURLの情報など一部加工してます。
#!/usr/bin/env /usr/bin/python # -*- coding: utf-8 -*- print "testpi" import requests import os from datetime import datetime #ファイル読み込み関数 def file_r(file_name): f = open(file_name,'r') for row in f: var = row.strip() f.close() return var #HTTPステータスチェック関数 def http_status(url_tmp): try: httpst_tmp = requests.get(url_tmp) return httpst_tmp.status_code except : httpst_tmp = "error" return httpst_tmp #メール送信 def mail_smtp(mail_title, mail_text): import smtplib from email.MIMEText import MIMEText from email.Header import Header from email.Utils import formatdate FROM_ADDR = "送信元メールアドレス" TO_ADDR = "送信先メールアドレス" ENCODING = "iso-2022-jp" message = MIMEText(mail_text.decode('utf-8').encode(ENCODING),"plain",ENCODING,) message["Subject"] = str(Header(mail_title.decode('utf-8'),ENCODING)) message["From"] = "%s <%s>" %(str(Header(u"ラズベリーパイ",ENCODING)),FROM_ADDR) message["To"] = "%s <%s>" %(str(Header(u"サイト接続情報",ENCODING)),TO_ADDR) message["Date"] = formatdate() s = smtplib.SMTP("メール送信サーバー", ポート番号) s.ehlo() s.starttls() s.login("ユーザーアカウント", "パスワード") s.sendmail( FROM_ADDR, [TO_ADDR], message.as_string(), ) s.close() #utf-8 → shift-jis 変換 def utf_shit(text): text = text.decode('utf-8') text = text.encode('shift-jis') return text #プログラム開始 #変数用意 time = datetime.now().strftime("%Y/%m/%d %H:%M:%S") time_m = datetime.now().strftime("%Y%m") url1 = http_status('http://example.net/') #自サイト url2 = http_status('http://example2.net/') #Google print "url1:" + str(url1) print "url2:" + str(url2) print time_m #サーバーチェックcsv作成 if os.path.exists('/var/samba/HTTP/log/http-error-' + time_m + '.csv'): print "" else: f = open('/var/samba/HTTP/log/http-error-' + time_m + '.csv' , "w") f.write(str(utf_shit("時間,mixhost,Goole,状態\n"))) f.write(utf_shit(str(time)) + utf_shit(",") + utf_shit(str(url1)) + utf_shit(",") + utf_shit(str(url2)) + utf_shit(",監視実行\n")) f.close() #httpコード作成 if os.path.exists('/var/samba/HTTP/http-code.tmp'): print "" else: f = open('/var/samba/HTTP/http-code.tmp' , "w") f.write(str("200")) f.close() if url1 != 200: if url2 != 200: print "回線不良" else: print '再チェック:http://example.net/' url3 = http_status('http://example.net/') url1 = url3 print "url3:" + str(url3) if url1 != 200: print "ファイル読み込み" if file_r("/var/samba/HTTP/http-code.tmp") == "200": f = open('/var/samba/HTTP/log/http-error-' + time_m + '.csv' , "a") f.write(utf_shit(str(time)) + utf_shit(",") + utf_shit(str(url1)) + utf_shit(",") + utf_shit(str(url2)) + utf_shit(",ダウン\n")) f.close() print "ネットワークダウン" f = open('/var/samba/HTTP/http-code.tmp' , "w") f.write(str(url1)) f.close() mail_smtp("サイトダウン", str(time) + "," + str(url1)) else: print "正常" if file_r("/var/samba/HTTP/http-code.tmp") != "200": f = open('/var/samba/HTTP/log/http-error-' + time_m + '.csv' , "a") f.write(utf_shit(str(time)) + utf_shit(",") + utf_shit(str(url1)) + utf_shit(",") + utf_shit(str(url2)) + utf_shit(",接続\n")) f.close() f = open('/var/samba/HTTP/http-code.tmp' , "w") f.write(str(url1)) f.close() mail_smtp("サイト再接続", str(time) + "," + str(url1)) else: print "正常" if file_r("/var/samba/HTTP/http-code.tmp") != "200": f = open('/var/samba/HTTP/log/http-error-' + time_m + '.csv' , "a") f.write(utf_shit(str(time)) + utf_shit(",") + utf_shit(str(url1)) + utf_shit(",") + utf_shit(str(url2)) + utf_shit(",接続\n")) f.close() f = open('/var/samba/HTTP/http-code.tmp' , "w") f.write(str(url1)) f.close() mail_smtp("サイト再接続", str(time) + "," + str(url1)) print '処理終了'
関数の使い方や文字コードの変換法など非効率と感じる部分がありますが、まあ今の僕はこれが精一杯です。ソースコードはメモ用なのでほぼそのまま貼り付けています。
プログラムは色々修正して現在に至ってます。ログの情報は7月になったら今月(6月)の状態を報告しようかと思います。