WEBサーバの死活監視の1つとして有効的なのがURLチェックです。
PINGコマンドでドメイン名を指定してもサーバ側(FWなども含む)でPINGに応答しないように設定していると稼動しているのに応答がないといった状況になります。
1番正確に判定しやすいのが、実際にURLにアクセスして目視する。
ですけど、1日に何度も目視なんてしてられませんから自動で監視してくれるサービスもあります。
大きな企業になれば自動で監視してくれるサービスにも費用を出して万全の体制がとれますが、あまりお金を掛けられない会社では担当者が毎日WEBサイトにアクセスして死活監視を目視しているということがあります。
また、監視サービスを利用していても、エラーが発生した場合に複数人にEメールメッセージは送信されているが「誰か対応するだろう」といった対応漏れが発生してしまうことも起こります。
Eメールだと他のメールに埋もれて見落としてしまったり、自動メール配信なので迷惑メールとして判定されてしまったりとリスクがあります。
そこで、お金をかけずに複数人でも進捗が把握できるようにチャットワーク(https://go.chatwork.com/ja/)を利用する仕組みを考えました。
【用意するもの】
・常時稼動しているサーバ(インターネット疎通あり)
・PHP7.x系
・Cron
・チャットワークのアカウント(API専用で用意した方がいいです)
※チャットワークについてはこちら(https://go.chatwork.com/ja/)
【確認できること】
ブラウザからHTTP(S)接続してページが見えるかどうか
HTTPアクセスを強制リダイレクトでHTTPSにしているなどアクセス左記がリダイレクトされていてもHTTPステータスコード302が返ってきますので正常稼動していると判定します。
SSL証明書の失効、設定ミスの場合はアクセスが拒否されますのでエラーとして判定されます。
ログイン画面が表示されるものは正常稼動と判定されますが、Basic認証の場合はエラーとして判定されます。
グローバルIPでHTTP接続が可能ならば正常として判定されます。
サーバの応答が異常に遅い場合(応答の状態にもよりけり)もエラー判定されます。
【スクリプト】
注意点
・監視したいサービス名称を決める際は2バイト文字・半角カナ・記号等は避けてください。サーバ側の設定によっては文字化けファイル名が生成されて全体にエラーを及ぼす可能性があります
・エラーが発生した日時を記録するファイルを生成しますので、ファイルの設置場所には書き込み権限が必要です
・Cronを利用する場合はサーバに余分な負荷をかけないように間隔を調整してください
・チャットワークのAPIは5分間に1000回までですでの余分な動作の実行はしないように調整してください
・チャットワークのルームIDとは対象チャットルームURL(www.chatwork.com/#!rid0000000)の /#!rid 以降の数字です
・.htaccessで404Not Foundを正常なページへ強制リダイレクトさせている場合は正規に存在するファイル(テキストファイルなど)を指定しましょう
必ず書き換えが必要なのは最初の項目の $target と $cwRoomId と $cwTokenCode の部分です。
サーバは稼動しているけども負荷が高くて応答に時間がかかっている場合も分かるように応答時間をシビアに設定しています。
応答時間をゆるくしたい場合は $curlOptions の項目を変更してください。
エラーが発生して対応するまでには時間が必要ですので、何度もお知らせがくるのが嫌な場合は $compTime の値を変更して下さい。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 |
<?php //監視したいサービスを追加します。サービス名称,対象URL //エラー結果を保存するファイルのファイル名に使用しますので2バイト、半角カナ・記号等文字は使用しないようにしましょう。 $target = [ ['EXSMPLE_SERVER1' ,'http://example.com/'], ['EXSMPLE_SERVER1_SSL' ,'https://example.com/'], ['EXSMPLE_SERVER2' ,'http://example.net/hoge.png'], ['EXSMPLE_SERVER2_SSL' ,'https://example.net/'], ['EXSMPLE_SERVER3' ,'http://example.org/'], ['EXSMPLE_SERVER_SUB1' ,'http://sub1.example.com/'], ['EXSMPLE_SERVER1_IP' ,'http://192.0.43.10/'] ]; //対象となるサービスを配列から取得して処理 foreach ($target as $value) { //対象となるサービスの名称 $targetName = htmlspecialchars($value[0], ENT_QUOTES, 'UTF-8'); //対象となるサービスのURL $targetUrl = $value[1]; //対象となるURLのHTTP_CODE取得処理 $resultHttpCode = curlGetInfo($targetUrl); //取得したHTTP_CODEからエラーを判定 if ($resultHttpCode === 0) { echo "{$targetName}はエラーです。<br />\n"; //エラーの場合はエラー時処理を実施 errorAcion($targetName,$targetUrl,$resultHttpCode); }else{ //HTTP_CODEが正常時の処理 echo "{$targetName}は正常({$resultHttpCode})です。<br />\n"; } } //HTTP_CODE取得処理 function curlGetInfo($targetUrl) { $curlGetInfo = null; //curl関数のオプションを指定 $curlOptions = array( CURLOPT_RETURNTRANSFER => true, CURLOPT_HEADER => true, CURLOPT_FAILONERROR => true, CURLOPT_FORBID_REUSE => true, CURLOPT_FRESH_CONNECT => true, CURLOPT_USERAGENT => "curl", CURLOPT_CONNECTTIMEOUT => 10, CURLOPT_TIMEOUT => 5, CURLOPT_MAXREDIRS => 1, ); $ch = curl_init($targetUrl); curl_setopt_array($ch, $curlOptions); $urlCurlResponce = curl_exec($ch); //curlでエラーが発生した場合はHTTP_CODEを0にセット if(!curl_errno($ch)) { $curlGetInfo = curl_getinfo($ch); $resultHttpCode = $curlGetInfo['http_code']; } else { $resultHttpCode = 0; } curl_close($ch); return $resultHttpCode; } //HTTP_CODEがエラー時処理 function errorAcion($targetName,$targetUrl,$resultHttpCode) { //現在日時を取得 $now = date( 'Y-m-d H:i:s' ); //エラー情報ファイル名をセット //ファイル用の別フォルダを作ってもOK $errorFileName = './ErrorFile_' . $targetName . '.txt'; //エラー情報ファイルの存在を確認し、なければ生成 if ( file_exists($errorFileName)) { //エラー情報ファイルの内容を配列に格納 末尾の改行と空白行は除く $errorFileArray = file($errorFileName, FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES); //配列の行数を取得 $num = count($errorFileArray); //最終行のみを取得する for($i = $num - 1; $i == $num - 1; $i--) { //タブ区切りで配列に保存 $getLastLine = explode("\t",$errorFileArray[$i]); //ダブルクォーテーションで記録された日時データからダブルクォーテーションを外す $getLastUpdate = str_replace('"','',$getLastLine[0]); } //頻繁にお知らせメッセージが届かないように判定用経過時間を設定 $compTime = date( "Y-m-d H:i:s", strtotime( "-20 minute" ) ); if ($getLastUpdate > $compTime) { echo "エラー中ですが判定経過時間内ですのでメッセージ送信は実施しません<br />\n"; }else{ //エラー情報ファイルに書き込みを実施 writeErrorFile($now,$targetName,$targetUrl,$resultHttpCode,$errorFileName); //チャットワークにメッセージをPOST echo "エラー発生!メッセージ送信の処理に移行します。<br />\n"; postChatWork($now,$targetName,$targetUrl,$resultHttpCode,$errorFileName); } }else{ echo "ファイル({$errorFileName})が存在しないので新しく生成します。<br />\n"; //エラー情報ファイルを生成 ディレクトリに書き込み権限が設定されていないと生成されません touch($errorFileName); if (file_exists($errorFileName)) { //エラー情報ファイルに書き込みを実施 writeErrorFile($now,$targetName,$targetUrl,$resultHttpCode,$errorFileName); //チャットワークにメッセージをPOST echo "エラー発生!メッセージ送信の処理に移行します。<br />\n"; postChatWork($now,$targetName,$targetUrl,$resultHttpCode,$errorFileName); }else{ //新規でファイルを生成することが出来なかった場合 echo "<strong>エラー情報用のファイルが生成できませんでした。</strong><br />サーバの書き込み権限を確認してください。\n"; } } } //エラー情報ファイルへの書き込み処理 function writeErrorFile($now,$targetName,$targetUrl,$resultHttpCode,$errorFileName) { //エラー情報の書き込みデータ $responseData = [$now , $targetName , $targetUrl , $resultHttpCode]; //エラー情報を追記で書き込み $fp = fopen($errorFileName,'a'); //エラー情報を書き込み実施 タブ区切り fputcsv($fp,$responseData,"\t"); } //チャットワークへのメッセージ送信処理 function postChatWork($now,$targetName,$targetUrl,$resultHttpCode,$errorFileName) { //メッセージを送信したいルームID $cwRoomId = xxxxxxxx; //利用申請で発行されたチャットワークAPIのtoken $cwTokenCode = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"; //POSTするメッセージ内容 $cwMessage = "{$now}:\n{$targetName}({$targetUrl})で監視エラーが発生しました。\n確認してください。"; //メッセージ内容をセット $cwPostData = array( 'body' => $cwMessage ); $curlChatWorkOptions = array( CURLOPT_URL => "https://api.chatwork.com/v2/rooms/{$cwRoomId}/messages", CURLOPT_HTTPHEADER => array( 'X-ChatWorkToken: ' . $cwTokenCode), CURLOPT_RETURNTRANSFER => TRUE, CURLOPT_SSL_VERIFYPEER => FALSE, CURLOPT_POST => TRUE, CURLOPT_POSTFIELDS => http_build_query($cwPostData,'', '&') ); $ch = curl_init(); curl_setopt_array($ch, $curlChatWorkOptions); $cwCurlResponce = curl_exec($ch); //API結果を配列に変換 $cwApiResult = json_decode($cwCurlResponce, true); if (isset($cwApiResult["message_id"])) { echo "チャットワークAPIを使用してメッセージの送信が終わりました。<br />\n"; }else{ echo "<strong>チャットワークAPIの設定が間違っているようです。</strong>メッセージが送信できませんでした。<br />\n"; } curl_close($ch); } |
任意のファイル名でスクリプトを設置したらブラウザからアクセスしてみてください。
://example.com/hoge.php
全てが正常であれば架空のサブドメインを追加してみてください。
エラーがでてチャットワークで指定したチャットルームにメッセージが届けば成功です。
【cronの設定】
あまり頻繁にすると監視先のサーバに負担をかけてしまうので環境に合わせて調整しましょう
1 2 |
//5分毎にチェックする */5 * * * * /usr/bin/php -q /var/www/html/hoge/hoge.php |