先日データーセンターでネットワークトラブルがあって、そのトラブルそのものはうちの問題ではなかったので、おまかせにしていたら数時間で復旧したのだが、トラブルに弊社が気づくのが遅れてしまい、お客様に余計な心配をかけてしまった。
そんなわけで、外部のサーバーからWebサーバーの稼働状況を監視するPerlスクリプトを作成して、Cronでぶんまわすことにした。
仕組み
仕組みはとても簡単で、ざっと以下のような感じ。
- コマンドライン引数に渡されたURLに対してwgetを実行する。
- 実行した結果を評価して、エラーがあればメールを送信する。
という感じ。
wgetコマンドを実行する際に実際にファイルをダウンロードしちゃうと面倒なので、以下のようなオプションをつけた。
my $com = "/usr/bin/wget -q -o /dev/null --spider '".$url."'";
ちなみに、pingだとネットワークトラブルしか検出できないが、wgetならネットワークが生きていてapacheが死んでるなんていうシチュエーションも拾ってくれる。
使い方
以下のように、このPerlスクリプトにURLを引数で渡して、Cronに登録する。
*/10 * * * * /path/to/lifecheck.pl http://www.example.com/
ちなみに、Cronに自前スクリプトを登録する際は環境変数によって挙動が変わったりするので、以下のように環境変数をundefしちゃうと都合が良いと個人的に思うのだが。みんなはどうしているんだろう?
undef %ENV;
ソース
以下のソースをコピペして、lifecheck.plというファイル名で任意のパスに保存する。
#!/usr/bin/perl -wT
undef %ENV;
use strict;
use warnings;
use Encode;
use utf8;
use Mail::Sendmail;
my $from = 'admin@example.com';
my $to = 'you@example.com';
my $reg = q{^https?://[-_.!~*'()a-zA-Z0-9;/?:@&=+$,%#]+$};
my $in = shift @ARGV;
my $url = '';
if ($in =~ /($reg)/) {
$url = $1;
}
if (!$url) {
die('url?');
}
$url =~ s/'/'\''/g;
my $com = "/usr/bin/wget -q -o /dev/null --spider '".$url."'";
system($com);
if ($?) {
&mailto(
$from,
$to,
'['.$url.'] Alert',
"Can not connect Web Server.\nPlease check below.\n".$url
);
}
sub mailto
{
my ($from, $to, $subject, $body) = @_;
$subject = encode('MIME-Header-ISO_2022_JP', $subject);
$body = encode('iso-2022-jp', $body);
my %mail;
$mail{'Content-Type'} = 'text/plain; charset="iso-2022-jp"';
$mail{'From'} = $from;
$mail{'To'} = $to;
$mail{'Subject'} = $subject;
$mail{'message'} = $body."\n";
sendmail %mail;
}