端くれプログラマの備忘録 PHP [PHP] レスポンスタイムを計測する監視スクリプト

[PHP] レスポンスタイムを計測する監視スクリプト

仕事先が契約しているデータセンターのウェブサーバーがもう笑うしかないぐらい不安定。僅かなアクセスしか無いにも関わらず、気が付くとサーバーは落ちてるし、502、503、504のエラーが返るのも日常茶飯事。24時間通算してどれぐらい不具合が起きているのだろうか?と気になったので監視スクリプトを作ってみた。

監視スクリプトの仕様

  • 監視スクリプトはターゲットのサーバーとは別の安定したサーバーに置く。
  • 監視スクリプトはPHPで書いてcronで5分ごとに実行させる。
  • ターゲットのサーバーから特定URLをGETするのに要した時間をログに書き出す。

ネットを調べるとpingコマンド利用のサーバー死活監視スクリプトが多数ヒットしたけど、僕が必要なのはブラウザにページが表示されるまでの体感時間なので、HTTPのGETのレスポンスタイムを計測するのが現実的かと。サーバーが完全に死んでいたらタイムアウトになるだろうし。

監視スクリプト

以下のようなスクリプトを作成した。HTTPリクエストの実行にはPEARのHTTP_Requestを利用。logsというサブディレクトリを作成しておくと、日付を名前にしたCSVファイルが自動生成されて、スクリプトが実行されるたびにログが追記される仕組み。監視するURLは複数指定可能にした。

<?php
 
error_reporting(E_ALL ^ E_NOTICE ^ E_DEPRECATED);
 
set_include_path("." . PATH_SEPARATOR . "/xxx/xxx/pear/php" . PATH_SEPARATOR . get_include_path());
 
require_once "HTTP/Request.php";
 
function logging($message)
{
    $file = dirname($_SERVER['SCRIPT_FILENAME']).'/logs/'.date('Ymd').'.csv';
 
    $fh = fopen($file, 'a');
    for ($i = 0; $i < 5; $i++) {    // retry loop
        if (flock($fh, LOCK_EX)) {
            fwrite($fh, $message);
            fflush($fh);
            flock($fh, LOCK_UN);
            break;  // success
        }
        sleep(1);   // wait
    }
    fclose($fh);
}
 
function logging_succeess($ptime, $url, $code, $header)
{
    $data = $ptime . "," . date('Y/m/d H:i:s') . "," . $code . "," . $url . "\n";
    if ($code != 200) {
        $data .= print_r($header, true) . "\n";
    }
    logging($data);
}
 
function logging_failed($ptime, $url)
{
    $data = $ptime . "," . date('Y/m/d H:i:s') . "," . "FAILED," . $url . "\n";
    logging($data);
}
 
$urls = array();
$urls[] = "http://www.site1.com/index.html";
$urls[] = "http://www.site2.com/index.php";
$urls[] = "http://www.site3.com/index.html";
$urls[] = "http://www.site4.com/index.php";
$urls[] = "http://www.site5.com/index.html";
$urls[] = "http://www.site6.com/index.php";
 
$option = array(
    "timeout" => "10",
    "allowRedirects" => true,
    "maxRedirects" => 3,
);
 
foreach ($urls as $url) {
    $http = new HTTP_Request($url, $option);
    $http->addHeader("User-Agent", "SiteMon");
    $http->addHeader("Referer", "http://www.myserver.com/");
 
    $stime = microtime(true);
    $response = $http->sendRequest();
    $etime = microtime(true);
    $ptime = $etime - $stime;
 
    if (!PEAR::isError($response)) {
        $code    = $http->getResponseCode();
        $header  = $http->getResponseHeader();
        $body    = $http->getResponseBody();
        $cookies = $http->getResponseCookies();
        logging_succeess($ptime, $url, $code, $header);
    } else {
        logging_failed($ptime, $url);
    }
}
 
?>

実行例

以下にログファイルの抜粋を例として示す。各行先頭から処理時間(秒)、実行日時、ステータスコード、URLの順にカンマ区切りで記録される。ステータスが200以外のときはレスポンスヘッダの配列ダンプも追記される。

0.17917799949646,2014/05/19 23:35:01,200,http://www.site1.com/index.html
0.41295695304871,2014/05/19 23:35:02,200,http://www.site2.com/index.php
0.073950052261353,2014/05/19 23:35:02,200,http://www.site3.com/index.html
15.073293924332,2014/05/19 23:35:03,408,http://www.site4.com/index.php
Array
(
 [cache-control] => no-cache
 [connection] => close
 [content-type] => text/html
)
0.0778648853302,2014/05/19 23:35:32,503,http://www.site5.com/index.html
Array
(
 [cache-control] => no-cache
 [connection] => close
 [content-type] => text/html
)
3.459300994873,2014/05/19 23:35:39,200,http://www.site6.com/index.php