◆ 簡単に使えて結構高機能
◆ デーモンはいなくて cron を使って毎回コマンドが実行されてるだけ
◆ 設定ファイルはコマンドの引数で渡されて毎回ロードされる
◆ 設定ファイルの書き方はグローバルと各ファイルにオプションを指定していくだけ

forever-service を使ってみたときにログのローテーション機能として logrotate の設定ファイルも作られました
logrotate は名前は知ってたのですがこれまで特に使ってませんでした
使ってるサービス自身がそういう機能を持っていたり 自分で出力するときに日付のファイルにするようにしてたりで 特に使わなくても困ってなかったです
こういうツールを新しく使うときは使い方とか設定が面倒なのですが せっかく設定ファイルが自動で作られたので使ってみることにしました

使ってみた

logrotate は fedora や centos ではデフォルトで入ってました
インストール不要で使えるなら使いやすいなら普段遣いにもよさそうです

とりあえず出力された設定ファイルをみてみたのですがすごくシンプルでした

/opt/log1/testlog {
daily
rotate 10
missingok
notifempty
copytruncate
}

使いかたの説明を読んでみましたが全体的に思ってた以上にシンプルなものでした

なにするもの

logrotate は名前通りログファイルをローテートするものです
1 ファイルにログを出力し続けるとすごく大きなファイルになってしまいます
開くのも時間かかりますし 探すのも大変です
毎日別のファイルにログしてくれるとそれぞれのファイルは小さいですし日付で探しやすいです
自分で出力するならその日の日付のファイルに出力すればいいですが そういう機能が無いツールもあるので logrotate が使えます

logrotate では毎日ファイルを切り替える daily 設定以外にも hourly, weekly, monthly, yearly が選べます
ただし hourly の場合は cron の設定も必要になります
それ以外の 10 日ごと みたいな日数指定はオプションリスト見た感じはなさそうです
日付以外にはファイルサイズでファイルを切り替えるオプションがありました

logrotate では単純にファイル切り替えだけじゃなくて 古いログを消してくれる機能もあります
ファイルで分けてるので古いファイルを消すだけです
最近の数ファイルならともかく何十も古いファイルを残しておいても見ませんしストレージの無駄遣いですからね
自分で作る場合は日毎のファイル出力はかんたんですが 消すのが面倒なんです
フォルダ内の対象ファイル一覧を取り出して それぞれのファイル名から日付を取り出して 消す条件にあってるかの確認したりで 使いまわせはしますがファイル名のルール変わるとその辺調整したりで面倒だなーと感じるところです
そこをやってくれるというのが嬉しいところです
消すルールは何日残すとか ファイルをいくつ残すという感じで設定できます
今ではあんまり使わなそうですが 昔の名残なのかメールで送信って機能もありました

cron

logrotate 自体はコマンドが実行されたら引数に渡された設定ファイルを読み込んでローテート処理を行うというものです
定期実行は cron 任せです

設定は「/etc/cron.daily/logrotate」にあります

#!/bin/sh

/usr/sbin/logrotate /etc/logrotate.conf
EXITVALUE=$?
if [ $EXITVALUE != 0 ]; then
/usr/bin/logger -t logrotate "ALERT exited abnormally with [$EXITVALUE]"
fi
exit $EXITVALUE

cron.daily にこの設定があり cron.hourly にはありません
なので logrotate で hourly 設定にしても 1 日 1 回しかローテートされません
hourly を使う場合はこの cron の設定ファイルを cron.daily から cron.hourly フォルダに移動する必要があります
cron.hourly に配置すれば 1 時間ごとに実行されるので 1 日ごとに更に実行する必要はないので移動で大丈夫です
コピーは不要です

mv /etc/cron.daily/logrotate /etc/cron.hourly/

設定

「/etc/logrotate.conf」の中身はこんなのでした

# see "man logrotate" for details
# rotate log files weekly
weekly

# keep 4 weeks worth of backlogs
rotate 4

# create new (empty) log files after rotating old ones
create

# use date as a suffix of the rotated file
dateext

# 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 and btmp -- we'll rotate them here
/var/log/wtmp {
missingok
monthly
create 0664 root utmp
minsize 1M
rotate 1
}

/var/log/btmp {
missingok
monthly
create 0600 root utmp
rotate 1
}

# system-specific logs may be also be configured here.

weekly や rotate 4 などブロックに入ってないところがグローバルの設定で ファイル名の後のブロックがログファイル固有の設定です
「/etc/logrotate.d」フォルダを include してるのでこのフォルダ内の設定ファイルもすべてロードされます
forever-service で作ったファイルもここに配置されてました

設定ファイルの書き方は ファイル名を書いてその後の {} ブロックの中にオプションを行ごとに書いていきます
ファイル名は半角スペースで区切れば複数ファイルをまとめて設定できます
ファイル名に半角スペースがある場合は "" で囲みます

オプションの説明は man コマンドで見れます
このページでも見れますが古いのか hourly は載ってませんでした

たいていはローテート間隔 (daily や weekly) と削除ルール (rotate) を書いておくくらいで十分だと思います

copytruncate

使うまでファイルをローテートすることで心配だった部分に途中でファイルを消したり移動したりして大丈夫なのかというのがあります
プログラムで書きこみ処理のたびにファイルオープンとクローズをしてるなら途中でファイルを消して作り直したりファイルを移動しても特に心配ありません
指定のファイル名のファイルがなければ作られるだけです
ですが 中にはずっとファイルを開きっぱなしのプログラムだってあります

Windows だとプログラムが開いてる途中のファイルは消したり移動したりしようとするとエラーが出ます
リソースモニターでそのファイルを開いてるプログラム見つけて終了させないといけなくてよく困るあれです

ですが Linux の場合は移動や削除もできます
そしてその場合は移動先に書き込みが続きますし 削除した場合はプログラム的にはエラーは出ずに書き込めているのにどこのファイルにも書き込まれてません
/dev/null に書き込まれてるのかな?
そういうのがあるので 書き込み先を変えるのが難しいです
一旦消して新しく作ってもそこに書き込んでくれませんし ファイル名を変えても変えた先に書かれます

logrotate ではそういうのに対応できるのかなと思っていたのですが copytruncate オプションをつけるとうまく行ってました
このオプションだとローテートするときに 現在のファイルをコピーして その後で現在のファイルを truncate してファイルサイズを 0 にするそうです
そんなことできるの?と思ったのですが truncate という Linux コマンドがありました
Linux はけっこう長く使ってるのに初めて見ました
これを使えばできるのかなと Node.js で stream で書き込み続けて その途中で truncate コマンドを使ってみると無事ファイルを空にできてその後にも書き込みができました
こんな機能あったんだ……

ただこの仕組みを知ると少し心配なのは書き込み処理中に copytruncate を行うとコピーが完了してから truncate するまでに書き込まれるデータがあるかもという部分です
そのデータがあると そこはコピーされず消されるわけです
そういうことがないように logrotate がファイルをロックしたりしてればいいのですけど

state ファイル

logrotate はコマンド実行されたらローテートするものですが 何度も連続して実行されたときに 毎回ローテートしてしまわないように state ファイル保存してます
デフォルトのは「/var/lib/logrotate/logrotate.state」にあります
中身はこんなのです

logrotate state -- version 2
"/var/log/sssd/sssd_implicit_files.log" 2019-7-27-3:28:1
"/var/log/dnf.librepo.log" 2019-7-27-3:28:1
"/var/log/dnf.plugin.log" 2019-4-1-3:0:0
"/var/log/dnf.rpm.log" 2019-7-27-3:28:1
"/var/log/sssd/sssd_nss.log" 2019-7-27-3:28:1
"/var/log/hawkey.log" 2019-7-27-3:28:1
"/var/log/dnf.log" 2019-7-27-3:28:1
"/var/log/httpd/error_log" 2018-10-21-10:43:1
"/var/log/chrony/*.log" 2019-4-1-3:0:0
"/var/log/wtmp" 2018-3-11-21:0:0
"/var/log/sssd/sssd.log" 2018-3-11-21:0:0
"/var/log/spooler" 2019-7-27-3:28:1
"/var/log/btmp" 2019-7-27-3:28:1
"/var/log/iscsiuio.log" 2019-4-1-3:0:0
"/var/log/maillog" 2019-7-27-3:28:1
"/var/log/php-fpm/error.log" 2018-10-21-10:43:1
"/var/log/wpa_supplicant.log" 2019-4-1-3:0:0
"/var/log/secure" 2019-7-27-3:28:1
"/var/log/messages" 2019-7-27-3:28:1
"/var/log/httpd/access_log" 2018-5-20-3:28:1
"/var/account/pacct" 2018-3-11-21:0:0
"/var/log/cron" 2019-7-27-3:28:1

ファイルごとのローテート時刻が保存されています

思ってた以上に良いツールだった

最初はそれほど期待してなかったのですが使ってみると思った以上に良いツールでした
変に複雑じゃなくてシンプルな仕組みというのが個人的に好みでした

デーモンとかなしで cron でコマンド実行されて
設定ファイルはコマンドの引数なので場所は引数変えるだけで良いし
毎回ロードされるので再起動みたいなのも不要
設定もグローバルと各ファイルごとにオプションを書くだけのシンプル構文

Apache なんか設定ファイル意味不明過ぎますし デフォルト設定で使うならともかく設定カスタマイズなんてやりたくないですからね

それに疑問だったファイルを開いたままのツールのログをクリアする方法もわかりましたし 積極的に使っていこうという気持ちになりました