> ## Documentation Index
> Fetch the complete documentation index at: https://private-7c7dfe99-parallel-read-in-order-multi-part.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

> このエンジンは、アプリケーションのログファイルをレコードのストリームとして処理できます。

# FileLog テーブルエンジン

このエンジンは、アプリケーションのログファイルをレコードのストリームとして処理できます。

`FileLog` では、次のことができます。

* ログファイルをサブスクライブする。
* サブスクライブしたログファイルに追記された新しいレコードを処理する。

## テーブルの作成

```sql theme={null}
CREATE TABLE [IF NOT EXISTS] [db.]table_name [ON CLUSTER cluster]
(
    name1 [type1] [DEFAULT|MATERIALIZED|ALIAS expr1],
    name2 [type2] [DEFAULT|MATERIALIZED|ALIAS expr2],
    ...
) ENGINE = FileLog('path_to_logs', 'format_name') SETTINGS
    [poll_timeout_ms = 0,]
    [poll_max_batch_size = 0,]
    [max_block_size = 0,]
    [max_threads = 0,]
    [poll_directory_watch_events_backoff_init = 500,]
    [poll_directory_watch_events_backoff_max = 32000,]
    [poll_directory_watch_events_backoff_factor = 2,]
    [handle_error_mode = 'default']
```

エンジン引数:

* `path_to_logs` – サブスクライブするログファイルのパス。ログファイルを含むディレクトリへのパス、または単一のログファイルへのパスを指定できます。なお、ClickHouse で指定できるのは `user_files` ディレクトリ内のパスのみです。
* `format_name` - レコードのフォーマット。FileLog はファイル内の各行を個別のレコードとして処理するため、すべてのデータフォーマットがこれに適しているわけではありません。

パラメータ:

* `poll_timeout_ms` - ログファイルから 1 回 `poll` する際のタイムアウト。デフォルト: [stream\_poll\_timeout\_ms](/ja/reference/settings/session-settings/stream#stream_poll_timeout_ms)。
* `poll_max_batch_size` — 1 回の `poll` で取得するレコードの最大数。デフォルト: [max\_block\_size](/ja/reference/settings/session-settings/max#max_block_size)。
* `max_block_size` — `poll` の最大バッチサイズ (レコード数) 。デフォルト: [max\_insert\_block\_size](/ja/reference/settings/session-settings/max-insert#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 engine のエラー処理方法。設定可能な値: default (メッセージの解析に失敗した場合は例外がスローされます) 、stream (例外メッセージと生のメッセージが仮想カラム `_error` および `_raw_message` に保存されます) 。

## 説明

配信されたレコードは自動的に追跡されるため、ログファイル内の各レコードは一度しかカウントされません。

`SELECT` はレコードの読み取りにはあまり適していません (デバッグ用途を除く) 。各レコードは一度しか読み取れないためです。より実用的なのは、[materialized view](/ja/reference/statements/create/view) を使ってリアルタイムのストリームを作成することです。そのためには、次のようにします。

1. エンジンを使用して FileLog テーブルを作成し、それをデータストリームとして扱います。
2. 必要な structure を持つテーブルを作成します。
3. エンジンからのデータを変換し、あらかじめ作成したテーブルに格納する materialized view を作成します。

`MATERIALIZED VIEW` をエンジンに接続すると、バックグラウンドでデータの収集が開始されます。これにより、ログファイルからレコードを継続的に受け取り、`SELECT` を使って必要なフォーマットに変換できます。
1 つの FileLog テーブルには、必要な数だけ materialized view を持たせることができます。これらはテーブルから直接データを読み取るのではなく、新しいレコードを block 単位で受け取ります。そのため、詳細度の異なる複数のテーブルに書き込むことができます (グループ化と aggregation を行うもの／行わないもの) 。

例:

```sql theme={null}
CREATE TABLE logs (
    timestamp UInt64,
    level String,
    message String
  ) ENGINE = FileLog('user_files/my_app/app.log', 'JSONEachRow');

CREATE TABLE daily (
    day Date,
    level String,
    total UInt64
  ) ENGINE = SummingMergeTree
  PARTITION BY toYYYYMM(day)
  ORDER BY (day, level);

CREATE MATERIALIZED VIEW consumer TO daily
    AS SELECT toDate(toDateTime(timestamp)) AS day, level, count() AS total
    FROM logs GROUP BY day, level;

SELECT level, sum(total) FROM daily GROUP BY level;
```

ストリームのデータ受信を停止する、または変換ロジックを変更するには、materialized view をデタッチします:

```sql theme={null}
DETACH TABLE consumer;
ATTACH TABLE consumer;
```

`ALTER` を使用してターゲットテーブルを変更する場合は、ターゲットテーブルとビューのデータに不整合が生じるのを避けるため、materialized view を無効にすることを推奨します。

## 仮想カラム

* `_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` の消費は、ローカルファイルをベストエフォートで追尾するものとして扱ってください。行を一切失えない場合は、消費したデータがターゲット内で検証されるまでソースログファイルを保持し、必要に応じて再度消費できるようにします。テーブルを削除して再作成すると、記録されたオフセットが破棄され、ファイルは先頭から再読み込みされます。
