印刷用表示へ切り替え 通常表示へ切り替え 更新履歴を表示 更新履歴を隠す
Linux Apache のログを月別に保存したい

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 を使ってログのローテーションが行われる。次のような順番で処理が行われる。

  1. システムは /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
  2. 毎朝4時2分に /etc/cron.daily 内のスクリプトが名前順に実行される (logrotate が含まれている)
  3. /etc/cron.daily/logrotate により,/usr/sbin/logrotate コマンドは /etc/logrotate.conf の設定で動作する
  4. /etc/logrotate.conf はデフォルトの動作を指定し(週に1度実行し,4世代まで残す),個別の動作については /etc/logrotate.d ディレクトリの中のファイルに任せる
  5. ログをローテートするかどうかは,/var/lib/logrotate.status の最終処理日が基準となる
  6. 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 ...」に展開されるからである。

このファイルを編集する場合,直接編集して失敗するとログが消えてしまう可能性があるので,私は次のような手順を踏んでいる。

  1. /etc/logrotate.d/apache を /tmp/apache にコピー
  2. /tmp/apache を修正
  3. /usr/sbin/logrotate -d /tmp/apache でテスト (実際の動作は行わない)
  4. /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)
Trackbacks

  • 「手違いで複数トラックバックを送ってしまった!」という場合でも気にしないでください (重複分はこちらで勝手に削除させていただきます)
  • タイムアウトエラーは,こちらのサーバの処理能力不足が原因です (詳細は トラックバック送信時のエラー をご覧ください)
  • トラックバックする記事には,この記事へのリンクを含めてください(詳細は 迷惑トラックバック対策 をご覧ください)
Comments
Post a comment
  • 電子メールアドレスは必須ですが,表示されません (気になる場合は「メールアドレスのような」文字列でもOKです)
  • URL を入力した場合はリンクが張られます
  • コメント欄内ではタグは使えません
  • コメント欄内に URL を記入した場合は自動的にリンクに変換されます
  • コメント欄内の改行はそのまま改行となります
  • 「Confirmation Code」に表示されている数字を入力してください (迷惑コメント対策です)


(必須, 表示されます)


(必須, 表示されません)


(任意, リンクされます)


Confirmation Code (必須)


Remember info (R)?