[Mackerel]ログローテーション運用時のログ監視で抑えておきたい「State」オプション

今回の記事ではMackerelを使ったログ監視における「State」という概念をログローテーションのパターン毎の検証も交えてまとめておきたいと思います。
2020.02.10

この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。

はじめに

こんにちは。大阪オフィスの林です。

みなさま、AWSの監視に何を使っていますでしょうか?弊社ではMackerelを利用した監視オプションサービスを提供しています。今回の記事ではMackerelを使ったログ監視における「State」という概念を検証交えてまとめておきたいと思います。またログ監視について下記の記事も併せてご覧頂ければと思います。

「State」とは?

Mackerelでは「State」オプションを使う(デフォルトで有効)ことによって、ログのチェック完了位置(バイト数)を「stateファイル」に出力し記録しておき、次回以降は前回チェック完了位置(バイト数)以降の出力差分に対して、ログのチェックを実施することが出来ます。

これは常に追記され続けるログファイルに対しては何も問題ないと思います。しかし世の中のシステムでは常に追記され続けるログファイルがある一方で、何かしらの方法でログのローテーションを行っているシステムも多くあります。ログのローテーションが行われた際の挙動についても説明していきたいと思うのですが、「Stateファイル」にはもう一つ重要な情報が記録されているのでそちらを先に説明したいと思います。

「Stateファイル」

「Stateファイル」には「ログのチェック完了位置(バイト数)」に加え、もう1つ重要な情報が記録されます。それは「inode(アイノード)番号」です。「inode番号」とはファイルの属性情報などをまとめたデータです。「State」オプションを使ったMackerelのログ監視では「mackerel-agent.conf」で記載した設定および、この「inode番号」を含む「Stateファイル」を使いながらログ監視を行います。

Mackerelの「Stateファイル」まとめ

Mackerelの「Stateファイル」では次の2つの情報を記録しています。

1. ログをどこまで見たかという記録

「skip_bytes」という情報を記録しログのどこまでチェックしたかを記録しています。次回以降は記録したbyte数をスキップしてチェックを始めます。(設定で毎回フルチェックへも変更可能)

2. どのファイルをチェックするかという記録

「inode番号」を記録し、どのファイルをチェックしたか(するか)を記録しています。

ログローテーションのパターン

「Stateファイル」の説明が終わったのでログのローテーションが行われた際の挙動についても説明していきたいと思います。今回は2つのログローテーションのパターンを取り上げます。ここでは1つを「リネームパターン」と呼び、もう1つを「コピーパターン」と呼ぶこととします。

リネームパターン

もとのログファイル名をリネームし、もとのログファイル名で再度ファイルを新規作成することでローテーションをしているパターンです。

コピーパターン

もとのログファイルを別名でコピーします。次にもとのログファイルの中身を初期化することでローテーションをしているパターンです。

プロセスは少し違うものの結果としては同じことをしているように見えます。しかし前述した「inode番号」という視点で見てみると全く異なるのです。続いてMackerelのログ監視の挙動と併せて確認していきます。

ログローテーション時のログ監視の挙動

リネームパターン(inodeの視点を入れる)

リネームパターンの場合、inode番号はリネーム後も継承されます。またログを再作成した際に、同じファイル名でもinode番号が異なって作成されます。

実機でも見てみます。まずmackerel-agent.conf内の設定確認です。/home/ec2-user/test.logの中身でerrorという文字があるかどうかを監視する設定です。

[plugin.checks.testlog]
command = ["check-log", "--file", "/home/ec2-user/test.log", "--pattern", "error", "--check-first", "--missing", "OK"]
prevent_alert_auto_close = true

実際のtest.logのinode番号を見ていきましょう。ls -iでinode番号を確認することが出来ます。今回の場合13360227がinode番号となります。

[ec2-user@ip-172-16-0-186 ~]$ ls -i test.log
13360227 test.log

次にMackerelで持っている「stateファイル」に記録されている情報を見ていきます。「stateファイル」はデフォルトで/var/tmp/mackerel-agent/check-log/配下にあります。check-log以降は実際のログのパスと同じパス(今回の場合は/home/ec2-user/)でディレクトリが切られます。下記の結果の場合、27バイトは次回スキップするという情報と、inode番号13360227が監視の対象ファイルであることが分かります。

[ec2-user@ip-172-16-0-186 ~]$ sudo cat /var/tmp/mackerel-agent/check-log/home/ec2-user/test.log-b80d3f843b6e93c6d5ba4b22e0d5747a.json
{"skip_bytes":27,"inode":13360227}

リネームしてみますが、リネームしてもinode番号が変わらないということが分かります。

[ec2-user@ip-172-16-0-186 ~]$ sudo mv test.log test.log.001
[ec2-user@ip-172-16-0-186 ~]$ ls -i test.log.001
13360227 test.log.001

ファイルを新規作成すると同じ名前でもinode番号が変わるということが分かります。

[ec2-user@ip-172-16-0-186 ~]$ sudo touch test.log
[ec2-user@ip-172-16-0-186 ~]$ ls -i test.log
13360193 test.log

Mackerelでは「ログローテーションが発生していないか否か」を「stateファイルに保存されたinode番号とファイルパスで指定されるファイルのもつinode番号の一致」を確認する形で毎回実施しています。stateファイルに保存されたinode番号とファイルパスで指定されるファイルのもつinode番号が不一致の場合、ログファイルのinode変更を検知して、ローテーションされたファイルをinode番号で特定し、そのファイル末尾までのチェックを実施します。よってリネームパターンでログがローテーションされる場合、監視周期が来て次の監視周期が来る前にログがローテーションされてしまっても、ローテーションされたファイルを漏れなくチェックすることが出来ます。

コピーパターン(inodeの視点を入れる)

次にコピーパターンを見ていきます。コピーパターンの場合、ローテーションされたファイルのinode番号はコピー時に別の番号が付与されます。もともとのファイルには何も変更を加えていないので、元のファイルのinode番号は変わりません。

実機でも見てみます。mackerel-agent.conf内の設定は先ほどと同じです。「stateファイル」を見てみます。13バイトは次回スキップするという情報と、inode番号13360193が監視の対象ファイルであることが分かります。

[ec2-user@ip-172-16-0-186 ~]$ sudo cat /var/tmp/mackerel-agent/check-log/home/ec2-user/test.log-b80d3f843b6e93c6d5ba4b22e0d5747a.json
{"skip_bytes":13,"inode":13360193}[ec2-user@ip-172-16-0-186 ~]$

コピーの場合、コピーした先のファイルのinode番号は変わりますが、もともとのログファイルのinode番号が変わらないということが分かります。

[ec2-user@ip-172-16-0-186 ~]$ ls -i test.log
13360193 test.log
[ec2-user@ip-172-16-0-186 ~]$ cp test.log test.log.001
[ec2-user@ip-172-16-0-186 ~]$ ls -i test.log*
13360193 test.log  13360227 test.log.001

次に「stateファイル」も見てみますが、先ほどの状態から変化はありません。

[ec2-user@ip-172-16-0-186 ~]$ sudo cat /var/tmp/mackerel-agent/check-log/home/ec2-user/test.log-b80d3f843b6e93c6d5ba4b22e0d5747a.json
{"skip_bytes":13,"inode":13360193}

このケースの場合、監視周期が来て次の監視周期が来る前にログがコピーでローテーションされてしまった場合、ローテーション先のログを監視することが出来ません。Mackerelからも下記が注意点として挙げられています。

logrotate でいうところの copytruncate 方式のログローテーションには対応していません。 ローテーション時にログファイル自身のコピーをおこない、ログファイルのリセットを行う場合、ログファイル自身のinode番号は変わらないため。

まとめ

ひとことに「ログ監視」と言っても色々なケースが世の中には存在しており、その中で要件や制約を考えながらより最適なアーキテクチャを見つけていかなければと感じた時間でした(Mackerelに限らず)。

以上、大阪オフィスの林がお送りしました!