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 のログ設定を下記のように設定して、エラーログとスローログを出力させているとします(クエリーログはすぐに膨大になるので通常時は出さないようにしています)
# /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 にあったので、これに手を加えて作成しました。
# vi /etc/logrotate.d/mysql-log-rotate
/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
}
設定値の説明については下記が詳しいです。
僕は次のようにしていますが、このあたりはお好みで。
* スローログの解析とかをやるときにいちいち解凍するのが面倒なので、圧縮しない(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 ユーザしか扱えないようにする権限設定も忘れずに。
# vi /root/.my.cnf
[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...] <configfile> -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 の挙動については下記が詳しいです)
# /usr/bin/mysqladmin flush-logs
でも OK だったし、
# logrotate /etc/logrotate.d/mysql-log-rotate
でも OK でした。
なぜ、cron からの実行だとダメなのか??原因を調べるために、logrotate のログを出力させます。
# vi /etc/cron.daily/logrotate
-/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
-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 さん、ありがとうございました!
logrotate -df /etc/logrotate.d/mysql-log-rotate
ひろやん(id:hiboma)ありがとうございました! ### 参考サイト * [http://d.hatena.ne.jp/erio_nk/20121013/1350089102:title=MySQLのlogrotate設定 - erio_nk://memo:bookmark] * [http://ijo.cc/it/ja/server/mysql-log-rotate/:title=MySQL5.1のlog出力とlogrotate設定 | ijo.cc:bookmark] * [http://kjirou.sakura.ne.jp/wiki_mirror/index.php?a%2F%A5%ED%A5%B0%A4%CE%A5%ED%A1%BC%A5%C6%A1%BC%A5%B7%A5%E7%A5%F3(logrotate):title=a/ログのローテーション(logrotate) - SORENARI-WIKI:bookmark]