logrotateでログファイルがローテーションされない事への対処 | A Day In The Boy's Life

A Day In The Boy's Life

とあるエンジニアのとある1日のつぶやき。

logrotateは、Apacheのアクセスログや、syslogなど運用の中で肥大化していくログファイルを定期的に退避してくれるツールです。

logrotateの設定は、/etc/logrotate.confファイルにて全てのログファイルに対しての設定を、/etc/logrotate.d/ディレクトリ以下に個別のログファイルごとの設定を記載して管理します。


※ /etc/logrotated/ディレクトリ以下の個別の設定ファイルに記載した内容は、logrotate.confファイルに設定した内容より

  優先度が高くなります。


- /etc/logrotate.confの設定例

# see "man logrotate" for details
# rotate log files weekly
weekly
# keep 4 weeks worth of backlogs
rotate 10
# create new (empty) log files after rotating old ones
create
# uncomment this if you want your log files compressed
compress
# RPM packages drop log rotation information into this directory
include /etc/logrotate.d
# no packages own wtmp -- we'll rotate them here
/var/log/wtmp {
monthly
create 0664 root utmp
rotate 1
}
# system-specific logs may be also be configured here.

Apacheのログファイル(access_logやerror_logなど)のローテーションする場合の例


- /etc/logrotate.d/httpd

/var/log/httpd/*_log {
daily
missingok
notifempty
sharedscripts
postrotate
/bin/kill -HUP `cat /var/run/httpd.pid 2>/dev/null` 2> /dev/null || true
endscript
}

各設定項目の内容は、「logrotate @ Stray Penguin 」 がとても参考になるかと思います。


先ほど述べたように、個別の設定ファイル(上記の/etc/logrotate.d/httpd)の設定は、/etc/logrotate.confより優先されるので、ローテーションが行われる退避する周期が「weekly」から「daily」に上書きされます。

指定しなかった場合は、logrotate.confの設定が適用され、何も記述が無いものに関してはlogrotateのデフォルト値が採用されるようです。


このlogrotateですが、単純なログの退避になりますので専用のスクリプトを書いても大して手間ではないのですが、Linuxのディストリビューションに標準で入っていることもあり、広く利用されています。

ただ、設定や利用方法に関して少し難があります。


ここでは、ログのローテーションがうまく行かなかった場合の対処、確認方法を書いてみたいと思います。



logratateがうまくいかない時の確認事項


まず、logrotateの設定に問題がないかどうかを確認する方法ですが

$ /usr/sbin/logrotate -d /etc/logrotate.d/httpd

と、「-d」オプションをつけてローテーションする対象のファイルを指定し実行します。

「-d」オプションが、テストで実行してみる(実際にはローテーションされない)オプションになります。


もちろん、/etc/logrotate.confファイルを指定する事も可能です。

この場合、lorotate.confファイル内で、各個別の設定ファイルが読み込まれるのでlogrotate.dディレクトリ以下の全てがテストの対象となります。

通常であれば、全てをテストする必要は無いかと思いますので、logrotate.d以下の個別の設定ファイルを指定して実行してみればよいでしょう。


次に、設定ファイルには問題が無いのに、ローテーションされない場合についてです。

実際に実行しても何の反応もなく、ログのローテーションも行われない場合は、「-v」オプションをつけてローテーションの様子を確認してみればよいです。


$ /usr/sbin/logrotate -v /etc/logrotate.d/http
considering log /var/log/httpd/access_log
log does not need rotating

などの出力があった場合、ローテーションがされていません。



1. 前回ローテーションされた日を確認する


先ほどのApacheログファイルの設定ファイル例では、「daily」で実行するように指定しています。

logrotateは、この実行の周期を確認して実行します。

どこで前回実行された日を確認しているかと言うと、/var/lib/logrotate.statusに対象のログファイルと実行された日が記載されています。

実行してみるには、この日付をその周期より前に戻してあげる必要があります。

例えば、「daily」で実行するなら、logrotate.statusファイル内の該当ファイルの日付は昨日より前にセットする必要があります。(「weekly」なら1週間以上前)



2. 設定ファイル内の「rotate」の項目を確認する


$ /usr/sbin/logrotate -v /etc/logrotate.d/http

のように、個別の設定ファイルを指定して実行した場合、logrotate.confに書いた設定内容が反映されていないので注意が必要です。

ですので、先ほど書いた設定ファイルの例で、logrotate.conf内に「rotate」の記載はありますが個別の「http」のファイルには記載がありません。

ですので、「rotate」の設定は有効になっておらずデフォルト値の「0」が採用されます。

「rotate」とは、ローテーションして保管する世代数を表しますが「0」の場合、ローテーションされた瞬間に切り捨てられます。

つまり、対象のログファイルの内容が消されて、新しくファイルが作られるだけ(createを指定した場合)対応として、「rotate」の項目を追加し「0」以外の数値を指定して実行してみてください。



3. ログファイルのサイズと、設定ファイルの「size」項目の確認


「-v」オプションつきで実行してみた際に


rotating pattern: /var/log/httpd/access_log 1048576 bytes (no old logs will be kept)

のような出力があった場合、対象となるログファイルがローテーションの対象サイズより小さいためローテーションされていない可能性があります。

上記の例の場合、対照のログファイルのサイズが1MB以下であるためローテーションの対象ではないと判断されてしまっています。

これを変更するためには、設定ファイルに「size」の項目を追加して、対象にしたいファイルサイズを指定してあげれば動作します。

「0」を指定した場合、ファイルサイズに関係なくローテーションされます。

デフォルトでは、1MBのようです。


※ 全て、RedHatES4 + logrotate-3.7.1-5で確認しました。バージョンの違いによりデフォルト値や挙動が異なってくる

  可能性があります。また、実行してみる際はテスト環境などでまず行ってみてください。

  上記の設定の過程でログファイル自体が完全に消失する可能性もあります。



2007.06.05追記


先月頭にRedHatES4のRPMパッケージの更新が大量に出ていて、それを適用させてからlogrotateの挙動がおかしくなりました。(logrotate自体が更新パッケージに含まれていましたし)

具体的には、「postrotate」~「endscript」内が正しく実行されません。

私の環境では、「logrotateでローテーションされるファイル名を変更する 」に書いたローテーション後に日付を入れるスクリプトを書いていますが、この中で


for f in $1;


の箇所の「$1」に対象のログファイル名が入ってきません。

対象のログファイルは、設定ファイルの先頭の


/var/log/httpd/*_log {

から取り込まれるはずなのですが、これが取り込まれず変数が空になっているようです。

対処方法として、対象のログを全て記述し、for分もそのように記載します。


/var/log/httpd/*_log {


を、下記のように変更


/var/log/httpd/access_log /var/log/httpd/error_log {


また、


for f in $1;


を、下記のように変更


for f in /var/log/httpd/access_log /var/log/httpd/error_log;

これで何とか動くようになりました。

パッケージ自体のバグなのかな・・・?