MRTG にて qmail の送受信のメール数をカウントしようと、 qmailmrtg をインストールしようとするが、 multilog やら qmail の起動スクリプトの変更やら、後々面倒そう。 ということで、カウント用のプログラムをちょいと作る。
logcount.pl
Debian には、log 関係のプログラムも色々あるみたいだけど、 設定もややこしそうで、Perl FN ログ整理ということで『C で高速化?』とも思ったが、汎用性を考えると正規表現は 欲しいし、試しに作った Perl でも十分すぎる速度であった。 /FN で作ってみる。
設定ファイル記録した正規表現に、パターンマッチした行の数をカウントすることにする。 またリアルタイムに計数したいので、前回読み込み終了した場所を保存しておき、 次回は seek で途中から行うことにする。
≪ /etc/mrtg.d/qmail.conf : qmail の受信・送信の履歴をカウントする正規表現ファイル ≫ \w+ qmail: \d+\.\d+ starting delivery \d+: msg \d+ to remote \w+ qmail: \d+\.\d+ starting delivery \d+: msg \d+ to local ≪ /etc/cron.d/qmail-smtp : 5分おきにログファイルをカウント ≫ 1-56/5 * * * * root if [ -x /etc/mrtg.d/logcount.pl ]; then /etc/mrtg.d/logcount.pl -c /etc/mrtg.d/qmail.conf -s /var/run/logcount.txt /var/log/syslog 2>&1; fi ≪ /etc/mrtg.d/qmail-mrtg.sh : MRTG 用のデータを作るプログラム ≫ #!/bin/bash /usr/bin/tail +2 /var/run/logcount.txt | /usr/bin/head -2 /usr/bin/uptime | cut -d, -f 1 echo qmail ≪ /etc/mrtg.d/logcount.pl : カウントするプログラム ≫ #!/usr/bin/perl use Getopt::Std ; # カウント情報を保存するファイル $stats = "/var/run/logcount.txt" ; # Usage: logcount.pl -c 設定ファイル -s 計数ファイル ログファイル # 設定ファイル # 1行毎にログファイルとパターンマッチする正規表現を記載 # 計数ファイル # 先頭行は、最後に読み込んだファイル位置 # 残りの行は、パターンマッチした行の数 getopts( "c:s:" ) ; $config = $opt_c if ( $opt_c ne "" ) ; $stats = $opt_s if ( $opt_s ne "" ) ; # 設定ファイルの読み込み open( CONF , "$config" ) || die( "Can't open $config\n" ) ; for( $size = 0 ; $line = ; $size++ ) { next if ( $line =~ /^#/ ) ; $line =~ s/\s+$// ; $regex[ $size ] = $line ; } close( CONF ) ; # 計数ファイルの読み込み if ( ! -f "$stats" ) { open( STAT , ">$stats" ) || die( "Can't open $stats\n" ) ; close( STAT ) ; } $seek = 0 ; if ( open( STAT , "+<$stats" ) ) { $seek = 0 + ; for( $j = 0 ; ($j < $size) && ($line = ) ; $j++ ) { $count[ $j ] = 0 + $line ; } } # ログファイルを開く $logfile = shift( @ARGV ) if ( @ARGV > 0 ) ; open( LOG , "$logfile" ) || die( "Can't open $logfile\n" ) ; @stat = stat( LOG ) ; if ( $stat[ 7 ] < $seek ) { $seek = 0 ; # 切り詰められたら先頭から読み直し } else { seek( LOG , $seek , SEEK_SET ) ; } # ログファイルの読み込み while( $line = ) { #print $line ; if ( $line =~ /\n$/ ) { ($date , $logdata) = ($line =~ /^(\w+\s+\d+\s\d+:\d+:\d+)\s+(.*)$/) ; # パターンマッチする表現を求める for( $i = 0 ; $i < $size ; $i++ ) { $rex = $regex[ $i ] ; if ( $logdata =~ /$rex/ ) { $count[ $i ]++ ; break ; } } $seek = tell( LOG ) ; } else { last ; # 追記中で行末が無いデータなら処理せず終了 } } close( LOG ) ; # 計数ファイルを更新 seek( STAT , 0 , SEEK_SET ) ; print STAT "$seek\n" ; for( $i = 0 ; $i < $size ; $i++ ) { print STAT $count[ $i ]."\n" ; } close( STAT ) ;