gweber/logflow-sim
GitHub: gweber/logflow-sim
一个可解释的日志管道模拟器,用于验证和迁移日志配置,确保安全检测规则不被破坏。
Stars: 0 | Forks: 0
# logflow-sim
[](https://github.com/gweber/logflow-sim/actions/workflows/ci.yml)
[](LICENSE)
[](https://nodejs.org/)
[](CONTRIBUTING.md)
**可解释的日志管道模拟器。** 解析您的路由配置,构建一个规范化的中间表示,并模拟一条 syslog 消息通过它 — 发出每一步匹配的输入、进入的规则集、评估的条件、执行的查找、更改的变量以及触发的操作的逐步跟踪,所有信息均带有源位置。
无需调用上游守护进程。无需固定测试数据。无需对配置文本进行正则表达式处理。解析器和评估器在进程内使用 TypeScript 实现。
一个来自 [**netverdict.io**](https://netverdict.io) 的开源项目。采用 MIT 许可证。
第三方内容和商标通知见 [NOTICE.md](NOTICE.md) — rsyslog、syslog-ng、Fluent Bit、NXLog、Vector、OpenTelemetry、Logstash、Filebeat、Promtail、Fluentd、Sigma、Wireshark、MCP 和 Claude 是各自所有者的商标;logflow-sim 与其中任何一方均无关联。
## 作为 GitHub Action 使用
**在每次 PR 上进行验证:**
```
- uses: gweber/logflow-sim@v1
with:
conf-path: ./rsyslog
command: test
fail-on: errors
```
诊断信息将作为内联 PR 注释显示。
**差异模式 — 阻止那些会重新路由过多真实流量的 PR:**
```
# .github/workflows/logflow-diff.yml
on: pull_request
jobs:
diff:
permissions:
contents: read
pull-requests: write
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with: { ref: ${{ github.base_ref }}, path: base }
- uses: actions/checkout@v4
with: { path: head }
- uses: gweber/logflow-sim@v1
with:
command: diff
conf-path: base/rsyslog
overlay-dir: head/rsyslog
lines: head/test/fixtures/replay-corpus.log
max-route-change-pct: 5
pr-comment: true
```
该 Action 在 PR 上发布的内容:
完整示例请参见 [`examples/github-workflows/`](examples/github-workflows/)。
## 支持的方言
| 方言 | 解析 | 发出(转换目标) |
|---|---|---|
| rsyslog / RainerScript | ✓ 完整 | ✓ |
| syslog-ng | ✓ 完整 | ✓ |
| Fluent Bit | ✓ | ✓ |
| NXLog | ✓ | ✓ |
| Logstash | ✓ | ✓ |
| Vector | ✓ | ✓ |
| OpenTelemetry Collector | ✓ | ✓ |
| Filebeat | ✓ | ✓ |
| Promtail (Loki) | ✓ | ✓ |
| Fluentd (经典) | ✓ | ✓ |
每种方言位于 `src/core/dialects//` 下,并在 [`src/core/dialects/types.ts`](src/core/dialects/types.ts) 中实现了 `Dialect` 接口。模拟器和 UI 使用规范化的 IR — 它们与方言无关。
## 支持的 SIEM 目标平台
logflow-sim 了解 10 个主要 SIEM 平台以及一个透传 `generic` 目标的字段词汇。迁移同时转换管道语法(方言轴)和目标平台首选的字段/值词汇(SIEM 轴) — 或者通过 `logflow-sim retag` 独立转换任一轴。
| 目标平台 | 供应商 | 线路格式 | 主要分类法 |
|---|---|---|---|
| `generic` | — | 透传 | (无) |
| `splunk` | Splunk | JSON (HEC) | sourcetype |
| `elastic-ecs` | Elastic | JSON (ECS) | event.category / event.type |
| `datadog` | Datadog | JSON (Intake API) | ddsource |
| `loki` | Grafana Labs | JSON (Push API) | 低基数标签 |
| `graylog-gelf` | Graylog | GELF 1.1 | facility |
| `microsoft-sentinel` | Microsoft | JSON (DCR) | 自定义日志表 (*_CL) |
| `sumo-logic` | Sumo Logic | JSON (HTTP) | _sourceCategory |
| `chronicle-udm` | Google | UDM JSON | metadata.event_type |
| `qradar-leef` | IBM | LEEF 2.0 (管道) | LEEF EventID |
| `arcsight-cef` | OpenText | CEF 0 (管道) | CEF EventClassID |
转换通过 [OCSF](https://schema.ocsf.io) 枢纽进行 — 每个插件都映射到/来自 OCSF,而不是直接映射到其他插件,因此添加一个新的 SIEM 在映射工作上是 O(1) 复杂度。有损转换以 `SIEM_VALUE_LOSSY` 诊断形式呈现;原始值被逐字保留。
完整参考:[`content/docs/siem-targets.md`](content/docs/siem-targets.md)。
### 方言 × SIEM 覆盖矩阵
支持每一种组合:OCSF 枢纽使值重写与方言无关,渲染器由目标 SIEM 选择,而不是源方言。下面的矩阵显示了每种方言驱动每个目标时使用的**原生输出驱动程序** — 对于标记为 `→` 的单元格,方言通过通用的 HTTP/syslog 转发器发出,而不是特定于方言的插件。
| 方言 ↓ \ SIEM → | Splunk | Elastic | Datadog | Loki | Graylog | Sentinel | Sumo | Chronicle | QRadar | ArcSight |
|---|---|---|---|---|---|---|---|---|---|---|
| **rsyslog** | `omsplunkhec` | `omelasticsearch` | `omhttp`→ | `omhttp`→ | `omfwd`+GELF | `omhttp`→ | `omhttp`→ | `omhttp`→ | `omfwd`+LEEF | `omfwd`+CEF |
| **syslog-ng** | `http()`→ | `elasticsearch-http()` | `http()`→ | `http()`→ | `gelf()` | `http()`→ | `http()`→ | `http()`→ | `syslog(LEEF)` | `syslog(CEF)` |
| **Fluent Bit** | `splunk` | `es` / `elasticsearch` | `datadog` | `loki` | `gelf` | `azure_logs_ingestion` | `http`→ | `http`→ | `syslog`+LEEF | `syslog`+CEF |
| **NXLog** | `om_http`→ | `om_elasticsearch` | `om_http`→ | `om_http`→ | `om_udp`+GELF | `om_http`→ | `om_http`→ | `om_http`→ | `om_udp`+LEEF | `om_udp`+CEF |
| **Logstash** | `splunk` | `elasticsearch` | `datadog_logs` | `loki` | `gelf` | `microsoft-sentinel-logstash` | `sumologic` | `google_cloud_chronicle` | `syslog`+LEEF | `syslog`+CEF |
| **Vector** | `splunk_hec_logs` | `elasticsearch` | `datadog_logs` | `loki` | `socket`+gelf | `azure_monitor_logs` | `sumo_logic` | `gcp_chronicle_logging` | `socket`+LEEF | `socket`+CEF |
| **OTel** | `splunk_hec` | `elasticsearch` | `datadog` | `loki` | `file`→GELF | `azuremonitor` | `sumologic` | `googlecloud` | `file`→LEEF | `file`→CEF |
| **Filebeat** | `output`→ | `elasticsearch` ★ | `output`→ | `output`→ | `output`→ | `azure_logs_ingestion` | `output`→ | `output`→ | `output`→ | `output`→ |
| **Promtail** | — | — | — | `clients` ★ | — | — | — | — | — | — |
| **Fluentd** | `splunk_hec` | `elasticsearch` | `datadog` | `loki` | `gelf` | `azure_logs_ingestion` | `sumologic` | `google_cloud_chronicle` | `syslog`+LEEF | `syslog`+CEF |
★ = 规范配对(Promtail 是 Loki 代理;Filebeat 是 Elastic 的 beats 转发器)。
`→` = 通过通用 HTTP/syslog 转发器,无方言原生插件。
`+GELF`/`+LEEF`/`+CEF` = 线路负载由 logflow-sim 的专用渲染器渲染;方言只负责传输。
`—` = 该方言没有为此目标提供合理的输出(Promtail 是单一用途设计)。
```
# 独立重标签(保留流水线语法)
logflow-sim retag ./rsyslog \
--source-siem=splunk --target-siem=elastic-ecs \
--out-dir=./ecs/
# 流水线 + SIEM 一次性完成
logflow-sim convert ./rsyslog \
--target=vector --source-siem=splunk --target-siem=datadog \
--out-dir=./vector-dd/
```
## 跨方言迁移
使用您现有的 rsyslog 配置,生成一个可工作的 OpenTelemetry Collector 配置(或任何其他支持的目标)。`/migrate` 处的向导会引导您完成此过程;相同的流程也可以无头执行:
```
curl -s -X POST localhost:3000/api/convert \
-H 'content-type: application/json' \
-d '{"target":"otel"}' | jq -r .output > otel-collector.yaml
```
跨方言发出是尽力而为的 — 表达式语言构造(rsyslog 的 `lookup()`、Vector VRL、OTel OTTL)无法 1:1 转换。发出器会将每个转换注意事项都作为诊断信息呈现,迁移 UI 会突出显示它们。要验证端到端的路由一致性:
1. 将生成的配置保存到一个文件夹中,该文件夹应镜像您的配置目录结构。
2. 在差异模式下将其用作叠加层(`/diff` 或 `logflow-sim diff`)。
3. 通过两者重放一个有代表性的语料库 — 任何非零的输出差异都是您需要手动协调的路由变更。
## CLI
`logflow-sim` CLI 是 Action 背后的引擎,同样适用于本地 pre-commit hook 或任何 CI 运行器。
```
logflow-sim parse # parse + validator (silent drops, dead code, undef refs)
logflow-sim test # parse + run conf/tests/*.json
logflow-sim simulate --input=msg.json # one message, JSON trace
logflow-sim replay --lines=corpus.log # batch, aggregate verdict
logflow-sim replay --pcap=capture.pcap # accepts pcap classic and pcapng
logflow-sim convert --target=otel --out-dir=./out # whole-tree migration + lookup sidecars
[--source-siem=splunk] # also retag destination vocabulary
[--target-siem=elastic-ecs]
logflow-sim retag --target-siem=elastic-ecs # destination retag only (keep pipeline dialect)
--out-dir=./out [--source-siem=…]
logflow-sim diff --overlay-dir=pr-conf/ \
--lines=corpus.log \
--max-route-change-pct=5 # exit 1 if PCT exceeded
```
输出格式:`--format=human`(默认),`--format=github`(用于 Action 的注释),`--format=json`(机器可读,可管道传输到 jq)。
## 静态验证器
`logflow-sim parse`(以及 `/api/config/parse`)对解析后的 IR 运行静态分析器。它可以捕获那些在语法检查中不会显示的路由错误:
- **静默丢弃路径**:规则集的最后一条语句是不带 `else` 的 `if`,或者以 `set/unset/reset` 结束 — 在 fall-through 路径上的消息不会产生任何输出,并被静默丢弃。
- **死代码**:定义了但从未从任何输入到达的规则集、查找表、模板。
- **未定义的引用**:`call rulename`、`lookup("table", ...)`、`template="x"` 引用了不存在的名称。
- **冲突的输出**:同一目标被多个无条件操作写入。
- **缺失的查找文件**:`lookup_table(...)` 引用了磁盘上不存在的 JSON 文件。
每个发现都包含源位置和人类可读的解释,例如:
可以通过 `--fail-on=warnings` 在 CI 门控中触发这些错误。
## 实时配置预览("/config" + 方言选择器)
配置页面的方言选择器不仅仅是解析覆盖。当您将其切换到非源方言时,文件树和查看器会切换到即时转换的预览 — `rsyslog.conf` 变成了 `otel-collector.yaml`,所有引用的查找表都以 OTel 的 transform/OTTL 风格发出(或 Vector 的 enrichment_tables + CSV 附属文件等)。将选择器切换回 `auto` 以返回磁盘上的源文件。这与驱动 `/api/convert` 和 `logflow-sim convert` 的是同一个引擎。
## 重放与差异
模拟器可以通过您的配置运行一批真实的消息:
- **重放** — 接受 `/var/log/messages` 风格的逐行转储**或**线路捕获(libpcap classic + pcapng + LINUX_SLL,UDP + 重组的 TCP 用于 RFC 6587 八位字节计数和非透明帧)。返回聚合报告:按规则集、按输出目标、顶级程序/主机名,以及用于不匹配/静默丢弃/出错消息的深入分析样本。
- **差异** — 通过您的实时配置和一个叠加变体重放同一批消息,获取按输出和按规则集的差异,以及对于每个路由发生变化的消息的并排基线与叠加输出。支持多文件叠加。
尝试针对真实语料库运行:
```
# 从 Loghub 研究数据集中获取 25k 条真实 /var/log/messages 日志行
curl -sL https://zenodo.org/records/8196385/files/Linux.tar.gz | tar -xz
# 通过捆绑的演示配置重放它们
./scripts/replay-loghub.sh
```
## 检测影响
通过您的实时配置将 Sigma 检测规则运行在重放语料库上 — 可选地与提议的更改进行差异比较 — 以查看在合并之前路由更改是否会降低 SOC 可见性:
```
curl -s -X POST localhost:3000/api/detection/impact \
-H 'content-type: application/json' \
-d '{ "rules": [...sigma rules...], "lines": "..." }' | jq .summary
```
返回每个规则的命中次数,以及(在差异变体中)叠加配置下哪些规则获得或丢失了覆盖。完整文章:
[这次路由更改会破坏您的 SIEM 吗?](https://netverdict.io/logflow/blog/2026-05-17-detection-impact-before-you-merge)。
## 项目与本地模式
[`/projects`](http://localhost:3000/projects) 页面允许您完全在客户端加载配置 — 克隆实时服务器配置、上传文件夹、拖放单个文件,或拖放 `.zip`(页面任何位置均支持拖放)。加载后,UI 进入**本地模式**,所有解析/模拟/搜索/验证都在 Web Worker 中运行。项目文件不会离开浏览器。保存的项目在 `localStorage` 中持久化,可以随时重命名、导出回 ZIP 或删除。
## MCP 服务器(从 LLM 使用 logflow-sim)
附带一个 [Model Context Protocol](https://modelcontextprotocol.io) 服务器 (`logflow-sim-mcp`),该服务器将内核暴露为 LLM 可以调用的工具:`logflow_parse`、`logflow_simulate`、`logflow_replay`、`logflow_diff`、`logflow_convert`、`logflow_retag`、`logflow_detect`、`logflow_validate`。
Stdio JSON-RPC 2.0 传输 — 注册到 Claude Desktop 或任何支持 MCP 的客户端。详情见 [`content/docs/mcp.md`](content/docs/mcp.md)。
## 国际化
UI 提供 13 种语言:英语、德语、法语、西班牙语、葡萄牙语、意大利语、日语、中文、韩语、俄语、印地语、土耳其语、越南语。选择器位于顶部栏。工具/方言名称保持英文,以便 UI 词汇与您正在分析的配置相匹配。目录位于 [`src/ui/i18n/locales/`](src/ui/i18n/locales/) — 欢迎提交单文件 PR。
## 快速开始
```
docker compose up --build
```
打开 。将您自己的配置挂载到 `./conf/`,或者通过将 compose 卷指向 `./conf-demo/` 来运行捆绑的演示。
### 不使用 Docker
```
npm install
npm run dev
```
API 运行在 `:3000`,Vite UI 开发服务器运行在 `:5173` 并带有 HMR。在生产环境(`npm run build && npm start`)中,服务器从 `dist/ui` 提供构建好的 UI。
## 文件夹布局
```
src/
├── core/ pure TS — no Node deps
│ ├── vfs.ts virtual filesystem interface
│ ├── source-map.ts file/line/col tracking
│ ├── diagnostics.ts severity-tagged error reporting
│ ├── ir/ normalized intermediate representation (vendor-neutral)
│ ├── simulate/ evaluator, expressions, templates
│ ├── lookups/ parse-table + lookup query
│ └── dialects/
│ ├── types.ts the Dialect plugin contract
│ └── rsyslog/ RainerScript parser + AST + IR mapping
├── vfs/node.ts NodeVFS — fs + fast-glob adapter
├── config/ Node-side loaders (use VFS)
├── lookups/loader.ts Node-side lookup loader (uses VFS + core)
├── api/ Express routes
├── content/ blog + docs markdown loader
├── server.ts Express bootstrap
└── ui/ Preact SPA
conf-demo/ bundled demo configuration (tracked in git)
conf/ your own configs (gitignored — mount your dir here)
content/posts/, content/docs/ markdown for blog + docs pages
test/ vitest suites
```
## API 示例
```
# 存活检测
curl -s localhost:3000/api/health
# 解析摘要 + 诊断
curl -s localhost:3000/api/config/parse | jq .
# 模拟一条防火墙消息命中 :6514/UDP
curl -s -XPOST localhost:3000/api/simulate \
-H 'content-type: application/json' \
-d '{
"transport": "udp", "port": 6514,
"fromhost": "fw01", "hostname": "fw01",
"programname": "firewall",
"msg": "TRAFFIC deny tcp 10.0.0.1 -> 8.8.8.8:53"
}' | jq .
# 跨加载的配置进行多文件 grep
curl -s 'localhost:3000/api/config/search?q=10.254.0.20'
curl -s -G --data-urlencode 'q=10\.252\.\d+\.\d+' --data 'regex=1' \
'localhost:3000/api/config/search'
# 运行 conf/tests 下的所有测试用例
curl -s -XPOST localhost:3000/api/tests/run -d '{}' \
-H 'content-type: application/json' | jq '.passed,.total'
```
## 已知限制
这是一个**解释器**,而不是重新实现。完整列表请参见 [`content/docs/limitations.md`](content/docs/limitations.md)。
简而言之:
- 无队列运行时,无实际文件/网络 I/O。
- 查找表:仅支持 JSON(普通对象、对象数组、rsyslog 原生格式)。
- 模板:支持完整的 `%property%` 替换及修饰符(小写、大写、子字符串、正则表达式提取、日期组件) — 但尚未支持晦涩的 rsyslog 属性替换器标志。
- 未知语句**永远不会被静默跳过** — 它们被保留为带有警告诊断的 `Unknown` IR 节点。
## 测试
```
npm test
```
覆盖了词法分析器、解析器、include 解析、RFC 3164 / 5424 rawmsg 解码、查找表加载(所有三种格式),以及端到端的模拟器行为(输入选择、`$DefaultRuleset` 回退、if/elif/else、set/reset/unset、带 `nomatch` 的查找命中/未命中、`stop`、DynaFile 模板解析、omfwd target/port/protocol、数组 RHS `startswith_i`、`call` 跨规则集、正则表达式提取、`exec_template`、`tolower`/`toupper`、`&` 连接、数值比较、`continue`)。
### 语料库回归套件
`test/corpus/` 包含 20 多个真实的 rsyslog 配置,这些配置是逐字从公共来源获取的(Debian / Fedora / Alpine / Gentoo 发行版默认配置以及来自大型开源项目的配置 — 请参见 [`SOURCES.md`](test/corpus/SOURCES.md))。
语料库测试解析每个配置,并断言其诊断计数和 IR 摘要与 `test/corpus/baseline.json` 中记录的基线匹配。任何偏差都是回归。
从上游刷新语料库:
```
./scripts/fetch-corpus.sh
git diff test/corpus/ # what changed upstream
```
在有意更改解析器导致计数变化后,重新生成基线:
```
UPDATE_CORPUS_BASELINE=1 npm test -- corpus
```
## 许可证
MIT。
标签:API集成, Filebeat, Fluent Bit, Fluentd, GitHub Actions, GNU通用公共许可证, Logstash, MITM代理, Node.js, NXLog, OISF, OpenTelemetry Collector, Promtail, PR验证, rsyslog, Sigma规则, syslog-ng, TypeScript, URL发现, Vector, 中间表示, 可观测性, 安全插件, 安全检测, 日志处理工具, 日志管理, 日志管道模拟, 步骤跟踪, 流量模拟, 目标导入, 管道配置验证, 自动化攻击, 自动笔记, 请求拦截, 路由差异, 配置解析, 错误检测