ircでapacheのログをリアルタイムで監視

自宅サーバーでも日常的にapacheのログを監視したいけど、いちいちサーバーに入ってコマンドたたいて・・・っていうのが面倒だと思います。

そこで、ircサーバーを使って、apacheのログ監視をする方法があります。ircサーバーのチャンネルにapacheのアクセスログを出力することで、リアルタイムでアクセスがあればircのクライアントに表示されるという仕組みです。アクセスログをircサーバーに書き込むスクリプトをperlを使って書いてみました。

apacheのhttpd.confに以下のように追記するだけで、スクリプトを経由してリアルタイムでircに出力してくれます。

CustomLog "|/root/src/irc_write_httpd.pl" combined

スクリプトはこんな感じです。

ソケットを使うことを意識して書いてみました。

#!/usr/bin/perl

use strict;
use warnings;
use Socket;
use FileHandle;
use Jcode;
use threads;

my ($ip, $port, $sockaddr);
my ($irc_host, $channel, $nick, $user, $server_name, $real_name);

$ip = "IRCD_IP";
$port = 'IRCD_PORT';

$irc_host = "IRCD_HOST";
$channel = '#CHANNEL';
$nick = 'NICK_NAME';
$user = 'USER_NAME';
$server_name = 'LOG_CHECK_CHANNEL';
$real_name = ':REAL_NAME';

$sockaddr = &socket_create($ip, $port);
&socket_connect($sockaddr, $ip, $port);

&irc_login($irc_host, $channel, $user, $nick, $server_name, $real_name);
&irc_write;

close(SOCKET);

sub socket_create
{
    local(*sockaddr);
    local(*ip, *port) = $_;
    $ip = inet_aton($ip) || die "IP($ip) not found.\n";
    $sockaddr = pack_sockaddr_in($port, $ip);
    return $sockaddr;
}

sub socket_connect
{
    local(*sockaddr, *ip, *port) = $_;
    socket(SOCKET, PF_INET, SOCK_STREAM, 0) || die "socket error.\n";
    connect(SOCKET, $sockaddr) || die "connect $ip $port error.\n";
    autoflush SOCKET (1);
}

sub irc_login
{
    local(*irc_host, *channel, *user, *nick, *server_name, *real_name) = $_;
    print SOCKET "USER $user $irc_host $server_name $real_name\r\n";
    print SOCKET "NICK $nick\r\n";
    print SOCKET "JOIN $channel\r\n";
}

sub irc_write
{
    my $input;

    while(<SOCKET>)
    {
        print $_;

        if($_ =~ /End of NAMES list/)
        {
            while($input = <STDIN>)
            {
                if($input =~ /^$/)
                {
                    print SOCKET "PRIVMSG $channel :\t\r\n";
                    sleep 5;
                }
                else
                {
                    $input = &url_decode($input);
                    Jcode::convert(\$input,"jis");
                    print SOCKET "PRIVMSG $channel :$input\r\n";
                    sleep 5;
                }
            }
            print SOCKET "QUIT\r\n";
        }
    }
}

sub url_decode()
{
    my $input = $_;
    $input = shift;
    $input =~ tr/+/ /;
    $input =~ s/%([0-9A-Fa-f][0-9A-Fa-f])/pack('H2', $1)/eg;
    return $input;
}