FileLog では、次のことができます。
- ログファイルをサブスクライブする。
- サブスクライブしたログファイルに追記された新しいレコードを処理する。
テーブルの作成
path_to_logs– サブスクライブするログファイルのパス。ログファイルを含むディレクトリへのパス、または単一のログファイルへのパスを指定できます。相対パスは、file テーブル関数と同様に、user_files_pathディレクトリを基準に解決されます。ただし、サーバーの作業ディレクトリを基準にすでにuser_files_path内を指している相対パス (たとえば、公式 Docker イメージのようにサーバーがデータディレクトリ内で実行されている場合のuser_files/my_app/app.log) は、作業ディレクトリを基準とするパスとして扱われます。パス内のファイル名には glob (*、?、{abc,def}、{N..M}) を使用でき、ディレクトリ内で一致するファイルのみを読み込めます。詳しくは glob によるファイルの選択 を参照してください。なお、ClickHouse で指定できるのはuser_filesディレクトリ内のパスのみです。format_name- レコードのフォーマット。FileLog はファイル内の各行を個別のレコードとして処理するため、すべてのデータフォーマットがこれに適しているわけではありません。
poll_timeout_ms- ログファイルから 1 回pollする際のタイムアウト。デフォルト: stream_poll_timeout_ms。poll_max_batch_size— 1 回のpollで取得するレコードの最大数。デフォルト: max_block_size。max_block_size—pollの最大バッチサイズ (レコード数) 。デフォルト: max_insert_block_size。max_threads- ファイルをパースする最大スレッド数。デフォルトは 0 で、この場合は max(1, physical_cpu_cores / 4) が使用されます。poll_directory_watch_events_backoff_init- ディレクトリ監視スレッドの初期スリープ値。デフォルト:500。poll_directory_watch_events_backoff_max- ディレクトリ監視スレッドの最大スリープ値。デフォルト:32000。poll_directory_watch_events_backoff_factor- バックオフの進み方。デフォルトは指数関数的です。デフォルト:2。handle_error_mode— FileLog エンジン のエラー処理方法。設定可能な値: default (レコードのパースに失敗した場合、直接のSELECTでは例外がスローされます。テーブルが materialized view にストリーミングしている間は、そのレコードはスキップされ、エラーはサーバーログに書き込まれます) 、stream (例外メッセージと生のレコードが仮想カラム_errorおよび_raw_recordに保存されます) 。
説明
配信されたレコードは自動的に追跡されるため、ログファイル内の各レコードは一度しかカウントされません。copytruncate を指定した logrotate の実行後など、次回の読み取り時にファイルが記録済みのオフセットより短くなっている場合は、そのファイルは先頭から再度読み取られます。ただし、次回の読み取りまでにファイルサイズがそのオフセット以上に戻った場合、切り詰めは検出されません。ディレクトリ内で複数の名前を持つファイル (ハードリンク) は、そのうちいずれか 1 つの名前で読み取られます。
開けないファイル (リンク先が削除されたシンボリックリンク、サーバーに読み取り権限がないファイル、または単一ファイルのテーブルで削除されたファイル) は、サーバーログにエラーが記録され、スキップされます。テーブルがロードされている間は、ファイルを開けるようになるまで再試行されます。存在しなかったファイルが開けるようになると、先頭から読み取られます。シンボリックリンクは、テーブルがそのリンクを検出した時点でリンク先が存在する場合にのみ読み取られます。
SELECT はレコードの読み取りにはあまり適していません (デバッグ用途を除く) 。各レコードは一度しか読み取れないためです。より実用的なのは、materialized view を使ってリアルタイムのストリームを作成することです。そのためには、次のようにします。
- エンジンを使用して FileLog テーブルを作成し、それをデータストリームとして扱います。
- 必要な structure を持つテーブルを作成します。
- エンジンからのデータを変換し、あらかじめ作成したテーブルに格納する materialized view を作成します。
MATERIALIZED VIEW をエンジンに接続すると、バックグラウンドでデータの収集が開始されます。これにより、ログファイルからレコードを継続的に受け取り、SELECT を使って必要なフォーマットに変換できます。
1 つの FileLog テーブルには、必要な数だけ materialized view を持たせることができます。これらはテーブルから直接データを読み取るのではなく、新しいレコードを block 単位で受け取ります。そのため、詳細度の異なる複数のテーブルに書き込むことができます (グループ化と aggregation を行うもの/行わないもの) 。
例:
ALTER を使用してターゲットテーブルを変更する場合は、ターゲットテーブルとビューのデータに不整合が生じるのを避けるため、materialized view を無効にすることを推奨します。
glob によるファイルの選択
path_to_logs のファイル名に glob が含まれている場合、テーブルはそのディレクトリ内で名前が一致するファイルを読み取ります。後から作成されたファイルも対象になります。パスのディレクトリ部分では glob はサポートされていません。
テーブルが読み取っているファイルは、一致しない名前にリネームされても、ディレクトリから削除されるまで読み取られ続けます。一方、テーブルがデタッチされている間やサーバーが停止している間に作成され、一致しない名前にリネームされたファイルは読み取られません。macOS ではディレクトリの一覧を比較してディレクトリを監視するため、テーブルが一覧を取得する前に作成され、一致しない名前にリネームされたファイルも同様に読み取られません。これはログローテーションに求められる動作です。例えば、compress と delaycompress を指定した logrotate では、ディレクトリは次のような状態になります。
FileLog('/var/lib/clickhouse/user_files/my_app/*.log', 'JSONEachRow') を使用するテーブルは app.log を読み取ります。ローテーション後も app.log.1 の読み取りを継続するため、アプリケーションがログファイルを開き直すまでの間にそのファイルへ書き込んだ行が失われることはありません。また、圧縮済みファイルが読み取られることもありません。glob が圧縮済みファイルのファイル名に一致しないようにしてください。
仮想カラム
_filename- ログファイル名。データ型:LowCardinality(String)._offset- ログファイル内のオフセット。データ型:UInt64.
handle_error_mode='stream' の場合に追加される仮想カラム:
_raw_record- 正常にパースできなかった生のレコード。データ型:Nullable(String)._error- パース失敗時に発生した例外メッセージ。データ型:Nullable(String).
_raw_record と _error の仮想カラムに値が入るのは、パース中に例外が発生した場合のみです。メッセージが正常にパースされた場合、これらは常に NULL になります。
データの永続性
FileLog エンジンは、チャンクに対応する挿入がコミットされる前に、そのチャンクまで読み取ったオフセットを記録します。そのため、サーバーが中断されると、記録されたオフセットがターゲットテーブルに到達したデータより先に進む可能性があります。再起動時には、各ログファイルはメタデータディレクトリに記録されたオフセットから読み取りを再開するため、それらの行が再読み込みされることはありません。エラーは発生せずにデータが失われ、count() が単に小さくなります。通常のプロセス障害だけでもこの問題は発生し、電源断は必要ありません。これは、ターゲットパートの書き込みがまだ完了していない間にオフセットがメタデータファイルへ記録され、そのファイルが所定の場所へリネームされるためです。
OS page cache が失われると、すでにターゲットテーブルへ書き込まれたデータも失われる可能性があります。たとえば、デバイスレベルの電源断や、不適切なホストまたはカーネルのリセットが該当します。オフセットを保持するメタデータファイル自体も、ファイルまたはそのディレクトリに対して fsync を実行せずに書き込まれるため、それ自体の永続性も保証されません。
メッセージブローカーエンジンとは異なり、ターゲットを先に永続化しても FileLog をこの問題から保護することはできません。オフセットは、対応する挿入が完了する前に読み取りパイプライン内から記録されるため、ターゲットの MergeTree テーブルで fsync_after_insert = 1 を設定しても、オフセットが進む前に挿入されたパートの永続性を確立することはできません。FileLog の消費は、ローカルファイルをベストエフォートで追尾するものとして扱ってください。行を一切失えない場合は、消費したデータがターゲット内で検証されるまでソースログファイルを保持し、必要に応じて再度消費できるようにします。SYSTEM RESET FILELOG を実行するか、テーブルを削除して再作成すると、記録されたオフセットが破棄され、ファイルは先頭から再読み込みされます。