Splunk Forwarderのファイル監視を理解する: fishbucketとCRCの基本
Tips & Tricks 森山 雅也 (Masaya Moriyama)はじめに
Splunk Universal ForwarderやHeavy Forwarderでファイルを監視していると、次のような事象に遭遇することがあります。
- ソースファイルは存在するが、Splunk側でイベントが検索できない
- splunk list inputstatusではfinished readingと表示されている
- 同じログが再度取り込まれて重複して見える
- splunkd.logに File will not be readやseekptr checksumが出力されている
- crcSalt = <SOURCE>を設定すべきか迷う
このような場合、まず確認したいのがfishbucketとCRCです。
Forwarderのファイル監視で「ログが取り込まれない」「重複する」「想定と異なるsourceで取り込まれる」といった問題を調査する際には、これらは重要な手がかりになります。
今回は、Forwarderのファイル監視を理解するうえで知っておきたいfishbucket、CRC、crcSalt、initCrcLengthの基本と、トラブルシュート時の確認点をご紹介します。
1. fishbucketとCRCによるファイル追跡
Forwarderは、監視対象のファイルを見つけると、そのファイルをどこまで読んだかを記録します。
この読み取り状態を保存する内部のチェックポイントデータベースがfishbucketです。
たとえば/var/log/app.logを監視している場合、Splunkは「このファイルをどこまで読んだか」を覚えておく必要があります。これがないと、Splunkの再起動やログローテーションのたびに、同じデータを何度も取り込んでしまいます。
標準構成では、fishbucketは次の場所にあります。
$SPLUNK_HOME/var/lib/splunk/fishbucket/splunk_private_db
SPLUNK_DBを標準の場所から変更している場合は、実際のデータ保存先を確認してください。
Splunkはファイルを識別するとき、ファイル名だけを見ているわけではありません。
Splunkのmonitor inputでは、デフォルトでファイル先頭の256バイトを読み取り、その内容からCRCを計算します。このbeginning CRCは、ファイル冒頭部分を使ったフィンガープリントのようなものです。
Splunkはbeginning CRCをキーとして、fishbucketに保存されている過去の情報を探します。該当するエントリが見つかると、seekAddress(読み込み済みのバイト位置)や、その位置の内容を確認するためのseekCRCなどを参照します。
このようにCRCは、monitor inputがファイルを識別し、fishbucket上の読み取り位置を参照するための手がかりとして使われます。この情報は、Splunkがログローテーション時にファイルを識別する仕組みでも使われます。これにより、ローテーション後のファイルを新しいファイルと誤認し、同じデータを二重に取り込むことを防ぎます。
一方で、別のファイルであっても先頭の256バイトが同一であれば、同じbeginning CRCになります。beginning CRCが一致すると、Splunkは同じfishbucketエントリのseekAddressとseekCRCを使って、過去に読み取ったファイルとの連続性を確認します。
異なるファイルが同じbeginning CRCを持つ場合、Splunkはそれぞれの読み取り位置を独立して追跡できません。その結果、一方のファイルが読み取られなかったり、イベントが想定と異なるsourceで取り込まれたりすることがあります。
たとえば、次のようなファイルでは注意が必要です。
- 先頭に長い固定ヘッダーがある
- stack traceや定型メッセージで冒頭が同じ
- 同じテンプレートから複数種類のログが作られる
このような場合、デフォルトのbeginning CRCだけではファイルを十分に区別できず、「ファイルが読み飛ばされたように見える」「想定と異なるsourceで取り込まれる」といった状況になることがあります。CRCはファイルを見分けるための重要な判断材料ですが、先頭の256バイトだけでは区別できないファイルもあります。
2. CRC関連のログと読み取り状態
fishbucketやCRCに関係する問題では、splunkd.logやinputstatusに特徴的なメッセージや状態が現れることがあります。たとえば、splunkd.logに次のようなメッセージが出る場合があります。
File will not be read, is too small to match seekptr checksum
Last time we saw this initcrc, filename was different.
You may wish to use larger initCrcLen for this sourcetype, or a CRC salt on this source.
これは、対象ファイルのbeginning CRCに対応する過去のエントリがfishbucketに見つかったものの、現在のファイルが短く、保存されている読み取り位置でseekCRCを照合できないことを示しています。ファイルの切り詰めや再作成のほか、先頭部分が同一の別ファイルを検出した場合にも発生することがあります。また、inputstatusの実行結果では、次のように表示されることがあります。
type = ignored file (crc conflict, needs crcSalt)
この場合は、同じbeginning CRCを持つファイルがあり、Splunkが対象ファイルを独立したファイルとして扱えていない可能性があります。また、次のようなfinished readingは、Forwarderのmonitor inputがファイル終端まで処理した状態を示します。
file position = 4738
file size = 4738
percent = 100.00
type = finished reading
ただし、これだけで「Indexerに保存され、検索できる状態になった」とまでは判断できません。
finished readingを確認できた場合は、次に転送、インデックス処理、検索条件のどこでデータが見えなくなっているのかを切り分けます。
3. initCrcLengthとcrcSaltの設定
initCrcLengthとcrcSaltは、どちらもCRCによるファイル識別に関係するinputs.confの設定です。ファイルのどこに識別可能な差分があるかと、ログローテーションの方式を確認して使い分けます。
initCrcLengthは、CRCの計算に使うファイル先頭のバイト数を増やす設定です。先頭の256バイトは同一でも、もう少し後ろまで読むとファイルごとの差分が現れる場合に有効です。
[monitor:///path/to/logs/*.log]
initCrcLength = 1024
設定値は大きければよいというものではなく、サンプルファイルを比較し、何バイト目で差分が現れるかを確認してから決めることをおすすめします。
また、initCrcLengthを変更するとファイル識別に使うCRCも変わるため、既存データが再度取り込まれる可能性があります。本番環境へ適用する前に、対象ファイルと影響範囲を確認してください。
長い固定ヘッダーや長いstack traceが複数ファイルで共通している場合、initCrcLengthを大きくしても期待した効果が出ないことがあります。その場合は、crcSaltやmonitor stanzaの設計を見直します。
crcSaltはCRCの計算にsaltを追加します。代表的な設定は次の形式です。
[monitor:///path/to/logs/*.log]
crcSalt = <SOURCE>
<SOURCE>を指定すると、ファイルのフルパスがCRCに追加されます。そのため、先頭部分が同一のファイルでも、パスが異なれば別のファイルとして識別されます。
これは、別ファイルであるにもかかわらず先頭の256バイトが同一の場合に有効な対策候補です。
ただし、crcSalt = <SOURCE>はいつでも安全に使える設定ではありません。ログローテーションやファイルの移動によってパスが変わると、Splunkが別のファイルとして認識し、既に読んだデータを再度取り込むことがあります。
たとえば、次のような運用では注意が必要です。
- app.logがapp.log.1に名前変更される
- ワイルドカードを使ったstanzaで現行ファイルとローテーション後のファイルを両方監視している
- ローテーション後のファイルも同じディレクトリに残る
現行ファイルをローテーション前に読み取る運用であれば、ローテーション後のファイルをblacklistで監視対象から外す方法を検討できます。また、異なる種類のログを別々のmonitor stanzaで監視しており、そのstanza間でCRCが衝突する場合は、stanzaごとに異なる固定文字列のcrcSaltを指定する方法もあります。
[monitor:///path/to/system*.log]
crcSalt = system
[monitor:///path/to/journal*.log]
crcSalt = journal
固定文字列のsaltは、異なる値を設定したstanza間のCRCを区別します。同じstanza内にある複数ファイルには同じsaltが追加されるため、そのファイル同士を区別する方法にはなりません。
既存のmonitor stanzaにcrcSaltを追加したり値を変更したりすると、ファイル識別に使うCRCも変わります。適用時には、既存データが再度取り込まれないかを検証してください。
4. 調査で確認するコマンドと検索例
Forwarder側では、まず次のコマンドで監視設定と読み取り状態を確認します。
$SPLUNK_HOME/bin/splunk list inputstatus
$SPLUNK_HOME/bin/splunk btool inputs list --debug
パース処理を行うHeavy Forwarderでは、必要に応じてprops.confの有効な設定も確認します。
$SPLUNK_HOME/bin/splunk btool props list --debug
splunkd.logでは、例えば、次のような文字列を探します。
TailReader
TailingProcessor
WatchedFile
FileClassifierManager
File will not be read
seekptr checksum
initcrc
crc conflict
needs crcSalt
Checksum for seekptr
File too small to check seekcrc
Will re-read entire file
検索時はsource条件をいったん外し、ログ本文や_indextimeでも確認します。
index=<target_index> "<unique raw string>"
| table _time _indextime host source sourcetype index splunk_server _raw
確認時は、次の点も見ておくと切り分けやすくなります。
- source条件を外しても見つからないか
- _timeではなく_indextimeで見るとどうか
- 別のsource、sourcetype、indexに入っていないか
- イベント分割により、別イベントの_rawに含まれていないか
finished readingであるにもかかわらずイベントが見つからない場合は、Forwarderの読み取り後に範囲を広げ、転送、インデックス処理、検索条件を順に切り分けます。
まとめ
Forwarderのファイル監視では、ファイルパスだけでなく、fishbucketとCRCによるファイル追跡も確認ポイントになります。調査時には、次の観点で確認すると整理しやすくなるかと思います。
- btool inputsで、対象ファイルが意図したmonitor stanzaに含まれ、crcSaltやinitCrcLengthに想定外の設定がないことを確認する
- inputstatusで、対象ファイルが検知されているか、どこまで読み取られているかを確認する
- splunkd.logで、crc conflict、initcrc、seekptr checksumなど、CRC衝突を示すメッセージがないか確認する
- finished readingの場合は、source条件を外して検索し、転送、インデックス処理、検索条件へ調査範囲を広げる
- CRC衝突が確認できた場合に、ログローテーション方式を踏まえてinitCrcLengthまたはcrcSaltを検討し、変更後に重複取り込みや取りこぼしがないことを確認する
ログが想定通り取り込まれない、または想定と違う形で取り込まれる場合の確認ポイントとして、ぜひ参考にしてみてください。
Related Articles

脅威の連鎖を断ち切ろう:証明書サービスの悪用を防ぐ

テレワークにおけるセキュリティ課題とその対策方法
