- 移除 DefaultsConfig 类型、ProbeConfig.defaults 字段 - 移除 CheckerSchemas.defaults、ResolveContext.defaults、CheckerValidationInput.defaults - 更新所有 checker schema/resolve/validate 删除 defaults 合并逻辑 - 更新 config-loader 不再读取传递 defaults - 更新测试、README、DEVELOPMENT、probes.example.yaml - 重新生成 probe-config.schema.json(不含 defaults) - 同步 delta specs 到主规范 - 归档 openspec change
25 KiB
DiAL
轻量级多类型拨测监控工具
基于 Bun + TypeScript 构建 · YAML 配置驱动 · 内置 Dashboard
DiAL 是一个自托管的拨测监控工具,支持 HTTP、命令行、数据库、TCP、UDP、ICMP 和 LLM 多种拨测类型。通过 YAML 配置文件定义拨测目标,后端定时并发执行拨测并将结果持久化到本地 SQLite,前端 Dashboard 展示各目标的实时状态、可用率和耗时趋势。
功能亮点:
- 多种拨测类型:HTTP(GET/POST/PUT 等)、Cmd(命令行执行)、DB(PostgreSQL/MySQL/SQLite)、TCP(端口可达性 + Banner 探测)、UDP(自定义 payload 请求-响应)、ICMP(存活检测、延迟、丢包率)、LLM(大模型服务应用层健康检查)
- 丰富的校验规则:状态码、响应头、JSONPath、CSS 选择器、XPath、正则匹配、数值比较等
- 结构化观测数据:检查结果保留按需读取的 HTTP body 预览、TCP/UDP 响应摘要、ICMP 丢包率、CMD 输出预览、LLM token 用量等 observation,便于排障和后续分析
- 响应式 Dashboard:实时状态、可用率统计、耗时趋势图、手动/自动刷新、版本号展示
- 多主题支持:系统、明亮、黑暗三种主题模式
- 零外部依赖:数据存储使用 SQLite,无需额外数据库服务
版本管理
DiAL 使用 package.json.version 作为唯一版本源,Dashboard Header 展示当前运行实例版本号(如 v0.1.0)。
版本升迁命令:
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。
应用截图
| 亮色 | 暗色 | |
|---|---|---|
| 主页 | ![]() |
![]() |
| 详情页 | ![]() |
![]() |
快速开始
前置条件: Bun >= 1.0
ICMP checker 依赖系统 ping 命令。精简容器镜像需额外安装,例如 Alpine 可安装 iputils-ping。
# 克隆仓库
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。
生产部署
# 构建
bun run build
# 运行
./dist/dial-server ./probes.yaml
构建产物为独立可执行文件,只需一个 YAML 配置文件即可运行。
跨平台发布打包
# 编译全部 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。
配置文件结构
# yaml-language-server: $schema=./probe-config.schema.json
server: # 服务配置(均可省略)
listen:
host: "127.0.0.1"
port: 3000
storage:
dataDir: "/tmp/probes_data"
retention: "7d"
logging:
level: "info"
file:
path: "<dataDir>/logs/dial.log"
probes: # 拨测运行时配置(可省略)
execution:
maxConcurrentChecks: 20
variables: # 配置变量(可省略)
env_name: "生产"
base_url: "https://api.example.com"
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 专属默认值见对应章节
如需在多个 target 间共享相同的配置值,可使用 variables 定义变量,然后在 target 中通过 ${var} 引用。例如在 variables 中定义 default_interval: "30s",在多个 target 的 interval 字段写 ${default_interval}。
variables — 配置变量
variables 是顶层动态键值表,key 必须符合 [a-zA-Z_][a-zA-Z0-9_]*,value 仅支持 string、number、boolean。target 中的字符串值可引用变量:
${key}:引用 variables 或环境变量${key|default}:变量和环境变量都不存在时使用默认值,第一个|后的内容为默认值$${key}:转义输出字面量${key}
解析优先级为 variables -> process.env -> 默认值。字段值完整等于单个变量引用时会保留 number/boolean/string 类型;部分拼接时统一转为字符串。变量替换仅作用于 targets,且不会替换 id 和 type 字段。
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 |
否 |
配置示例
- 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 |
否 |
配置示例
- 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 |
否 |
配置示例
- 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 |
否 |
配置示例
- 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 |
否 |
配置示例
- 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 |
否 |
配置示例
- 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 |
否 |
配置示例
- 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、匹配状态、耗时和时间戳。
开发
bun run check # schema:check + typecheck + lint + test
bun run verify # check + build
开发相关文档(项目结构、构建、测试、代码规范等)请参阅 DEVELOPMENT.md。
License
Apache-2.0



