> ## 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` - 로그 파일에서 한 번 폴링할 때의 시간 초과 값입니다. 기본값: [stream\_poll\_timeout\_ms](/ko/reference/settings/session-settings/stream#stream_poll_timeout_ms).
* `poll_max_batch_size` — 한 번의 폴링으로 가져올 수 있는 최대 레코드 수입니다. 기본값: [max\_block\_size](/ko/reference/settings/session-settings/max#max_block_size).
* `max_block_size` — 폴링의 최대 배치 크기(레코드 수)입니다. 기본값: [max\_insert\_block\_size](/ko/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 엔진에서 오류를 처리하는 방식입니다. 가능한 값: default(메시지 파싱에 실패하면 예외를 발생시킴), stream(예외 메시지와 원시 메시지를 가상 컬럼 `_error` 및 `_raw_message`에 저장함).

## 설명

전달된 레코드는 자동으로 추적되므로 로그 파일의 각 레코드는 한 번만 계산됩니다.

레코드를 읽는 용도로는 `SELECT`가 그다지 유용하지 않습니다(디버깅 시 제외). 각 레코드는 한 번만 읽을 수 있기 때문입니다. 보다 실용적인 방법은 [materialized view(materialized views)](/ko/reference/statements/create/view)를 사용해 실시간 스트림을 만드는 것입니다. 이를 위해 다음을 수행하십시오:

1. 이 엔진을 사용해 FileLog 테이블을 만들고, 이를 데이터 스트림으로 간주합니다.
2. 원하는 구조의 테이블을 생성합니다.
3. 엔진의 데이터를 변환해 앞서 생성한 테이블에 저장하는 materialized view를 생성합니다.

`MATERIALIZED VIEW`를 엔진에 연결하면 백그라운드에서 데이터 수집이 시작됩니다. 이를 통해 로그 파일의 레코드를 지속적으로 수신하고, `SELECT`를 사용해 필요한 포맷으로 변환할 수 있습니다.
하나의 FileLog 테이블에는 원하는 만큼 materialized view를 둘 수 있습니다. 이들은 테이블에서 데이터를 직접 읽는 대신 새 레코드(블록 단위)를 받습니다. 따라서 상세 수준이 서로 다른 여러 테이블에 쓸 수 있습니다(그룹화/집계 적용 또는 미적용).

예시:

```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를 detach하십시오:

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

`ALTER`를 사용해 대상 테이블을 변경하려면, 대상 테이블과 뷰 데이터 간 불일치를 방지하기 위해 materialized view를 비활성화하는 것이 좋습니다.

## 가상 컬럼(Virtual columns)

* `_filename` - 로그 파일 이름입니다. 데이터 타입: `LowCardinality(String)`.
* `_offset` - 로그 파일 내 오프셋입니다. 데이터 타입: `UInt64`.

`handle_error_mode='stream'`일 때 추가되는 가상 컬럼:

* `_raw_record` - 성공적으로 파싱되지 않은 원시 레코드입니다. 데이터 타입: `Nullable(String)`.
* `_error` - 파싱 실패 중 발생한 예외 메시지입니다. 데이터 타입: `Nullable(String)`.

참고: `_raw_record` 및 `_error` 가상 컬럼은 파싱 중 예외가 발생한 경우에만 채워지며, 메시지가 성공적으로 파싱된 경우에는 항상 `NULL`입니다.

## 데이터 내구성

`FileLog` 엔진은 청크가 포함된 삽입이 커밋되기 전에 해당 청크를 소비한 오프셋을 먼저 기록하므로, 서버가 비정상 종료되면 기록된 오프셋이 실제로 대상 테이블에 반영된 데이터보다 앞서 있을 수 있습니다. 재시작하면 각 로그 파일은 메타데이터 디렉터리에 기록된 오프셋부터 이어서 읽기 때문에 그 사이의 행들은 다시 읽히지 않습니다. 즉, 아무런 오류 없이 유실되고 `count()` 값만 줄어듭니다. 전원 손실이 아니라 일반적인 프로세스 장애만으로도 이 문제가 발생하는데, 대상 파트가 아직 기록되는 중에 메타데이터 파일이 제자리로 이름이 변경되면서 오프셋이 기록되기 때문입니다.

OS 페이지 캐시가 유실되면 이미 대상 테이블에 기록된 데이터까지 함께 사라질 수 있습니다. 장치 수준의 전원 손실이나 비정상적인 호스트 또는 커널 리셋이 그 예입니다. 오프셋을 담고 있는 메타데이터 파일 자체도 파일이나 해당 디렉터리에 대한 fsync 없이 기록되므로, 그 자체로는 어떠한 내구성도 보장하지 않습니다.

메시지 브로커 엔진과 달리 `FileLog`에서는 대상을 먼저 내구성 있게 만드는 방식으로 이 문제를 막을 수 없습니다. 오프셋은 읽기 파이프라인 내부에서, 그것이 속한 삽입이 완료되기 전에 기록되므로, 대상 `MergeTree` 테이블에 `fsync_after_insert = 1`을 설정하더라도 오프셋이 전진하기 전에 삽입된 파트가 내구성 있게 확정되지는 않습니다. 따라서 `FileLog` 활용은 로컬 파일에 대한 최선 노력(best-effort) 방식의 테일링으로 간주하십시오. 단 한 행도 유실되어서는 안 되는 환경이라면, 소비된 데이터가 대상에서 검증될 때까지 원본 로그 파일을 보관하여 언제든 다시 활용할 수 있도록 하십시오. 테이블을 삭제하고 다시 생성하면 기록된 오프셋이 폐기되고 파일을 처음부터 다시 읽습니다.
