ログファイルをローテンションして溜まらないようにする話。
こんにちは。
サーバーの運用に関わっていれば、必ず出くわすログのローテーション。
いつ見られるとも知れないログをどうやってしまっておくかという非常〜にマイナーな運用ネタですが、こういう地道な作業をないがしろにしていると痛い目を見るというのは、運用エンジニアなら身を持って知っているものです。
最近のファイルシステムでは大きなログファイルを作っても何の問題も起きないからと放っておいた末に 1GB・2GBと際限なく大きくなってしまったログファイル、いざ障害が起きて読み込もうとするとテキストエディタがクラッシュしてしまったり…。
そういう笑えない状況に陥らないために、ログファイルは日頃からローテーションして適切なサイズ、分かりやすい時系列の名称のファイルにして整理しておきましょう。
これは OSその他ソフトが何かに関わらずやるべきことですが、ここでは Ubuntu Server を例にどんな感じのローテーションの仕組みがあるか見ていきます。
具体的な環境は Ubuntu Server 22.04.1 を使います。
Ubuntuで /var/log/syslog などをみてみると、ファイルがこんな風になっていますね。
subro@UbuntuServer2204:~$ ls -l /var/log/syslog*
-rw-r----- 1 syslog adm 42631 12月 12 21:36 /var/log/syslog
-rw-r----- 1 syslog adm 2303921 12月 12 21:31 /var/log/syslog.1
-rw-r----- 1 syslog adm 169845 11月 30 11:09 /var/log/syslog.2.gz
-rw-r----- 1 syslog adm 395574 11月 21 18:48 /var/log/syslog.3.gz
-rw-r----- 1 syslog adm 143513 11月 13 12:43 /var/log/syslog.4.gz
今生きているのが syslog、1つ前が syslog.1、もう一つ前が syslog.2.gz、以下同文です。
時系列で名前をつけて、圧縮して、一番古いのは順次削除…と誰がどこでやっているのか。
これらは、cronのスケジューラによって動かされている logrotateコマンド(rotates, compresses, and mails system logs)によって処理されています。
順に追っていきます。
まず cronのスケジューラ設定のファイル(/etc/crontab)から。
subro@UbuntuServer2204:~$ cat /etc/crontab # /etc/crontab: system-wide crontab # Unlike any other crontab you don't have to run the `crontab' # command to install the new version when you edit this file # and files in /etc/cron.d. These files also have username fields, # that none of the other crontabs do. SHELL=/bin/sh # You can also override PATH, but by default, newer versions inherit it from the environment #PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin # Example of job definition: # .---------------- minute (0 - 59) # | .------------- hour (0 - 23) # | | .---------- day of month (1 - 31) # | | | .------- month (1 - 12) OR jan,feb,mar,apr ... # | | | | .---- day of week (0 - 6) (Sunday=0 or 7) OR sun,mon,tue,wed,thu,fri,sat # | | | | | # * * * * * user-name command to be executed 17 * * * * root cd / && run-parts --report /etc/cron.hourly 25 6 * * * root test -x /usr/sbin/anacron || ( cd / && run-parts --report /etc/cron.daily ) 47 6 * * 7 root test -x /usr/sbin/anacron || ( cd / && run-parts --report /etc/cron.weekly ) 52 6 1 * * root test -x /usr/sbin/anacron || ( cd / && run-parts --report /etc/cron.monthly ) #
時刻を設定した覚えはありませんが、OSインストールした時刻なのかな?
ピンクの行で run-partsコマンド(ディレクトリにあるスクリプト・プログラムの実行)により、/etc/cron.daily ディレクトリにあるスクリプトが実行されます。
毎日1回 6:25に実行されるようになっています。
/etc/cron.daily ディレクトリの中身はこちら。
全部シェルスクリプトのようです。
subro@UbuntuServer2204:~$ ls -l /etc/cron.daily 合計 24 -rwxr-xr-x 1 root root 376 10月 27 2021 apport -rwxr-xr-x 1 root root 1478 4月 8 2022 apt-compat -rwxr-xr-x 1 root root 314 2月 14 2021 aptitude -rwxr-xr-x 1 root root 123 12月 6 2021 dpkg -rwxr-xr-x 1 root root 377 5月 25 2022 logrotate -rwxr-xr-x 1 root root 1330 3月 18 2022 man-db
logrotateとありますので、これですね。
スクリプトですので、中を見てみます。
subro@UbuntuServer2204:~$ cat /etc/cron.daily/logrotate #!/bin/sh # skip in favour of systemd timer if [ -d /run/systemd/system ]; then exit 0 fi # this cronjob persists removals (but not purges) if [ ! -x /usr/sbin/logrotate ]; then exit 0 fi /usr/sbin/logrotate /etc/logrotate.conf EXITVALUE=$? if [ $EXITVALUE != 0 ]; then /usr/bin/logger -t logrotate "ALERT exited abnormally with [$EXITVALUE]" fi exit $EXITVALUE
ピンクの行で logrotateコマンドを実行していました。
ここまでの設定で logrotateコマンドが毎日1回実行されていることが分かりました。
次は logrotateコマンドの設定ファイル(/etc/logrotate.conf)を見ていきましょう。
subro@UbuntuServer2204:~$ cat /etc/logrotate.conf # see "man logrotate" for details # global options do not affect preceding include directives # rotate log files weekly weekly # use the adm group by default, since this is the owning group # of /var/log/syslog. su root adm # 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 # packages drop log rotation information into this directory include /etc/logrotate.d # system-specific logs may also be configured here.
これはデフォルト値で、以下の内容になっています。
- 1週間間隔でローテーションをする
- (生きているものを除いて)4世代残す(4世代より古いものは消す)
- ローテート時に新しい空のログファイルを作る
- /etc/logrotate.d ディレクトリの下の設定も読む
他にコメントアウトされてますが、黄色い字の設定でローテート後のログファイルの名前にデフォルトの数字ではなく YYYYMMDDのような日付を入れることもできます。
更に読み込む /etc/logrotate.d ディレクトリの下はというと
subro@UbuntuServer2204:~$ ls -l /etc/logrotate.d 合計 52 -rw-r--r-- 1 root root 120 9月 12 2021 alternatives -rw-r--r-- 1 root root 126 10月 27 2021 apport -rw-r--r-- 1 root root 173 4月 8 2022 apt -rw-r--r-- 1 root root 79 2月 14 2021 aptitude -rw-r--r-- 1 root root 91 3月 18 2022 bootlog -rw-r--r-- 1 root root 130 10月 14 2019 btmp -rw-r--r-- 1 root root 112 9月 12 2021 dpkg -rw-r--r-- 1 root root 374 12月 24 2021 rsyslog -rw-r--r-- 1 root root 336 4月 13 2022 squid -rw-r--r-- 1 root root 270 4月 1 2022 ubuntu-advantage-tools -rw-r--r-- 1 root root 209 9月 19 2021 ufw -rw-r--r-- 1 root root 235 2月 19 2021 unattended-upgrades -rw-r--r-- 1 root root 145 10月 14 2019 wtmp
/var/log/syslog を出力している rsyslogd に関係していそうなファイルがあります。
他にもこれだけのログを相手にしているようですね。
rsyslogファイルに何が書いてあるか見てみましょう。
subro@UbuntuServer2204:~$ cat /etc/logrotate.d/rsyslog /var/log/syslog /var/log/mail.info /var/log/mail.warn /var/log/mail.err /var/log/mail.log /var/log/daemon.log /var/log/kern.log /var/log/auth.log /var/log/user.log /var/log/lpr.log /var/log/cron.log /var/log/debug /var/log/messages { rotate 4 weekly missingok notifempty compress delaycompress sharedscripts postrotate /usr/lib/rsyslog/rsyslog-rotate endscript }
rsyslogファイルだけでも、対象のログファイルが多くあります。
常駐プロセスの rsyslogdから出力されているログファイル群ですね。
ぱっと見で分かると思いますが、上の方に羅列されているファイルパスが対象のログファイルで、{}で囲われた設定でローテーションを行うようになっています。
上記の /etc/logrotate.conf の設定にも同じものがあり、多分ですが include行の位置により(後ろにある)のでこちらが優先するようになってるんでしょう。
設定内容はこのように。
rotate | 残す世代数 |
weekly | 最後のローテーションから7日間隔(日曜日がデフォ) |
missingok | 対象ログファイルが無くても良しとする |
notifempty | 空の場合ローテーションしない |
compress | gzipで圧縮 |
delaycompress | 直近ファイルの圧縮延期 |
sharedscripts 〜endscript | ログローテート後にここに書いたコマンドを実行する |
詳細は logrotateコマンドのマニュアルに書いてありますが、何となくわかるんじゃないでしょうか。
ログのローテーションに加えたいログファイルがあってこの設定と全く同じで良ければ、この設定ファイル上の方にログファイルのパスを足してやれば OKです。
ちょっと別な設定でローテーションしたいというなら、/etc/logrotate.d ディレクトリ下に設定ファイルを作ってやれば OKです。
最初の方に書いている通り、ログファイルは見てナンボのところ大きくなり過ぎると困るので、maxsize 設定で1ファイルあたり最大 10MBくらいに抑えておくのが程良いと思います。
これで自由自在にログファイルのローテーションを行えそうな気もしてきますが、ここで1つ注意点があります。
ログファイルのローテーションを考える時気にしなければいけないのは以下 2点
- アプリケーション(ログ出し元)はログファイルをどう扱っているか
- ログファイル監視との関係
これら業務でやっていて考慮していたポイントでしたので、書いておきますね。
●ログを出力するアプリケーションはログファイルを掴んでいないか
/etc/logrotate.conf の中に「create」という設定がありました。
あれはこのような動きをする設定です。
- 現在のログファイルをリネーム
- 新しく 0バイトのファイルを本来のログファイル名で作成
アプリケーションがログファイルに対してただ追記するだけのものならこれで良いのですが、ものによっては ログファイルをオープンしっ放しにしている場合があります。
アプリケーションからしてみれば、アプリケーション外からログファイルをイジられるなんて想定していませんから、設計としてはおかしくないんですね。
だからオープンしているファイル(i-node番号で紐付けされてる)のファイル名を変更するとか削除するとかされると、やや怪しい動きをするものがあるかも知れません。
Tomcatのログはこのタイプです。
なので上の設定でも「postrotate」という設定で、アプリケーション(この場合 rsyslogd)にログのローテーションを促すコマンドを実行している訳です。
logrotateコマンドには、こういうケースのために「copytruncate」なんて設定も持っていて、こんな動きになります。
- 現在のログファイルを別名ファイルにコピー
- 現在のファイルの中身を 0バイトに変更
●ログ監視との関係
ログ監視の仕組みは「ログの何行目までは監視済みか」というポインタを持っていて、システム再起動時などに既に監視済みのログメッセージを再度監視しないようにしています。
この際に、アプリケーションとログファイルの関係と同じことが起きます。
日立の JP1/Baseなんかはログファイルのローテーションに対応できるよう設計されていまして、監視対象のログファイルのローテーションの種別の選択肢がありました。
こんな事情がありまして、実際の運用の経験を通して考えてみても、ログローテーションの仕組みを持っているアプリケーションではその仕組みに任せた方が無難、というのが私の結論でした。
ここまで logrotateコマンドを紹介しておいてナンですが。
そう考えると、最近のアプリケーションはログローテーション機能を持っているものばかりですので、logrotateコマンドの出番はあまり無いかも知れません。
自分で作ったバッチジョブ用シェルスクリプトのログファイルなどをローテーションしたい場合は、logrotateコマンドの仕組みに組み込むのが良いと思います。
Windowsのイベントログはそれ自体にローテーション機能を持っているのでそれに任せるとして、テキストログは良い方法が思いつきません。
Powershellスクリプトで誰か作っているとは思いますが…。
ログローテーションに関しては以上でございます。
ご機嫌良う。