彼女からは、おいちゃんと呼ばれています

ウェブ技術や日々考えたことなどを綴っていきます

MySQL ログのローテーション設定(logrotate)(flush-logs が cron で動かないときの対処を含む)

MySQL のログをローテートさせる設定をしていて、下記の現象(詳細は本文参照)にハマりました。やっと解決できたのでメモしておきます。

手動でコマンドを叩いたときはうまくいくのに cron で動かしたときは flush-logs がうまくいかない <<

環境は CentOS 6.3、MySQL 5.5.28 です。

||

yum list centos-release

... Installed Packages centos-release.x86_64 6-3.el6.centos.9 @base

mysql -V

mysql Ver 14.14 Distrib 5.5.28, for Linux (x86_64) using readline 5.1 ||<

**MySQL ログのローテーション設定(logrotate)(flush-logs が cron で動かないときの対処を含む) -1. 前提 - MySQL ログ出力設定 -2. ローテートファイルの作成 -3. mysqladmin のための認証ファイルを作成 -4. デバッグモードで実行 -5. あれ?うまくいかないので logrotate のログを出力させる -6. /etc/cron.d/0hourly を編集 -おまけ - ローテーションを実際に実行して確認したいとき <<

*1. 前提 - MySQL ログ出力設定

MySQL のログ設定を下記のように設定して、エラーログとスローログを出力させているとします(クエリーログはすぐに膨大になるので通常時は出さないようにしています)

|conf|

/etc/my.cnf

[mysqld] slow_query_log slow_query_log_file=/var/log/mysql/slow.log long_query_time = 0.5 log_queries_not_using_indexes

[mysqld_safe] log-error = /var/log/mysql/error.log pid-file = /var/run/mysqld/mysqld.pid ||<

ログ出力用のディレクトリを作成。

||

mkdir /var/log/mysql

chown -R mysql /var/log/mysql

chmod -R 644 /var/log/mysql

||<

MySQL を再起動して設定を反映させる。

||

service mysqld restart

||<

*2. ローテートファイルの作成

ローテートさせる設定を書いたファイルを作成して、/etc/logrotate.d に置きます。ひな形が /etc/logrotate.d/mysqld にあったので、これに手を加えて作成しました。

-/etc/logrotate.d/mysqld

||

vi /etc/logrotate.d/mysql-log-rotate

||<

|conf| /var/log/mysql/error.log /var/log/mysql/slow.log { create 644 mysql mysql notifempty daily rotate 14 missingok nocompress dateext sharedscripts postrotate # just if mysqld is really running if test -x /usr/bin/mysqladmin && \ /usr/bin/mysqladmin ping &>/dev/null then /usr/bin/mysqladmin flush-logs fi endscript } ||<

設定値の説明については下記が詳しいです。

-Stray Penguin - Linux Memo (logrotate)

僕は次のようにしていますが、このあたりはお好みで。

-スローログの解析とかをやるときにいちいち解凍するのが面倒なので、圧縮しない(nocompress) -ログの参照、解析がやりやすいように、他のユーザーにも参照権限を与える(create 644 mysql mysql) -サフィックスは xxx.log.1 形式よりも xxx.log-20130320 みたいに日付が付く方がよい(dateext) -flush-logs の実行は、ログファイルごとに行うのではなく、1回のみ行う(sharedscripts) <<

*3. mysqladmin のための認証ファイルを作成

ローテートした後に「/usr/bin/mysqladmin flush-logs」するので、user と password を書いたファイルを作成します。

これについても /etc/logrotate.d/mysqld の中に説明が載っていました。説明にも書いているように、root ユーザしか扱えないようにする権限設定も忘れずに。

-/etc/logrotate.d/mysqld

||

vi /root/.my.cnf

||<

|conf| [mysqladmin] password = xxxxxxxx user= root ||<

||

chmod 600 /root/.my.cnf

||<

*4. デバッグモードで実行

/etc/logrotate.d/ 配下に置いているファイルは、cron が実行してくれるのですが、設定に誤りがないか確認するため、一度、手動でデバッグモードで実行しておくと良いです。

||

logrotate -dv /etc/logrotate.d/mysql-log-rotate

...(エラーがないか確認する) ||<

メモ: logrotate の使い方

||

logrotate --help

使い方: logrotate [OPTION...] -d, --debug Don't do anything, just test (implies -v) -f, --force Force file rotation -m, --mail=command Command to send mail (instead of `/bin/mail') -s, --state=statefile Path of state file -v, --verbose Display messages during rotation

Help options: -?, --help Show this help message --usage Display brief usage message ||<

*5. あれ?うまくいかないので logrotate のログを出力させる

と、ここまでで設定は完了で、あとは cron が毎日 logrotate してくれるよ、と他のいろんな記事には書かれていたので、うまくいく人は下記はすっ飛ばして良いと思います。

ですが、自分の環境だと、どうもうまくいかない。。。具体的にどういうことかというと、下記のように、ログが slow.log や error.log に書き込まれずに、サフィックスに日付が付いたログファイルのほうへ書き込まれてしまうのでした。

||

ls -l /var/log/mysql

-rw-r--r-- 1 mysql 0 3月 14 03:16 2013 error.log -rw-r--r-- 1 mysql 102 3月 14 00:12 2013 error.log-20130314 -rw-r--r-- 1 mysql 0 3月 14 03:16 2013 slow.log -rw-r--r-- 1 mysql 8029 3月 14 21:41 2013 slow.log-20130314 ||<

これは flush-logs がされていない様子。。。手動でコマンドを叩くと、slow.log や error.log に書き込まれるようになりました(flush-logs の挙動については下記が詳しいです)

-MySQL :: MySQL 5.1 リファレンスマニュアル :: 4.11.6 ログ ファイルの保守

||

/usr/bin/mysqladmin flush-logs

||<

でも OK だったし、

||

logrotate /etc/logrotate.d/mysql-log-rotate

||<

でも OK でした。

なぜ、cron からの実行だとダメなのか??原因を調べるために、logrotate のログを出力させます。

||

vi /etc/cron.daily/logrotate

||<

|diff| -/usr/sbin/logrotate /etc/logrotate.conf >/dev/null 2>&1 +/usr/sbin/logrotate -v /etc/logrotate.conf >/var/log/logrotate 2>&1 ||<

で、一日待って、出力されていたログが下記。

||

cat /var/log/logrotate

... running postrotate script /usr/bin/mysqladmin: connect to server at 'localhost' failed error: 'Access denied for user 'root'@'localhost' (using password: NO)' error: error running non-shared postrotate script for /var/log/mysql/error.log of '/var/log/mysql/error.log ' ||<

mysqladmin の認証ができていない様子。。。

*6. /etc/cron.d/0hourly を編集

mysqladmin の認証ができていない = 先に作成した /root/.my.cnf を読み込めていないのではないかと予想し、cron の設定を見てみたところ、それらしい箇所を見つけたので編集しました(環境によっては、/etc/cron.d/0hourly ではなく「/etc/cron.d/dailyjobs」のようです)

||

vi /etc/cron.d/0hourly

||<

|diff| -HOME=/ +HOME=/root ||<

これでうまくいくようになりました。

***(2013年3月22日 追記) コメント&はてぶコメントで教えていただきましたが、/etc/cron.d/0hourly を編集せずに、/etc/logrotate.d/mysql-log-rotate の方を編集して、下記のようにしても良さそうです。

|| /usr/bin/mysqladmin --defaults-extra-file=/root/.my.cnf flush-logs ||<

しても良さそうというか、/etc/cron.d/0hourly を編集することで他の箇所に影響を与えてしまうリスクもあるので、--default-extra-file を指定する方が良いですね。

id:sh2 さん、id:manabusakai さん、ありがとうございました! <<

*おまけ - ローテーションを実際に実行して確認したいとき

ローテーションを実際に実行して確認したい場合は、/var/lib/logrotate.status の日付を編集してから実行すればよいようです。

-logrotate(ログローテート)の動作確認 - OpenGroove

**(2013年3月22日 追記) こちらもはてぶコメントで教えていただきましたが、下記のように -f オプションをつければ、処理を強制できるので、次の日まで待たなくても動作確認ができます。

||

logrotate -df /etc/logrotate.d/mysql-log-rotate

||<

ひろやん(id:hiboma)ありがとうございました! <<

*参考サイト

-MySQLのlogrotate設定 - erio_nk://memo -MySQL5.1のlog出力とlogrotate設定 | ijo.cc -a/ログのローテーション(logrotate) - SORENARI-WIKI