« 実行されたSQLを自動的にログへ記録する (PostgreSQL) | メイン | 最大値を取得する »

カテゴリー:ファイル デバグ 

成長するファイルを読み込み続ける

このエントリーを含むはてなブックマーク  livedoorクリップ  成長するファイルを読み込み続けるをdel.icio.usに追加  成長するファイルを読み込み続けるをYahoo!ブックマークに追加  成長するファイルを読み込み続けるをニフティクリップに追加

例えばApacheのアクセスログやエラーログなどは、アクセスがある限り半永久的にデータがファイルに追記(記録)されていく。このような成長し続けるファイルを常に読み込み、表示し続けるにはどうすれば良いだろうか?

原理は簡単だ。
while(<FILE>){print ;} のようなプログラムの場合、ファイルの終端を表すEOF(End Of File)が来たタイミングでPerlの内部にフラグが立ち、それ以上ファイルポインタが先に進まなくなってしまう。

ところが一旦EOFが来たら、seek関数を実行するだけでこのフラグが消えるという性質がある。これを利用するのだ。

#!/usr/bin/perl

;#
;#成長するファイルを追いかける
;#

#------------------------------------------------#
#ライブラリ
#------------------------------------------------#
use strict;

#------------------------------------------------#
#メインルーチン
#------------------------------------------------#
package main;{
    my $file = $ARGV[0] || usage();
    my $sec  = $ARGV[1] || 3;
    my $position = 0;

    #----------------------------#
    #       エラーチェック       #
    #----------------------------#
    die "Not FILE PATH"         if( $file !~ /^([a-zA-Z0-9¥.¥_¥/¥-]{1,})$/ );
    die "Not found ($file)"     if( not -f $file );
    die "Can not READ ($file)"  if( not -r $file );
    die "Not INTEGER ($sec)"    if( $sec and $sec !~ /^([0-9]{1,})$/  );

    #----------------------------#
    #          追跡開始          #
    #----------------------------#
    open(DAT, $file) or die("Can not open ($file) $!");
    for(;;){
        seek(DAT, $position, 0);   #seekするとEOFフラグも解除される

        while(<DAT>){              #現在の末尾(EOF)まで処理する
            #-- 表示 --#
            print ;

            #-- 復帰用に現在位置を取得 --#
            $position = tell(DAT);
        }
        sleep( $sec );
    }
    close(DAT);    #実行されない。気持ち悪いならシグナル処理を入れる

    exit;
}


#------------------------------------------------#
#[function]使用説明、終了
#------------------------------------------------#
sub usage {
    print <<'END_OF_TXT';
使用方法: endless "file" [second]
---
成長するファイルを Ctrl + C などで終了されるまで表示し続ける。
(ログファイルなどをエンドレスにcatする。end-less)
---
  file ..... ファイルのパス。必須。
  second ... ファイルの成長が早い場合は少なく(1〜2)
             そうでない場合は大きな値を設定する(5〜)
             未指定の場合は3。
END_OF_TXT

    exit;
}


まず無限ループ中でファイルを最初から最後まで全て処理する。その後ファイルを閉じないでsleep。EOFフラグ解除のためfseek。ループの最初にもどりまたファイルを表示する処理を行うことで実現できる。ちょっとしたデーモンのように動作する。
 ※Ctrl+Cなどで終了させること。

用途としては例えばエラーログを常に表示する、ファイルにデータが追記された瞬間に何らかの処理を走らせるトリガーとして使用できる。指定した時間にプログラムを実行してくれるcronでは間に合わない要件を満たさないなどの状況に出くわしたらこういった手段も検討すると良いかもしれない。
 ※個人的にはデバグ程度にとどめるのをオススメするが。



余談だが、クックブックにあった以下のコードがこちらの環境(Debian3.2 + Perl5.8)で動作しなかった。

exit if( (stat(FILE))[3] ==3 )

ファイルが削除された、または読み込めなくなった際の処理が必要なのだが、ファイルテスト演算子などもうまく動作しないようだ。これらが分かる方はアドバイスなど求む。


○参考書籍
Perlクックブック〈VOLUME1〉
トム クリスチャンセン ネイザン トーキントン Tom Christiansen Nathan Torkington Shibuya Perl Mongers ドキュメントシステム
オライリージャパン (2004/09)
売り上げランキング: 58379




トラックバック

このエントリーのトラックバックURL:
http://katsubemakito.net/mt/mt-tb.cgi/625






クリエイティブ・コモンズ・ライセンス
このブログは、次のライセンスで保護されています。 クリエイティブ・コモンズ・ライセンス.