WEB上からapacheの生ログをリアルタイム?で見ることが出来るようにするWEBアプリ

 apache等のwebサーバの生ログ(httpd-access.log)をwebブラウザを利用して見られるようにする必要があったので作ってみました。まず誰か既にやってるよなと言う事でググってみました。

こんなのがHITしました WEB上からapacheの生ログを見ることができるようにするプログラム

よく見てみるとphpで作られていて実装は単純にsystem関数でtailしているだけの本当にシンプルなものです。 perlで同じことやっても全く面白くないので他の方法を考える。 ログを見るだけなら先程の簡単な方法で問題ないのですが例のアレを使った方法を試してみることにする。

例のアレとはAnyEventである。非同期型のアプリでもってブラウザ上で流れるようにログを表示したい衝動に駆られました。 webで非同期と言えばやっぱりそう Tatsumaki ですよね。

Tatsumakiとは

 PSGIのストリーミングや非同期のアプリケーションを簡単に記述できるWebアプリケーションフレームワークです。 webの表示の部分はTatsumaki側で良きにはからってくれるので問題ないのですがログを取得する部分でブロックしないように取れるモジュールがないものかとCPAN探すとありました。 Event::File なんですが内部でEventとIO::Fileを利用していて設定したファイルが更新されたときCallback関数に変更部分が渡され呼ばれる仕組みになってるようです。

これを使うと至極簡単に作れそうです^^

tail.psgi

use warnings;
use Tatsumaki;
use Tatsumaki::Error;
use Tatsumaki::Application;

my $logfile = '/var/log/httpd-access.log';

package TailStreamHandler;

use parent qw(Tatsumaki::Handler);
__PACKAGE__->asynchronous(1);

use strict;
use warnings;
use Tatsumaki::MessageQueue;
use Tatsumaki::Error;
use Event::File;

my %streams;

sub create_stream {
    my $self = shift;
    my ($channel) = @_;

    my $mq = Tatsumaki::MessageQueue->instance($channel);

    $streams{$channel} =

      Event::File->tail(
        file => $logfile,
        timeout => 10,
        cb   => sub {
            $mq->publish( { type => 'log', log => $_[1] } );
        }
      );
}

sub get {
    my $self = shift;
    my $channel = $logfile;

    my $session = $self->request->param('session')
      or Tatsumaki::Error::HTTP->throw( 500, "'session' needed" );

    my $mq = Tatsumaki::MessageQueue->instance($channel);

    $streams{$channel} or $self->create_stream($channel);

    $mq->poll_once(
        $session,
        sub {
            my @events_published = @_;
            $self->write( \@events_published );

            $self->response->header(
                'Cache-Control' => 'no-store, no-cache, must-revalidate,'
                  . 'post-check=0, pre-check=0, max-age=0',
                'Pragma'  => 'no-cache',
                'Expires' => 'Thu, 01 Jan 1970 00:00:00 GMT'
            );

            $self->finish;
        }
    );
}

package TailHandler;
use base qw(Tatsumaki::Handler);

sub get {
    my ( $self, $channel ) = @_;
    $self->render( 'tail.html', { uid => $channel } );
}

package main;
use File::Basename;

my $app = Tatsumaki::Application->new(
    [
        '/tail/stream' => 'TailStreamHandler',
        '/tail'        => 'TailHandler',
    ]
);

$app->template_path( dirname(__FILE__) . "/templates" );
$app->static_path( dirname(__FILE__) . "/static" );

return $app->psgi_app;

__END__

tail.html

<html>
<head>
<title>LogFile tail</title>
</head>
<body>
<h1>LogFile tail</h1>
<div id="logs" style="font-size:small;"></div>
<script type="text/javascript" src="http://www.google.com/jsapi"></script>
<script type="text/javascript">google.load("jquery", "1.3.2");</script>
<script type="text/javascript" src="/static/jquery.ev.js"></script>
<script type="text/javascript">
jQuery( function ($) {

    $.ev.loop('/tail/stream' + '?session=' + Math.random(), {
        log : function(ev) {
            if(! ev.log) return;

            $( "#logs" ).append( 
                ev.log + "<br>" 
            );

        }
    });
} );
</script>
</body>
</html>

アプリ起動する

plackupを使って起動させますサーバにはもちろん非同期型のTwiggyを使います。

$ plackup -s Twiggy -a tail.psgi

ブラウザからアクセス

http://localhost:5000/tail

 ログが更新されるとブラウザの更新を押さなくても新しいログが追加されていきます。更新されてから表示されるまでタイムラグがありますがこれはEvent::Fileモジュール側の問題でtimeoutを短くするとよりリアルタイムに近くなります。 (タイムアウトを短く汁って事はブロックされてんじゃんwww) ブラウザはChromeとかfirefoxを使って下さい。IEだと表示はされますが挙動が変になります。 まぁこれも誰得?なアプリですが利用方法として特定のアドレスにアクセスがあるとアラート表示するとかかなぁ・・・ 最後に

非同期型のWebアプリを数十行のプログラムで書けるのもTatsumakiのおかげですね、 Tatsumaki凄いよTatsumaki。

created:

Back to top