1
0
Files
DiAL/README.md

33 KiB
Raw Blame History

DiAL

轻量级多类型拨测监控工具

基于 Bun + TypeScript 构建 · YAML 配置驱动 · 内置 Dashboard


DiAL 是一个自托管的拨测监控工具,支持 HTTP命令行数据库TCPUDPDNSICMPLLM 多种拨测类型。通过 YAML 配置文件定义拨测目标,后端定时并发执行拨测并将结果持久化到本地 SQLite前端 Dashboard 展示各目标的实时状态、可用率和耗时趋势。

功能亮点:

  • 多种拨测类型HTTPGET/POST/PUT 等、Cmd命令行执行、DBPostgreSQL/MySQL/SQLite、TCP端口可达性 + Banner 探测、UDP自定义 payload 请求-响应、DNS本机解析检查 + DNS server 深度拨测、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)。

版本升迁命令:

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 index-dark
详情页 detail-light detail-dark

快速开始

前置条件: 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 配置文件即可运行。

Docker 部署

DiAL 提供基于 Alpine 的多阶段镜像。构建阶段使用 Bun 生成 musl 目标单可执行文件,运行阶段只包含 dial-server、基础证书、ping、musl executable 必需运行库、时区数据和容器运行所需目录。

# 构建当前架构镜像
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,默认监听 0.0.0.0:3000,并将 SQLite 数据和日志写入 /data/dial

多架构镜像可通过 Docker Buildx 构建:

docker buildx build --platform linux/amd64,linux/arm64 -t dial:alpine .

如需在容器中运行 ICMP checker除镜像内置的 iputils-ping 外,还需要授予 NET_RAW capability

docker run --rm --cap-add=NET_RAW -p 3000:3000 -v dial-data:/data/dial dial:alpine

官方镜像不内置 bunnodecurldigpsqlmysqlredis-cli 等 CMD checker 可能需要的额外命令。需要这些命令时请使用派生镜像自行安装:

FROM dial:alpine

USER root
RUN apk add --no-cache curl bind-tools postgresql-client
USER dial

跨平台发布打包

# 编译全部 7 个目标平台
bun run release

# 编译指定平台
bun run release --target linux-x64
bun run release --target linux-x64,windows-x64,darwin-arm64

支持的目标平台:linux-x64linux-arm64linux-x64-musllinux-arm64-muslwindows-x64darwin-x64darwin-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.yamlLICENSE,解压后可直接使用。

配置文件

程序通过 YAML 配置文件定义所有运行参数,完整示例参见 probes.example.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 按时间滚动:hourlydailyweekly daily
server.logging.file.rotation.maxFiles 保留的归档文件数量(不含活跃日志) 14

日志等级支持:tracedebuginfowarnerrorfatal

控制台始终输出pretty 格式),文件始终输出 JSONL 格式并支持滚动。rotation.sizerotation.frequency 任一条件触发即滚动。

内置默认值

未显式配置时,系统使用以下内置默认值:

  • interval30s(拨测间隔)
  • timeout10s(超时时间)
  • 各 checker 专属默认值见对应章节

如需在配置文件中共享相同的配置值,可使用 variables 定义变量,然后在 serverprobestargets 中通过 ${var} 引用。例如在 variables 中定义 default_interval: "30s",在多个 target 的 interval 字段写 ${default_interval}

variables — 配置变量

variables 是顶层动态键值表key 必须符合 [a-zA-Z_][a-zA-Z0-9_]*value 仅支持 string、number、boolean。serverprobestargets 中的字符串值可引用变量:

  • ${key}:引用 variables 或环境变量
  • ${key|default}:变量和环境变量都不存在时使用默认值,第一个 | 后的内容为默认值
  • ${key|}:变量和环境变量都不存在时使用空字符串作为默认值
  • $${key}:转义输出字面量 ${key}

解析优先级为 variables -> process.env -> 默认值,三者均不存在时配置校验失败。字段值完整等于单个变量引用时会保留 number/boolean/string 类型,环境变量和默认值会做类型推断,但空字符串保持为字符串;部分拼接时统一转为字符串。变量替换作用于 serverprobestargets,不作用于 variables 段自身,且不会替换 targets[].idtargets[].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 目标类型:httpcmddbtcpudpdnsicmpllm
group 分组名称 default
interval 拨测间隔,未配置时使用内置默认值 30s 30s
timeout 超时时间,未配置时使用内置默认值 10s 10s

HTTP Checkertype: 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 Checkertype: 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 Checkertype: 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 Checkertype: 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 Checkertype: udp

配置项

字段 说明 必填 默认值
udp.host 目标主机地址
udp.port 目标端口1-65535
udp.payload 发送数据 ""
udp.encoding payload 编码:texthexbase64 text
udp.responseEncoding 响应解码:texthexbase64 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 Checkertype: 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

DNS Checkertype: dns

DNS Checker 支持两种解析模式,通过 dns.resolver 字段区分:

  • system 模式:使用本机 DNS 解析器检查域名是否能解析到预期地址,输出有限 observation。
  • server 模式:直接向指定 DNS server 发起 UDP/TCP 深度拨测,检查 DNS 协议级响应RCODE、TTL、flags、记录值等

dns.resolver: system 配置项

字段 说明 必填 默认值
dns.resolver 解析模式 system
dns.name 待解析域名
dns.family 地址族 any

family 可选值:any(返回 IPv4 和 IPv6ipv4(仅 IPv4ipv6(仅 IPv6

system 模式 expect 校验项

字段 说明 断言模型
values 解析结果地址集合断言 DNS 集合include/exclude/exact
valueCount 解析结果数量 ValueMatcher
durationMs 解析耗时 ValueMatcher

示例

- id: "dns-system-api"
  name: "本机 DNS 解析"
  type: dns
  dns:
    resolver: system
    name: "api.example.com"
    family: any
  expect:
    values:
      exact:
        - "203.0.113.10"
    durationMs:
      lte: 500

dns.resolver: server 配置项

字段 说明 必填 默认值
dns.resolver 解析模式 server
dns.server DNS server 地址
dns.name 查询域名
dns.port DNS server 端口 53
dns.protocol 传输协议:udp / tcp udp
dns.recordType DNS 记录类型 A
dns.recursionDesired 是否设置 RD flag true
dns.tcpFallback UDP 响应 TC=1 时是否 TCP fallback true
dns.maxResponseBytes 响应最大字节数 4KB

recordType 可选值:AAAAACNAMENSMXTXTSOASRVCAAPTR

server 模式 expect 校验项

字段 说明 断言模型
responded 是否收到 DNS response boolean
rcode 期望 RCODE 列表(如 NOERROR string[]
values 目标类型记录值集合断言 DNS 集合include/exclude/exact
valueCount 目标类型记录数量 ValueMatcher
answerCount answer section 总记录数 ValueMatcher
ttlMin answer 中最小 TTL ValueMatcher
ttlMax answer 中最大 TTL ValueMatcher
authoritative AA flag boolean
recursionAvailable RA flag boolean
truncated TC flag boolean
authenticatedData AD flag boolean
result 完整结构化响应的 JSONPath 兜底断言 ContentExpectations
durationMs 完整查询耗时 ValueMatcher

示例

- id: "dns-server-api"
  name: "Cloudflare DNS A 记录"
  type: dns
  dns:
    resolver: server
    server: "1.1.1.1"
    port: 53
    protocol: udp
    name: "api.example.com"
    recordType: A
  expect:
    rcode: ["NOERROR"]
    values:
      include:
        - "203.0.113.10"
    ttlMin:
      gte: 60
    durationMs:
      lte: 200

- id: "dns-nxdomain-check"
  name: "负向 DNS 检查"
  type: dns
  dns:
    resolver: server
    server: "1.1.1.1"
    name: "nxdomain.example.com"
    recordType: A
  expect:
    rcode: ["NXDOMAIN"]

Notes

  • 未配置 expect 时,system 模式默认要求解析成功且 valueCount > 0server 模式默认要求 NOERROR + valueCount > 0
  • 显式配置非 NOERROR rcodeNXDOMAIN)时,不自动要求 valueCount > 0
  • values.exact 忽略返回顺序(集合匹配);对 A/AAAA 查询CNAME 链不计入 values,单独放入 cnameChain
  • values 按记录类型规范化为字符串格式MX="10 mail.example.com"、SOA=空格分隔字段、SRV="10 60 443 server.example.com"、CAA="0 issue letsencrypt.org" 等。

LLM Checkertype: llm

配置项

字段 说明 必填 默认值
llm.provider 模型提供方:openaiopenai-responsesanthropic
llm.url API base URL
llm.model 模型名称
llm.prompt 单轮 prompt
llm.mode 调用模式:http(非流式)或 stream(流式) http
llm.key API key支持 ${VAR} 变量替换 ""
llm.authToken Bearer tokenanthropic providerkey 互斥)
llm.headers 附加请求头
llm.ignoreSSL 忽略 HTTPS 证书校验 false
llm.options 生成选项
llm.providerOptions Provider 专属选项

llm.options 支持 maxOutputTokens(默认 16)、temperature(默认 0)、topPtopKpresencePenaltyfrequencyPenaltystopSequencesseed

expect 校验项

字段 说明 必填 默认值
status 可接受的状态码列表,支持精确码和范围(如 "2xx" [200]
headers 响应头校验,使用动态键名和 KeyedExpectations
output 模型输出校验,使用 ContentExpectations 数组
finishReason finish reason 校验,使用 ValueMatcher
rawFinishReason 原始 finish reason 校验,使用 ValueMatcher
usage Token usage 校验(inputTokens/outputTokens/totalTokens matcher
stream 流式断言(completedfirstTokenMs matchermode: 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 校验项

bodystdoutstderrbannerresponseoutputresult 均使用数组:

  • contains — 响应体包含指定文本
  • regex — 正则匹配(启动期会拒绝存在 ReDoS 风险的模式)
  • json — JSONPath 提取值比较(path 必填,如 $.slideshow.title
  • css — CSS 选择器提取 HTML 元素(selector 必填,attr 可选提取属性)
  • xpath — XPath 提取 XML/HTML 节点(path 必填,如 /html/body/h1/text()

ValueMatcher

equalscontainsregexemptyexistsgteltegtltequals 支持 JSON 深度相等;regex 固定使用无 flags 正则;提取器未配置 matcher 时等价于 exists: true。ValueMatcher expect 字段也可直接写 string、number、boolean 或 null等价于 { equals: value };数组和对象必须显式写成 { equals: ... }

KeyedExpectations

headersrows 中每行使用的校验结构,支持 ValueMatcher 的全部字段。

补充说明

  • 大小说明maxBodyBytesmaxOutputBytesmaxResponseBytesmaxBannerBytes 支持 KBMBGB 单位,也可直接使用数字
  • 时长格式500ms30s5m2h7d
  • JSON Schema:仓库根目录导出 probe-config.schema.json,在 YAML 文件顶部添加 # yaml-language-server: $schema=./probe-config.schema.json 即可在编辑器中获得提示和校验
  • 旧字段移除maxDurationMsmaxPacketLossmaxAvgLatencyMsmaxMaxLatencyMs 和旧正则字段 match 已移除,请分别改用 durationMs、ICMP matcher 字段和 regex

注意: 配置校验在启动时执行,非法配置会阻止启动并输出错误信息。除动态键值表(headersenvvariables)外,未知字段会导致启动失败,请使用 YAML 注释。

目标状态判定

采用单层判定模型:

  • UP = 拨测结果符合 expect 规则
  • DOWN = 拨测结果不符合 expect 规则

执行失败(网络错误、超时、进程崩溃)和 expect 不匹配都统一为 DOWN通过 failure.kind 区分原因("error" vs "mismatch")。

API 返回的检查结果包含 detailobservationdetail 是后端按 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