1
0
Files
DiAL/README.md

632 lines
28 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<h1 align="center">DiAL</h1>
<p align="center">
<strong>轻量级多类型拨测监控工具</strong>
</p>
<p align="center">
基于 Bun + TypeScript 构建 · YAML 配置驱动 · 内置 Dashboard
</p>
---
DiAL 是一个自托管的拨测监控工具,支持 **HTTP**、**命令行**、**数据库**、**TCP**、**UDP**、**ICMP** 和 **LLM** 多种拨测类型。通过 YAML 配置文件定义拨测目标,后端定时并发执行拨测并将结果持久化到本地 SQLite前端 Dashboard 展示各目标的实时状态、可用率和耗时趋势。
**功能亮点:**
- 多种拨测类型HTTPGET/POST/PUT 等、Cmd命令行执行、DBPostgreSQL/MySQL/SQLite、TCP端口可达性 + Banner 探测、UDP自定义 payload 请求-响应、ICMP存活检测、延迟、丢包率、LLM大模型服务应用层健康检查
- 丰富的校验规则状态码、响应头、JSONPath、CSS 选择器、XPath、正则匹配、数值比较等
- 结构化观测数据:检查结果保留按需读取的 HTTP body 预览、TCP/UDP 响应摘要、ICMP 丢包率、CMD 输出预览、LLM token 用量等 observation便于排障和后续分析
- 响应式 Dashboard实时状态、可用率统计、动态粒度趋势图avg/P95 + 状态条)、手动/自动刷新、版本号展示
- 多主题支持:系统、明亮、黑暗三种主题模式
- 零外部依赖:数据存储使用 SQLite无需额外数据库服务
## 版本管理
DiAL 使用 `package.json.version` 作为唯一版本源Dashboard Header 展示当前运行实例版本号(如 `v0.1.0`)。
**版本升迁命令:**
```bash
bun run version:patch # 升迁 patch 版本0.1.0 -> 0.1.1
bun run version:minor # 升迁 minor 版本0.1.0 -> 0.2.0
bun run version:major # 升迁 major 版本0.1.0 -> 1.0.0
bun run version:set 0.2.0 # 显式设置版本
```
版本升迁仅更新 `package.json`,不自动创建 git commit、tag 或 changelog。
## 应用截图
| | 亮色 | 暗色 |
| ------ | --------------------------------------------------- | ------------------------------------------------- |
| 主页 | ![index-light](assets/screenshot/light_index.png) | ![index-dark](assets/screenshot/dark_index.png) |
| 详情页 | ![detail-light](assets/screenshot/light_detail.png) | ![detail-dark](assets/screenshot/dark_detail.png) |
## 快速开始
**前置条件:** [Bun](https://bun.sh/) >= 1.0
ICMP checker 依赖系统 `ping` 命令。精简容器镜像需额外安装,例如 Alpine 可安装 `iputils-ping`
```bash
# 克隆仓库
git clone https://github.com/your-org/DiAL.git
cd DiAL
# 安装依赖
bun install
# 复制示例配置并按需修改
cp probes.example.yaml probes.yaml
# 启动开发服务器
bun run dev probes.yaml
```
`bun run dev` 会同时启动 Vite 开发服务器(`http://127.0.0.1:5173`)和 API 服务器(`http://127.0.0.1:3000`),访问前端地址即可使用 Dashboard。
## 生产部署
```bash
# 构建
bun run build
# 运行
./dist/dial-server ./probes.yaml
```
构建产物为独立可执行文件,只需一个 YAML 配置文件即可运行。
### Docker 部署
DiAL 提供基于 Alpine 的多阶段镜像。构建阶段使用 Bun 生成 musl 目标单可执行文件,运行阶段只包含 `dial-server`、基础证书、`ping`、musl executable 必需运行库、时区数据和容器运行所需目录。
```bash
# 构建当前架构镜像
docker build -t dial:alpine .
# 运行容器,使用内置容器配置示例
docker run --rm -p 3000:3000 -v dial-data:/data/dial dial:alpine
# 使用自定义配置文件
docker run --rm -p 3000:3000 \
-v "$PWD/docker/probes.yaml:/etc/dial/probes.yaml:ro" \
-v dial-data:/data/dial \
dial:alpine
```
容器默认读取 `/etc/dial/probes.yaml`,推荐将数据卷挂载到 `/data/dial`。容器专用示例配置位于 [`docker/probes.yaml`](docker/probes.yaml),默认监听 `0.0.0.0:3000`,并将 SQLite 数据和日志写入 `/data/dial`
多架构镜像可通过 Docker Buildx 构建:
```bash
docker buildx build --platform linux/amd64,linux/arm64 -t dial:alpine .
```
如需在容器中运行 ICMP checker除镜像内置的 `iputils-ping` 外,还需要授予 `NET_RAW` capability
```bash
docker run --rm --cap-add=NET_RAW -p 3000:3000 -v dial-data:/data/dial dial:alpine
```
官方镜像不内置 `bun``node``curl``dig``psql``mysql``redis-cli` 等 CMD checker 可能需要的额外命令。需要这些命令时请使用派生镜像自行安装:
```dockerfile
FROM dial:alpine
USER root
RUN apk add --no-cache curl bind-tools postgresql-client
USER dial
```
### 跨平台发布打包
```bash
# 编译全部 7 个目标平台
bun run release
# 编译指定平台
bun run release --target linux-x64
bun run release --target linux-x64,windows-x64,darwin-arm64
```
支持的目标平台:`linux-x64``linux-arm64``linux-x64-musl``linux-arm64-musl``windows-x64``darwin-x64``darwin-arm64`
**产出物结构:**
```
dist/release/
├── binaries/ ← 裸二进制(带版本号和平台标识)
│ ├── dial-server-0.1.0-linux-x64
│ ├── dial-server-0.1.0-windows-x64.exe
│ └── ...
└── packages/ ← tar.gz 压缩包 + SHA256 校验和
├── dial-server_0.1.0_linux_x64.tar.gz
├── dial-server_0.1.0_linux_x64.tar.gz.sha256
└── ...
```
压缩包内含可执行文件、`probes.example.yaml``LICENSE`,解压后可直接使用。
## 配置文件
程序通过 YAML 配置文件定义所有运行参数,完整示例参见 [`probes.example.yaml`](probes.example.yaml)。
### 配置文件结构
```yaml
# yaml-language-server: $schema=./probe-config.schema.json
server: # 服务配置(均可省略)
listen:
host: "127.0.0.1"
port: "${server_port}"
storage:
dataDir: "/tmp/probes_data"
retention: "${retention}"
logging:
level: "${log_level|info}"
file:
path: "<dataDir>/logs/dial.log"
probes: # 拨测运行时配置(可省略)
execution:
maxConcurrentChecks: "${max_checks}"
variables: # 配置变量(可省略)
env_name: "生产"
base_url: "https://api.example.com"
server_port: 3000
retention: "7d"
max_checks: 20
default_interval: "30s" # 通过变量在多个 target 间共享常用值
default_timeout: "10s"
targets: # 拨测目标列表(必填)
- id: "baidu-home"
name: "Baidu"
type: http
http:
url: "https://www.baidu.com"
expect:
# ...
- id: "my-cmd"
name: "脚本检查"
type: cmd
cmd:
# ...
expect:
# ...
# ... 更多 targets
```
### server.listen — 监听配置
| 字段 | 说明 | 必填 | 默认值 |
| ------ | -------- | ---- | ----------- |
| `host` | 监听地址 | 否 | `127.0.0.1` |
| `port` | 监听端口 | 否 | `3000` |
### server.storage — 存储配置
| 字段 | 说明 | 必填 | 默认值 |
| ----------- | ------------------------------------------------ | ---- | -------- |
| `dataDir` | 数据目录,相对路径基于配置文件所在目录解析 | 否 | `./data` |
| `retention` | 历史数据保留时长,支持 `ms`/`s`/`m`/`h`/`d` 单位 | 否 | `7d` |
### probes.execution — 拨测运行时配置
| 字段 | 说明 | 必填 | 默认值 |
| --------------------- | -------------- | ---- | ------ |
| `maxConcurrentChecks` | 最大并发拨测数 | 否 | `20` |
### server.logging — 日志配置
| 字段 | 说明 | 必填 | 默认值 |
| ---------------------------------------- | ---------------------------------------------- | ---- | ------------------------- |
| `server.logging.level` | 全局日志等级console 和 file 未指定时继承此值 | 否 | `info` |
| `server.logging.console.level` | 控制台日志等级 | 否 | 继承 `level` |
| `server.logging.file.level` | 文件日志等级 | 否 | 继承 `level` |
| `server.logging.file.path` | 日志文件路径,相对路径基于配置文件目录解析 | 否 | `<dataDir>/logs/dial.log` |
| `server.logging.file.rotation.size` | 按大小滚动,支持 `KB`/`MB`/`GB` 单位 | 否 | `50MB` |
| `server.logging.file.rotation.frequency` | 按时间滚动:`hourly``daily``weekly` | 否 | `daily` |
| `server.logging.file.rotation.maxFiles` | 保留的归档文件数量(不含活跃日志) | 否 | `14` |
日志等级支持:`trace``debug``info``warn``error``fatal`
控制台始终输出pretty 格式),文件始终输出 JSONL 格式并支持滚动。`rotation.size``rotation.frequency` 任一条件触发即滚动。
### 内置默认值
未显式配置时,系统使用以下内置默认值:
- `interval``30s`(拨测间隔)
- `timeout``10s`(超时时间)
- 各 checker 专属默认值见对应章节
如需在配置文件中共享相同的配置值,可使用 `variables` 定义变量,然后在 `server``probes``targets` 中通过 `${var}` 引用。例如在 `variables` 中定义 `default_interval: "30s"`,在多个 target 的 `interval` 字段写 `${default_interval}`
### variables — 配置变量
`variables` 是顶层动态键值表key 必须符合 `[a-zA-Z_][a-zA-Z0-9_]*`value 仅支持 string、number、boolean。`server``probes``targets` 中的字符串值可引用变量:
- `${key}`:引用 variables 或环境变量
- `${key|default}`:变量和环境变量都不存在时使用默认值,第一个 `|` 后的内容为默认值
- `${key|}`:变量和环境变量都不存在时使用空字符串作为默认值
- `$${key}`:转义输出字面量 `${key}`
解析优先级为 `variables -> process.env -> 默认值`,三者均不存在时配置校验失败。字段值完整等于单个变量引用时会保留 number/boolean/string 类型,环境变量和默认值会做类型推断,但空字符串保持为字符串;部分拼接时统一转为字符串。变量替换作用于 `server``probes``targets`,不作用于 `variables` 段自身,且不会替换 `targets[].id``targets[].type` 字段;对象 key 不参与替换。
配置加载内部区分三层形态:用户 YAML 属于 Authoring Config允许变量引用和 expect 简写;`normalizeAuthoringConfig()` 会在启动时完成变量替换、expect primitive/keyed/content 简写展开并移除 `variables` 段,生成 Normalized Configchecker 的 `resolve()` 只在 ResolvedConfig 阶段补默认值并解析 duration、size、路径和运行期环境。根目录 `probe-config.schema.json` 面向 Authoring Config因此 VSCode 校验会接受 `server.listen.port: "${server_port|3000}"``http.maxRedirects: "${MAX|5}"``expect.durationMs: 5000` 这类写法。
### targets — 拨测目标列表(必填)
每个 target 的通用字段:
| 字段 | 说明 | 必填 | 默认值 |
| ------------- | ------------------------------------------------------------------------------------ | ---- | --------- |
| `id` | 目标唯一标识,最长 30 字符,支持字母数字、下划线、连字符,不参与变量替换 | 是 | |
| `name` | 展示名称,最长 30 字符,支持变量替换,可省略或显式 null前端展示时 null 回退到 `id` | 否 | |
| `description` | 目标描述,最长 500 字符,支持变量替换,可省略或显式 null允许空字符串 | 否 | |
| `type` | 目标类型:`http``cmd``db``tcp``udp``icmp``llm` | 是 | |
| `group` | 分组名称 | 否 | `default` |
| `interval` | 拨测间隔,未配置时使用内置默认值 `30s` | 否 | `30s` |
| `timeout` | 超时时间,未配置时使用内置默认值 `10s` | 否 | `10s` |
---
### HTTP Checker`type: http`
**配置项**
| 字段 | 说明 | 必填 | 默认值 |
| ------------------- | ------------------- | ---- | ------- |
| `http.url` | 目标 URL | 是 | |
| `http.method` | HTTP 方法 | 否 | `GET` |
| `http.headers` | 请求头 | 否 | |
| `http.body` | 请求体 | 否 | |
| `http.ignoreSSL` | 忽略 HTTPS 证书校验 | 否 | `false` |
| `http.maxRedirects` | 最大重定向跟随次数 | 否 | `0` |
**expect 校验项**
| 字段 | 说明 | 必填 | 默认值 |
| ------------ | -------------------------------------------------- | ---- | ------- |
| `status` | 可接受的状态码列表,支持精确码和范围(如 `"2xx"` | 否 | `[200]` |
| `headers` | 响应头校验,使用动态键名和 `KeyedExpectations` | 否 | |
| `body` | 响应体校验,使用 `ContentExpectations` 数组 | 否 | |
| `durationMs` | 完整执行耗时校验,使用 `ValueMatcher` | 否 | |
**配置示例**
```yaml
- id: "json-api"
name: "JSON API 示例"
type: http
http:
url: "https://httpbin.org/json"
headers:
Authorization: "Bearer token"
expect:
status: [200]
headers:
Content-Type:
contains: "application/json"
body:
- json:
path: "$.slideshow.title"
equals: "Sample Slide Show"
durationMs:
lte: 10000
```
---
### Cmd Checker`type: cmd`
**配置项**
| 字段 | 说明 | 必填 | 默认值 |
| ---------- | -------------------------------------- | ---- | ------ |
| `cmd.exec` | 可执行文件名或路径 | 是 | |
| `cmd.args` | 命令行参数列表 | 否 | `[]` |
| `cmd.env` | 环境变量覆盖(继承进程环境变量并合并) | 否 | |
| `cmd.cwd` | 工作目录(相对于配置文件所在目录) | 否 | |
**expect 校验项**
| 字段 | 说明 | 必填 | 默认值 |
| ------------ | --------------------------------------------- | ---- | ------ |
| `exitCode` | 可接受的退出码列表 | 否 | `[0]` |
| `stdout` | 标准输出校验,使用 `ContentExpectations` 数组 | 否 | |
| `stderr` | 标准错误校验,使用 `ContentExpectations` 数组 | 否 | |
| `durationMs` | 完整执行耗时校验,使用 `ValueMatcher` | 否 | |
**配置示例**
```yaml
- id: "bun-script"
name: "Bun 脚本检查"
type: cmd
cmd:
exec: "bun"
args: ["-e", "console.log('ok')"]
expect:
exitCode: [0]
stdout:
- contains: "ok"
```
---
### DB Checker`type: db`
**配置项**
| 字段 | 说明 | 必填 | 默认值 |
| ---------- | ------------------------------------------------------------- | ---- | ------ |
| `db.url` | 数据库连接字符串,支持 `postgres://``mysql://``sqlite://` | 是 | |
| `db.query` | SQL 查询语句,不配置时仅测试连接 | 否 | |
**expect 校验项**
| 字段 | 说明 | 必填 | 默认值 |
| ------------ | ----------------------------------------------------------------------- | ---- | ------ |
| `rowCount` | 查询返回行数校验,使用 `ValueMatcher` | 否 | |
| `rows` | 查询结果逐行校验,数组内每行为列名到 `KeyedExpectations` 的映射 | 否 | |
| `result` | 完整查询结果 `{ rows, rowCount }` 校验,使用 `ContentExpectations` 数组 | 否 | |
| `durationMs` | 完整执行耗时校验,使用 `ValueMatcher` | 否 | |
**配置示例**
```yaml
- id: "sqlite-query"
name: "SQLite 数据库检查"
type: db
db:
url: "sqlite:///path/to/db.sqlite"
query: "SELECT COUNT(*) as cnt FROM users WHERE status = 'active'"
expect:
durationMs:
lte: 5000
rowCount: { gte: 1 }
rows:
- cnt: { gte: 0 }
```
---
### TCP Checker`type: tcp`
**配置项**
| 字段 | 说明 | 必填 | 默认值 |
| ----------------------- | ------------------------------------------- | ---- | ------- |
| `tcp.host` | 目标主机地址 | 是 | |
| `tcp.port` | 目标端口1-65535 | 是 | |
| `tcp.readBanner` | 是否读取服务端 banner | 否 | `false` |
| `tcp.bannerReadTimeout` | banner 读取超时(毫秒) | 否 | `2000` |
| `tcp.maxBannerBytes` | banner 最大字节数,支持 `KB`/`MB`/`GB` 单位 | 否 | `4KB` |
**expect 校验项**
| 字段 | 说明 | 必填 | 默认值 |
| ------------ | ------------------------------------------------------------------------- | ---- | ------ |
| `connected` | 期望连接结果,`true` 可达或 `false` 期望不可达 | 否 | `true` |
| `banner` | Banner 内容校验,使用 `ContentExpectations` 数组,需开启 `tcp.readBanner` | 否 | |
| `durationMs` | 完整执行耗时校验,使用 `ValueMatcher` | 否 | |
**配置示例**
```yaml
- id: "redis-port"
name: "Redis 端口可达"
type: tcp
tcp:
host: "127.0.0.1"
port: 6379
expect:
durationMs:
lte: 3000
```
---
### UDP Checker`type: udp`
**配置项**
| 字段 | 说明 | 必填 | 默认值 |
| ---------------------- | ---------------------------------------- | ---- | ------ |
| `udp.host` | 目标主机地址 | 是 | |
| `udp.port` | 目标端口1-65535 | 是 | |
| `udp.payload` | 发送数据 | 否 | `""` |
| `udp.encoding` | payload 编码:`text``hex``base64` | 否 | `text` |
| `udp.responseEncoding` | 响应解码:`text``hex``base64` | 否 | `text` |
| `udp.maxResponseBytes` | 响应最大字节数,支持 `KB`/`MB`/`GB` 单位 | 否 | `4KB` |
**expect 校验项**
| 字段 | 说明 | 必填 | 默认值 |
| -------------- | --------------------------------------------- | ---- | ------ |
| `responded` | 期望是否收到响应 | 否 | `true` |
| `response` | 响应内容校验,使用 `ContentExpectations` 数组 | 否 | |
| `responseSize` | 响应字节数校验,使用 `ValueMatcher` | 否 | |
| `sourceHost` | 响应来源地址校验,使用 `ValueMatcher` | 否 | |
| `sourcePort` | 响应来源端口校验,使用 `ValueMatcher` | 否 | |
| `durationMs` | 完整执行耗时校验,使用 `ValueMatcher` | 否 | |
**配置示例**
```yaml
- id: "udp-heartbeat"
name: "UDP 心跳检测"
type: udp
udp:
host: "127.0.0.1"
port: 9000
payload: "PING"
expect:
responded: true
response:
- contains: "PONG"
durationMs:
lte: 100
```
---
### ICMP Checker`type: icmp`
**配置项**
| 字段 | 说明 | 必填 | 默认值 |
| ----------------- | ------------------------- | ---- | ------ |
| `icmp.host` | 目标主机地址 | 是 | |
| `icmp.count` | ICMP 包数量,范围 `1-100` | 否 | `3` |
| `icmp.packetSize` | ICMP 包大小bytes | 否 | `56` |
ICMP checker 通过系统 `ping` 命令执行 ICMP 探测,支持 Linux、macOS 和 Windows 输出解析。
**expect 校验项**
| 字段 | 说明 | 必填 | 默认值 |
| ------------------- | --------------------------------------------------- | ---- | ------ |
| `alive` | 期望主机可达性 | 否 | `true` |
| `packetLossPercent` | 丢包率百分比校验,范围 `0-100`,使用 `ValueMatcher` | 否 | |
| `avgLatencyMs` | 平均延迟校验,使用 `ValueMatcher` | 否 | |
| `maxLatencyMs` | 最大单次延迟校验,使用 `ValueMatcher` | 否 | |
| `durationMs` | 完整执行耗时校验,使用 `ValueMatcher` | 否 | |
**配置示例**
```yaml
- id: "gateway-icmp"
name: "网关 ICMP 可达"
type: icmp
icmp:
host: "10.0.0.1"
count: 3
packetSize: 56
expect:
alive: true
packetLossPercent:
lte: 10
avgLatencyMs:
lte: 100
maxLatencyMs:
lte: 300
durationMs:
lte: 5000
```
---
### LLM Checker`type: llm`
**配置项**
| 字段 | 说明 | 必填 | 默认值 |
| --------------------- | ------------------------------------------------------ | ---- | ------- |
| `llm.provider` | 模型提供方:`openai``openai-responses``anthropic` | 是 | |
| `llm.url` | API base URL | 是 | |
| `llm.model` | 模型名称 | 是 | |
| `llm.prompt` | 单轮 prompt | 是 | |
| `llm.mode` | 调用模式:`http`(非流式)或 `stream`(流式) | 否 | `http` |
| `llm.key` | API key支持 `${VAR}` 变量替换 | 否 | `""` |
| `llm.authToken` | Bearer token`anthropic` provider`key` 互斥) | 否 | |
| `llm.headers` | 附加请求头 | 否 | |
| `llm.ignoreSSL` | 忽略 HTTPS 证书校验 | 否 | `false` |
| `llm.options` | 生成选项 | 否 | |
| `llm.providerOptions` | Provider 专属选项 | 否 | |
`llm.options` 支持 `maxOutputTokens`(默认 `16`)、`temperature`(默认 `0`)、`topP``topK``presencePenalty``frequencyPenalty``stopSequences``seed`
**expect 校验项**
| 字段 | 说明 | 必填 | 默认值 |
| ----------------- | ---------------------------------------------------------------------- | ---- | ------- |
| `status` | 可接受的状态码列表,支持精确码和范围(如 `"2xx"` | 否 | `[200]` |
| `headers` | 响应头校验,使用动态键名和 `KeyedExpectations` | 否 | |
| `output` | 模型输出校验,使用 `ContentExpectations` 数组 | 否 | |
| `finishReason` | finish reason 校验,使用 `ValueMatcher` | 否 | |
| `rawFinishReason` | 原始 finish reason 校验,使用 `ValueMatcher` | 否 | |
| `usage` | Token usage 校验(`inputTokens`/`outputTokens`/`totalTokens` matcher | 否 | |
| `stream` | 流式断言(`completed``firstTokenMs` matcher`mode: stream` | 否 | |
| `durationMs` | 完整执行耗时校验,使用 `ValueMatcher` | 否 | |
**配置示例**
```yaml
- id: "llm-openai-probe"
name: "OpenAI 健康检查"
type: llm
llm:
provider: openai
url: "https://api.openai.com/v1"
model: "gpt-4o-mini"
prompt: "Say OK"
key: "${OPENAI_API_KEY}"
expect:
status: [200]
finishReason: "stop"
output:
- contains: "OK"
```
---
### 通用校验规则
#### ContentExpectations 校验项
`body``stdout``stderr``banner``response``output``result` 均使用数组:
- `contains` — 响应体包含指定文本
- `regex` — 正则匹配(启动期会拒绝存在 ReDoS 风险的模式)
- `json` — JSONPath 提取值比较(`path` 必填,如 `$.slideshow.title`
- `css` — CSS 选择器提取 HTML 元素(`selector` 必填,`attr` 可选提取属性)
- `xpath` — XPath 提取 XML/HTML 节点(`path` 必填,如 `/html/body/h1/text()`
#### ValueMatcher
`equals``contains``regex``empty``exists``gte``lte``gt``lt``equals` 支持 JSON 深度相等;`regex` 固定使用无 flags 正则;提取器未配置 matcher 时等价于 `exists: true`。ValueMatcher expect 字段也可直接写 string、number、boolean 或 null等价于 `{ equals: value }`;数组和对象必须显式写成 `{ equals: ... }`
#### KeyedExpectations
`headers``rows` 中每行使用的校验结构,支持 ValueMatcher 的全部字段。
### 补充说明
- **大小说明**`maxBodyBytes``maxOutputBytes``maxResponseBytes``maxBannerBytes` 支持 `KB``MB``GB` 单位,也可直接使用数字
- **时长格式**`500ms``30s``5m``2h``7d`
- **JSON Schema**:仓库根目录导出 `probe-config.schema.json`,在 YAML 文件顶部添加 `# yaml-language-server: $schema=./probe-config.schema.json` 即可在编辑器中获得提示和校验
- **旧字段移除**`maxDurationMs``maxPacketLoss``maxAvgLatencyMs``maxMaxLatencyMs` 和旧正则字段 `match` 已移除,请分别改用 `durationMs`、ICMP matcher 字段和 `regex`
> **注意:** 配置校验在启动时执行,非法配置会阻止启动并输出错误信息。除动态键值表(`headers`、`env`、`variables`)外,未知字段会导致启动失败,请使用 YAML 注释。
## 目标状态判定
采用单层判定模型:
- **UP** = 拨测结果符合 expect 规则
- **DOWN** = 拨测结果不符合 expect 规则
执行失败(网络错误、超时、进程崩溃)和 expect 不匹配都统一为 DOWN通过 `failure.kind` 区分原因(`"error"` vs `"mismatch"`)。
API 返回的检查结果包含 `detail``observation``detail` 是后端按 checker 类型从结构化 observation 动态生成的人可读摘要,`observation` 保存该次检查的结构化观测数据。`detail` 不写入 SQLite存储层仅持久化 `observation` JSON、`failure` JSON、匹配状态、耗时和时间戳。
## 开发
```bash
bun run check # schema:check + typecheck + lint + test
bun run verify # check + build
```
开发相关文档(项目结构、构建、测试、代码规范等)请参阅 [DEVELOPMENT.md](DEVELOPMENT.md)。
## License
Apache-2.0