Apache の古いログを月別に保存したい。 ファイル名には access_log.200503 のように年月をつける。logrotate の設定を行う。
■ ■ ■
Vine Linux 3.1 のデフォルトの設定では,Apache のアクセスログは /var/log/httpd/access_log に保存される。1週間に1度ログのローテートが行われて,1週間前は access_log.1,2週間前は access_log.2 のように移動され,access_log.4 まで保存されて,それより古いものは削除される仕組みになっている。設定を変更して,先月の1か月分のログは access_log.200503 という名前にして保存するようにしたい。
Apache にはログをローテートするための独自の機能 rotatelogs があるが,ログをとる期間を秒単位で指定するしか方法がないため,1日,1週間間隔は可能だが,1か月間隔にはできない。参考: ログのrotateについて - abab-PukiWiki
Vine Linux 3.1, 2.6 では,logrotate を使ってログのローテーションが行われる。次のような順番で処理が行われる。
- システムは /etc/crontab のスケジュールにしたがって cron を実行する
01 * * * * root run-parts /etc/cron.hourly
02 4 * * * root run-parts /etc/cron.daily
22 4 * * 0 root run-parts /etc/cron.weekly
42 4 1 * * root run-parts /etc/cron.monthly
- 毎朝4時2分に /etc/cron.daily 内のスクリプトが名前順に実行される (logrotate が含まれている)
- /etc/cron.daily/logrotate により,/usr/sbin/logrotate コマンドは /etc/logrotate.conf の設定で動作する
- /etc/logrotate.conf はデフォルトの動作を指定し(週に1度実行し,4世代まで残す),個別の動作については /etc/logrotate.d ディレクトリの中のファイルに任せる
- ログをローテートするかどうかは,/var/lib/logrotate.status の最終処理日が基準となる
- Apache のログは /etc/logrotate.d/apache によってローテートされ,後処理として httpd の再起動が行われる
Apache のログの保存方法を変更するには,/etc/logrotate.d/apache を変更すればよい。デフォルトでは,次のような内容になっている。
/var/log/httpd/access_log {
missingok
postrotate
/bin/kill -HUP `cat /var/run/httpd.pid 2>/dev/null` 2> /dev/null || true
endscript
}
/var/log/httpd/agent_log {
missingok
postrotate
/bin/kill -HUP `cat /var/run/httpd.pid 2>/dev/null` 2> /dev/null || true
endscript
}
...
同じ内容で,error_log, referrer_log, request_log についても記述されている。{ } の内側の記述は全て同じなので,次のように書いても等価である。
/var/log/httpd/access_log /var/log/httpd/agent_log {
missingok
postrotate
/bin/kill -HUP `cat /var/run/httpd.pid 2>/dev/null` 2> /dev/null || true
endscript
}
{ } の前の文字列(/var/log/httpd/access_log など)にマッチするファイルに対し,{ } の中の処理が行われる。もし,/var/log/httpd ディレクトリにある全ての _log で終わるファイルに対して同じ処理を行いたいのであれば,次のように書くこともできる。
/var/log/httpd/*_log {
missingok
postrotate
/bin/kill -HUP `cat /var/run/httpd.pid 2>/dev/null` 2> /dev/null || true
endscript
}
つまり,「/var/log/httpd/*_log」は「/var/log/httpd/access_log /var/log/httpd/agency_log ...」に展開されるからである。
このファイルを編集する場合,直接編集して失敗するとログが消えてしまう可能性があるので,私は次のような手順を踏んでいる。
- /etc/logrotate.d/apache を /tmp/apache にコピー
- /tmp/apache を修正
- /usr/sbin/logrotate -d /tmp/apache でテスト (実際の動作は行わない)
- /tmp/apache を /etc/logrotate.d/apache に上書き
/etc/logrotate.d/apache の内容は次のようになる(テストでは /tmp/apache)。Apache/ログ管理 - JomoraWorks を参考にさせて頂いた。
/var/log/httpd/*_log {
monthly
missingok
postrotate
/bin/kill -HUP `cat /var/run/httpd.pid 2> /dev/null` 2> /dev/null
EXT=`date -d '1 day ago' +%Y%m`
for F in $1;
do mv $F.1 $F.$EXT
done
endscript
}
記述の概要は以下の通り。
- /var/log/httpd/*_log により,ファイル名の最後が _log で終わっているログファイルを $1 にセットして処理の対象にする
- monthly で月に1度だけ処理を行う
- missingok は対象のファイルがなくても処理を続ける (ここでは *_log にマッチしたファイルだけを対象にしているので,この行はあってもなくても動作は同じになる)
- postrotate ... endscript で,ローテート直後にファイル名の変更を行う
最後の postrotate ... endscript には Bourne Shell のスクリプトを書くことができる。/bin/kill コマンドで httpd デーモンに対し HUP (Hung Up) シグナルを送り,httpd の再起動を行っている。logrotate コマンドは,access_log を access_log.1 として名前の変更を行う。httpd はログを出力するファイル access_log を失っていまうため,そのままだとそれ以降ログが残すことができない(itb-TECH 【 logrotate 】)。そこで再起動をかけているのである。変数 $EXT には,date コマンドで昨日の年月をセットしている。月の最初にローテートされる場合,ローテートされたファイルの中身は先月のものだからである。httpd の再起動で access_log を新たに作らせている。シェル変数 $1 には,マッチした全てのファイル名がスペース区切りで「/var/log/httpd/access_log /var/log/httpd/agency_log」のような形でセットされる。for 文により,このファイル名を1つずつ変数 $f に取り出し,名前の変更を行っている。logrotate のディレクティブに関しては Stray Penguin - Linux Memo (logrotate) が分かりやすい。
Apache/ログ管理 - JomoraWorks の例のように,ログファイルを移動するのではなく別ファイルにコピーし,コピーしたもとのファイルの長さを 0 にしてしまうという方法もある。これなら,httpd が出力するファイル access_log は単にファイルの大きさが変わっただけなので httpd の再起動は不要になる。上では,コピーするより高速に処理が行われる移動の手順を選択した。
設定が書けたらテストを行う。-d オプションをつけて logrotate コマンドを起動する。どのような処理になるかが分かり,文法チェックにもなる。
# /usr/sbin/logrotate -d /tmp/apache
reading config file /tmp/apache
reading config info for /var/log/httpd/access_log {
Handling 1 logs
rotating pattern: /var/log/httpd/access_log { monthly (no old logs will be kept)
empty log files are rotated old logs are removed
errors displayed on stderr
rotating file /var/log/httpd/access_log
log does not need rotating
-d は実際の動作は行わせないためのオプションであるが,この状態では,-d をつけなくてもログのローテーションは行われない。前回の処理から1か月以上経過していないからである。毎月1日に動作させるためには,/var/lib/logrotate.status を編集し,1か月以上前の1日に日付を変更しておく必要がある。今日は2005年4月13日なので,動作させるために3月1日にセットする。
"/var/log/httpd/access_log" 2005-3-1
そして,再度テスト実行してみる。
# /usr/sbin/logrotate -d /tmp/apache
reading config file /tmp/apache
reading config info for /var/log/httpd/access_log {
Handling 1 logs
rotating pattern: /var/log/httpd/access_log { monthly (no old logs will be kept)
empty log files are rotated old logs are removed
errors displayed on stderr
rotating file /var/log/httpd/access_log
log needs rotating
renaming /var/log/httpd/access_log.1 to /var/log/httpd/access_log.2
copying /var/log/httpd/access_log to /var/log/httpd/access_log.1
truncating /var/log/httpd/access_log
running postrotate script
running script with arg /var/log/httpd/access_log: "
/bin/kill -HUP `cat /var/run/httpd.pid 2> /dev/null` 2> /dev/null
EXT=`date -d '1 day ago' +%Y%m`
for F in $1;
do mv $F.1 $F.$EXT
done
"
removing rotated log (rotateCount == 0)Failed to remove old log /var/log/httpd/access_log.1: Permission denied
access_log.1 が access_log.2 にリネームされ,access_log が access_log.1 にリネームされ,access_log のファイルの長さが 0 にセットされる。access_log というファイルはもはや存在しないが,無視して処理は続けられる。その後 access_log.1 を access_log.200503 にするスクリプトが実行され,access_log.1 を削除しようとして許可がなくて失敗している(一般ユーザ権限で実行したため)。
正しく動作しているようだ。
/tmp/apache を /etc/logrotate.d/apache に上書きして出来上がり。
忘れてはならないのは,このままの設定だと,今日か明日にローテートが走ってしまう。来月1日に動作させるために,/var/lib/logrotate.status を編集し,今月の1日に日付を変更しておくこと。
"/var/log/httpd/access_log" 2005-4-1
2007年11月12日追記:
logrotate の動作が変わってしまったので,手動スクリプトで対応することにしました (nlog(n): logrotate の動作がおかしい)。
Posted by n at 2005-04-13 22:18 | Edit | Comments (0) | Trackback(0)