2004年11月22日

Apacheのアクセスログ管理

Apacheのアクセスを記憶するログファイルは、リクエスト数に比例してどんどん大きくなる。ログファイルを一日おきにローテーションして、ログファイル名に日付を入れる処理を、logrotateというツールを使って実施する手順をまとめる。

■ apache のアクセスログ管理

Apacheのアクセスを記憶するログファイルは、リクエスト数に比例してどんどん大きくなる。そのファイルサイズがあまり大きくなると、扱いにくくなる。特にメモリの大きさを越えると、アクセス分析の処理にかかる時間が非常に長くなり、システムにかける負荷も増す。

アクセスが少ないサイトの場合は、毎月一度のログローテーションで十分である。FreeBSDならシステム付属のnewsyslog(8)を使えば簡単に実現できる。設定ファイル/etc/newsyslog.confにログファイルやPIDを加えるだけである。

しかし、一日数万pv以上のアクセスがあると、毎日一度のログローテーションが必要になってくる。ローテーションで生成されるログファイルの数も増えるため、ログファイル名に日付を入れたくなる。ログファイルを一日おきにローテーションして、ログファイル名に日付を入れる処理を、logrotateというツールを使って実施する手順をまとめる。

■ ログローテーションツール

ログローテーションを行うためのツールは、大きくシグナル型とパイプ型の二つに分類できる。シグナル型は、システムのデーモンから定期的に呼び出され、ログファイルを置き換え、ログを出力するアプリケーションにログファイルを再度開かせるためのシグナルを送る。パイプ型は、ログを出力するアプリケーションから呼び出され、ログデータを受け取り、アプリケーションに変わってログファイルに書き込む。

シグナル型には、newsyslogやlogrotateなどがある。newsyslogではファイル名に日付をつけることができないが、logrotateはローテーション処理の前後に実行されるスクリプトを指定できるので、そういった柔軟な処理が可能である。今回は、このlogrotateを用いた。

パイプ型には、rotatelogscronologなどがある。パイプ型は柔軟な処理ができるが、ログ出力ごとに実行されるため、その負荷が気になる。今回は、アクセスが非常に多い場合を対象としているため、パイプ型の利用は見送った。

■ logrotateを使ったログ管理

上記をまとめると、今回のログ管理方針は次のようになる。
・ログファイルは1日ごとにrotateする
・ログファイル名に日付を含める
・アクセス解析のため最近のログファイルは圧縮しない

まず、logrotateをインストールする。
# portinstall sysutils/logrotate

次に、logrotateが使う作業用ディレクトリを作る
# mkdir /var/lib

そして、設定ファイルを次のように作成する。
# vi /usr/local/etc/logrotate.conf

/var/log/httpd-access.log
/var/log/httpd-error.log
/var/log/httpd-toshikazu-access.log
/var/log/httpd-toshikazu-error.log
{
    daily
    create
    nocompress
    ifempty
    missingok
    sharedscripts
    postrotate
        # restart child processes immidiately
        #  /bin/kill -HUP `cat /var/run/httpd.pid`
        #  /usr/local/sbin/apachectl -k restart
        # wait to finish child processes gracefully
        #  /bin/kill -USR1 `cat /var/run/httpd.pid`
        /usr/local/sbin/apachectl -k graceful
        # rename to date style
        # 一日前の日付をYYYYmmddの形式で得る
        EXT=`date -v-1d +%Y%m%d`
        for f in $1; do
            mv $f.1 $f.$EXT
            OLDDIR=`echo $f | sed 's/\.log//'`
            FILENAME=`echo $f | sed 's/.*\///'`
            if [ ! -d $OLDDIR ]; then
                mkdir $OLDDIR
            fi
            mv $f.$EXT $OLDDIR/$FILENAME.$EXT
        done
        # compress old files
        # notice: do not compress hot log, use sleep if needed
        #sleep 60
        # keep log uncompressed for seven days, a week.
        # 八日前の日付をYYYYmmddの形式で得る
        EXT=`date -v-8d +%Y%m%d`
        for f in $1; do
            OLDDIR=`echo $f | sed 's/\.log//'`
            FILENAME=`echo $f | sed 's/.*\///'`
            if [ ! -d $OLDDIR ]; then
                mkdir $OLDDIR
            fi
            if [ -f $OLDDIR/$FILENAME.$EXT ]; then
                bzip2 $OLDDIR/$FILENAME.$EXT;
            fi
        done
    endscript
}

システムのログファイルはFreeBSD付属のnewsyslogで行い、apacheのログだけをlogrotateで扱うようにする。特別な理由がなければ、その方がずっとメンテナンスしやすいからだ。そのため、インストール後デフォルトで提供されるlogrotate.conf.sampleやlogrotate.dディレクトリ内の設定は利用しないようにする。sampleをベースにする場合、include行などはコメントアウトしておく。

logrotateは、/var/lib/logrotate.statusファイルに前回までの処理内容を記録する。例えば、1日1回と指定されたログファイルについて、このファイルに前日以前の日付が記述されていないと処理されない。試しに何度も実行したい場合は、このファイルを手動で編集すること。

logrotateを試しに動かすには、次のコマンドを実行する。
また、ログを新規追加した場合,logrotate.status更新のため一度実行しておくこと。
# /usr/local/sbin/logrotate /usr/local/etc/logrotate.conf
-d オプションで、実際の処理を行わない実行、
-v オプションで、実際の処理を行う詳細出力つきの実行。

最後に、crontab に登録して、毎日実行されるようにする。
# crontab -e
# 00:00 every day
0 0 * * * /usr/local/sbin/logrotate /usr/local/etc/logrotate.conf > /dev/null 2>&1

■ 参考

カモランドlogrotateの設定
logrotateを使ってファイル名に日付を入れる事例が紹介されている

logrotateのインストール
FreeBSDにlogrotateを導入した事例が紹介されている。

停止と再起動 - Apache HTTP サーバ
Apacheがログファイルを再度開くためのシグナルについて説明されている。