swatch でログを監視しよう

swatch とはログの監視に使用できるツールで、perl で書かれています。ログをリアルタイムで監視し、特定の文字列が書き込まれたらメールで管理者に通知することができます。
メールで通知をする以外にも、コンソールにメッセージを出したり、特定のコマンドを実行したりすることができます。
以下のページが参考になります。


なお、今回Swatch を試した環境は以下のようになります。

インストール

swatch はいくつかのモジュールに依存しているので、まずはそれらをインストールする必要があります。ソースからインストールする方法もありますが、今回はCPAN からインストールします。ソースからインストールする場合は、直前に紹介した参考ページを参考にして下さい。
それでは、モジュールを1つずつインストールします。

$ sudo cpan -i Bit::Vector
$ sudo cpan -i Date::Calc
$ sudo cpan -i Date::Parse
$ sudo cpan -i Date::Manip
$ LC_ALL=C sudo cpan -i Time::HiRes
$ sudo cpan -i File::Tail

swatch をインストール

swatch はソースからインストールします。

$ mkdir ~/src
$ cd ~/src
$ wget http://jaist.dl.sourceforge.net/sourceforge/swatch/swatch-3.2.1.tar.gz
$ tar zxvf swatch-3.2.1.tar.gz
$ cd swatch-3.2.1
$ perl Makefile.PL 
$ make
$ make test
$ sudo make install

swatch を使ってみよう

実際にswatch を使ってみます。swatch を使うには、設定ファイルを用意する必要があります。今回は、ファイル中に「WARN」という文字列が書き込まれたら通知を出すことにします。
通知方法は、「コンソールに検知された行を表示する」とします。

設定ファイルの準備

設定ファイルは「.swatchrc」という名前でホームディレクトリ以下に作成します。内容な以下のようになります。

  • ~/.swatchrc
watchfor /WARN/
   echo


設定ファイルの意味は、正規表現で監視するパターン(/WARN/)を指定し、その次の行に通知方法を記述します。今回の通知方法は「echo = コンソールに表示」です。

swatch の起動

swatch を起動する際には、引数として、「設定ファイル」と「監視するファイル」を指定します。監視するファイルに対してread 権限を持つユーザで起動する必要があります。
今回は、監視対象のファイルとして「~/hoge.txt」を作成します。

$ touch ~/hoge.txt


それでは、swatch を起動します。

$ swatch -c ~/.swatchrc -t ~/hoge.txt &
....

*** swatch version 3.2.1 (pid:29623) started at Wed Oct 22 18:37:41 JST 2008


swatch version....」と表示されたまま止まりますが、RET を押して、通常の状態に戻ることができます。

ファイルに「WARN」を含む文字列を書き込んでみる

では、監視対象のファイルに「WARN」を含む文字列を書き込んでみましょう。

$ echo "[WARN] This is test warning message." >> ~/hoge.txt 


文字列を書き込むと直ぐに書き込んだ文字列がコンソールに表示されます丶(´▽`)ノ

メールで通知を受け取る

先程はecho で通知を受け取りましたが、最後にメールで受け取る設定を紹介します。
メールエージェントとしてはsendmail を使用します。特に設定はいじらず起動します。

$ sudo /etc/init.d/sendmail start
Starting sendmail:                                         [  OK  ]
Starting sm-client:                                        [  OK  ]
設定ファイルを書きかえる

設定ファイルを以下のように書き換えます。通知手段を「mail」にし、送信先を指定します。送信先は、「hoge@hoge.example」とします。

  • ~/.swatchrc
watchfor /WARN/
   mail=hoge@hoge.example,subject=[swatch]$ENV{'HOSTNAME'}
ソースを書き換え、監視文字列を検知した時にメールを送信するようにする

今回僕がインストールしたswatch だと、そのままでは通知メールを送信することができませんでした。上記の設定ファイルを指定してswatch を再起動し、hoge.txt に「WARN」を含む文字列を書き込むと、メールは送信されず、キュー入ってしまいます。

$ echo "WARN" >> hoge.txt     # メールは送信されない
$ mailq -Ac                   # キューを確認すると、キューの中にたまっていることが分かる
/var/spool/clientmqueue (1 request)
-----Q-ID----- --Size-- -----Q-Time----- ------------Sender/Recipient-----------
m9M6w1gc028830 7 Wed Oct 22 15:58 admin
                                  hoge@hoge.example
Total requests: 1


特に負荷がないのにキューにたまるのは不思議です。swatch のソースを見てみます。

$ grep "sendmail" -r ~/src/swatch-3.2.1/lib/
/home/admin//src/swatch-3.2.1/lib/Swatch/Actions.pm~:    foreach my $mailer (qw(/usr/lib/sendmail /usr/sbin/sendmail)) {
/home/admin//src/swatch-3.2.1/lib/Swatch/Actions.pm:    foreach my $mailer (qw(/usr/lib/sendmail /usr/sbin/sendmail)) {


$mailer が送信プログラムを表すっぽいです。さらにgrep

$ grep "\$mailer" -r ~/src/swatch-3.2.1/lib/
/home/admin//src/swatch-3.2.1/lib/Swatch/Actions.pm~:    foreach my $mailer (qw(/usr/lib/sendmail /usr/sbin/sendmail)) {
/home/admin//src/swatch-3.2.1/lib/Swatch/Actions.pm~:      $args{'MAILER'} = $mailer if ( -x $mailer );
/home/admin//src/swatch-3.2.1/lib/Swatch/Actions.pm:    foreach my $mailer (qw(/usr/lib/sendmail /usr/sbin/sendmail)) {
/home/admin//src/swatch-3.2.1/lib/Swatch/Actions.pm:      $args{'MAILER'} = $mailer if ( -x $mailer );


$args{'MAILER'} が送信プログラムを表すっぽいです。さらにgrep

$ grep "MAILER" -r ~/src/swatch-3.2.1/lib/
/home/admin//src/swatch-3.2.1/lib/Swatch/Actions.pm~:# send_email -- send some mail using $MAILER.
/home/admin//src/swatch-3.2.1/lib/Swatch/Actions.pm~:  if (! $args{'MAILER'} ) {
/home/admin//src/swatch-3.2.1/lib/Swatch/Actions.pm~:      $args{'MAILER'} = $mailer if ( -x $mailer );
/home/admin//src/swatch-3.2.1/lib/Swatch/Actions.pm~:    if ($args{'MAILER'} ne '') {
/home/admin//src/swatch-3.2.1/lib/Swatch/Actions.pm~:      $args{'MAILER'} .= ' -oi -t -odq';
/home/admin//src/swatch-3.2.1/lib/Swatch/Actions.pm~:  open(MAIL_PIPE, "| $args{'MAILER'}")
/home/admin//src/swatch-3.2.1/lib/Swatch/Actions.pm~:    or (warn "$0: cannot open pipe to $args{MAILER}: $!\n" and  return);

.....


いた!怪しいのがいた!

$args{'MAILER'} .= ' -oi -t -odq';


明らかにオプションを追加している。man で調べる。

$ man sendmail


「-t」オプションは、「CC」、「BCC」を指定できるようにする。「-o」についてはTHE WHOLE SCOOP ON THE CONFIGURATION FILE を見ろって書いてあったので見ると、次のような意味だった。

  • 「-oi」: sendmail のbody の終端を表す「.」を本文に含まない
  • 「-odq」: 「-od」で送信方法を指定。次の「q」はキューに入れることを意味していた


ということで、ソースを書き換える。

  if (! $args{'MAILER'} ) {
    foreach my $mailer (qw(/usr/lib/sendmail /usr/sbin/sendmail)) {
      $args{'MAILER'} = $mailer if ( -x $mailer );
    }
    if ($args{'MAILER'} ne '') {
-      $args{'MAILER'} .= ' -oi -t -odq';
+      $args{'MAILER'} .= ' -oi -t';
    }
  }


再度swatch をビルドする。

$ cd ~/src/swatch-3.2.1
$ perl Makefile.PL 
$ make
$ make test
$ sudo make install


これで、swatch を起動し、先程の設定ファイルを読み込ませ、監視対象のファイルに「WARN」を含む文字列が書き込まれると、メールが送信されるようになりました。
また、以下のように書くと、最初にパターンが検知されてから10秒間は検知されなくなります。負荷が心配な場合は設定すると良いと思います。詳細はman 参照。

  • ~/.swatchrc
watchfor /WARN/
   mail=hoge@hoge.example,subject=[swatch]$ENV{'HOSTNAME'}
   threshold track_by=/WARN/,type=limit,count=1,seconds=10
感想

今回はソースを書き換える方法をとりましたが、もっといい方法があると思います。そもそも、何故デフォルトがキューに書き込む操作になっているかが分からなかったです。
ちなみに、ソースを書き換えなくても、設定ファイルでキューのメールを強制送信してしまうこともできます。ただ、この場合、キューにたまっている全てのメールが送信されてしまう問題があります。

  • ~/.swatchrc
watchfor /WARN/
   mail=hoge@hoge.example,subject=[swatch]$ENV{'HOSTNAME'}
   exec sendmail -q -Ac
追記

sendmail で一回キューに入ったメールはデフォルトで1時間後に再送信される設定になっています。

$ cat /etc/sysconfig/sendmail 
DAEMON=yes
QUEUE=1h


これは、「通常キューに入る場合 = 現時点では負荷が高い」という前提で設定されています。なので、やはりswatch がデフォルトでキューに入れるという動作はやっぱり疑問です。