お金をかけずにサーバーの勉強をしよう

ログのローテーション

2022年12月13日

メニューへ戻る

ログファイルをローテンションして溜まらないようにする話。

こんにちは。

サーバーの運用に関わっていれば、必ず出くわすログのローテーション。

いつ見られるとも知れないログをどうやってしまっておくかという非常〜にマイナーな運用ネタですが、こういう地道な作業をないがしろにしていると痛い目を見るというのは、運用エンジニアなら身を持って知っているものです。

最近のファイルシステムでは大きなログファイルを作っても何の問題も起きないからと放っておいた末に 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.

これはデフォルト値で、以下の内容になっています。

他にコメントアウトされてますが、黄色い字の設定でローテート後のログファイルの名前にデフォルトの数字ではなく 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空の場合ローテーションしない
compressgzipで圧縮
delaycompress直近ファイルの圧縮延期
sharedscripts
〜endscript
ログローテート後にここに書いたコマンドを実行する

詳細は logrotateコマンドのマニュアルに書いてありますが、何となくわかるんじゃないでしょうか。

ログのローテーションに加えたいログファイルがあってこの設定と全く同じで良ければ、この設定ファイル上の方にログファイルのパスを足してやれば OKです。

ちょっと別な設定でローテーションしたいというなら、/etc/logrotate.d ディレクトリ下に設定ファイルを作ってやれば OKです。

最初の方に書いている通り、ログファイルは見てナンボのところ大きくなり過ぎると困るので、maxsize 設定で1ファイルあたり最大 10MBくらいに抑えておくのが程良いと思います。


これで自由自在にログファイルのローテーションを行えそうな気もしてきますが、ここで1つ注意点があります。

ログファイルのローテーションを考える時気にしなければいけないのは以下 2点

これら業務でやっていて考慮していたポイントでしたので、書いておきますね。


●ログを出力するアプリケーションはログファイルを掴んでいないか

/etc/logrotate.conf の中に「create」という設定がありました。
あれはこのような動きをする設定です。

  1. 現在のログファイルをリネーム
  2. 新しく 0バイトのファイルを本来のログファイル名で作成

アプリケーションがログファイルに対してただ追記するだけのものならこれで良いのですが、ものによっては ログファイルをオープンしっ放しにしている場合があります。

アプリケーションからしてみれば、アプリケーション外からログファイルをイジられるなんて想定していませんから、設計としてはおかしくないんですね。

だからオープンしているファイル(i-node番号で紐付けされてる)のファイル名を変更するとか削除するとかされると、やや怪しい動きをするものがあるかも知れません。
Tomcatのログはこのタイプです。

なので上の設定でも「postrotate」という設定で、アプリケーション(この場合 rsyslogd)にログのローテーションを促すコマンドを実行している訳です。

logrotateコマンドには、こういうケースのために「copytruncate」なんて設定も持っていて、こんな動きになります。

  1. 現在のログファイルを別名ファイルにコピー
  2. 現在のファイルの中身を 0バイトに変更


●ログ監視との関係

ログ監視の仕組みは「ログの何行目までは監視済みか」というポインタを持っていて、システム再起動時などに既に監視済みのログメッセージを再度監視しないようにしています。

この際に、アプリケーションとログファイルの関係と同じことが起きます。

日立の JP1/Baseなんかはログファイルのローテーションに対応できるよう設計されていまして、監視対象のログファイルのローテーションの種別の選択肢がありました。


こんな事情がありまして、実際の運用の経験を通して考えてみても、ログローテーションの仕組みを持っているアプリケーションではその仕組みに任せた方が無難、というのが私の結論でした。

ここまで logrotateコマンドを紹介しておいてナンですが。

そう考えると、最近のアプリケーションはログローテーション機能を持っているものばかりですので、logrotateコマンドの出番はあまり無いかも知れません。

自分で作ったバッチジョブ用シェルスクリプトのログファイルなどをローテーションしたい場合は、logrotateコマンドの仕組みに組み込むのが良いと思います。


Windowsのイベントログはそれ自体にローテーション機能を持っているのでそれに任せるとして、テキストログは良い方法が思いつきません。
Powershellスクリプトで誰か作っているとは思いますが…。


ログローテーションに関しては以上でございます。
ご機嫌良う。