---
title: "FS 读取器"
description: "使用 readFsLogs 和 tailFsLogs 重放并尾随本地 NDJSON drain —— 可在进程内运行，也可通过任何外部 Node 工具运行，并且可在重启后继续工作。"
canonical_url: "https://evlog.zhcndoc.com/extend/fs-reader"
---
# FS 读取器

> 使用 readFsLogs 和 tailFsLogs 重放并尾随本地 NDJSON drain —— 可在进程内运行，也可通过任何外部 Node 工具运行，并且可在重启后继续工作。

[文件系统 drain](https://evlog.zhcndoc.com/integrate/adapters/self-hosted/fs) 会将宽事件以 NDJSON 形式写入 `.evlog/logs/` 下的 `.jsonl` 文件中（按天一个文件，例如 `2026-05-08.jsonl`；当启用基于大小的轮转时，还会带有诸如 `.1.jsonl` 的轮转后缀）。`evlog/fs` 模块还提供了**读取器**，让任何 Node 工具都能回放或跟随这段历史，而无需挂钩到正在运行的应用程序中。

<ndjson-tail>



</ndjson-tail>

<prompt :actions="["copy","cursor","claude"]" description="从磁盘读取或尾随 evlog NDJSON 日志" icon="i-lucide-folder-search">

构建一个脚本，用于消费 evlog 的本地 NDJSON 历史记录（无需应用挂钩）。

- 确认文件系统 drain 已接入（`evlog/fs` 适配器将 NDJSON 写入 `.evlog/logs/*.jsonl`）
- 对于回放：从 `evlog/fs` 导入 `readFsLogs`，并迭代 `for await (const event of readFsLogs({ since, until, level, filter }))`
- 对于跟随模式：导入 `tailFsLogs` 并以相同方式进行迭代。它会监视新行、处理轮转，并接受一个 `AbortSignal`
- 在读取时应用过滤器（`level`、`since`、`until`、自定义 `filter` 谓词），而不是进行后处理
- 将格式错误的行视为静默跳过（可能发生部分写入），并且绝不要让脚本因错误行而崩溃

文档：[https://www.evlog.dev/extend/fs-reader](https://www.evlog.dev/extend/fs-reader)

</prompt>

## 回放历史

```ts
import { readFsLogs } from 'evlog/fs'

for await (const event of readFsLogs({ since: '2026-03-01', level: 'error' })) {
  console.log(event.timestamp, event.action ?? event.message)
}
```

`readFsLogs(options)` 会按时间顺序遍历 NDJSON 文件，逐行解析，并产出通过所有过滤条件的事件。日期窗口之外的文件会被直接跳过。

### 选项

<table>
<thead>
  <tr>
    <th>
      选项
    </th>
    
    <th>
      类型
    </th>
    
    <th>
      描述
    </th>
  </tr>
</thead>

<tbody>
  <tr>
    <td>
      <code>
        dir
      </code>
    </td>
    
    <td>
      <code>
        string
      </code>
    </td>
    
    <td>
      要读取的目录。默认：<code>
        .evlog/logs
      </code>
      
      。
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        since
      </code>
    </td>
    
    <td>
      <code>
        Date | string
      </code>
    </td>
    
    <td>
      产出 <code>
        timestamp >= since
      </code>
      
       的事件。
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        until
      </code>
    </td>
    
    <td>
      <code>
        Date | string
      </code>
    </td>
    
    <td>
      产出 <code>
        timestamp <= until
      </code>
      
       的事件。
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        level
      </code>
    </td>
    
    <td>
      <code>
        LogLevel | LogLevel[]
      </code>
    </td>
    
    <td>
      按事件级别过滤。
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        filter
      </code>
    </td>
    
    <td>
      <code>
        (event) => boolean
      </code>
    </td>
    
    <td>
      自定义谓词。
    </td>
  </tr>
</tbody>
</table>

格式错误的行（部分写入、手动编辑）会被静默跳过，因此你的脚本永远不会因错误行而崩溃。

## 实时尾随

```ts
import { tailFsLogs } from 'evlog/fs'

const ac = new AbortController()
process.on('SIGINT', () => ac.abort())

for await (const event of tailFsLogs({ signal: ac.signal })) {
  console.log('live:', event.action ?? event.message)
}
```

`tailFsLogs(options)` 首先产出现有事件（除非 `fromEnd: true`），然后在新事件追加时持续产出，包括写入新创建的每日文件中的事件。跨轮询拆分的部分写入会被透明地重新组合。

### 尾随特有选项

<table>
<thead>
  <tr>
    <th>
      选项
    </th>
    
    <th>
      类型
    </th>
    
    <th>
      描述
    </th>
  </tr>
</thead>

<tbody>
  <tr>
    <td>
      <code>
        pollIntervalMs
      </code>
    </td>
    
    <td>
      <code>
        number
      </code>
    </td>
    
    <td>
      轮询间隔。默认：500ms（最小 50ms）。
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        fromEnd
      </code>
    </td>
    
    <td>
      <code>
        boolean
      </code>
    </td>
    
    <td>
      跳过已有事件；仅产出未来事件。默认：false。
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        signal
      </code>
    </td>
    
    <td>
      <code>
        AbortSignal
      </code>
    </td>
    
    <td>
      在中止时停止尾随。
    </td>
  </tr>
</tbody>
</table>

所有 [`readFsLogs`](#options) 选项也同样适用。

## 使用场景

- 一个本地 Electron / Tauri 仪表盘，从目标项目目录读取 `.evlog/logs/`
- 一个在测试运行后扫描日志的 CI 报告聚合器
- 一个类似 `grep` 的 CLI，将过滤后的事件管道传给 `jq`
- 在切换到实时的进程内订阅之前，先将历史事件回放到仪表盘中。参见 [先回放再实时配方](https://evlog.zhcndoc.com/extend/consumer-recipes#3-replay-history-then-go-live)。


## Sitemap

See the full [sitemap](https://evlog.zhcndoc.com/sitemap.md) for all pages.
