1
0
Files
DiAL/README.md
lanyuanxiaoyao 1c5cfafda6 feat: 前端指标体系增强 — Dashboard/Metrics API、2×4 统计区、趋势图面积+异常标记、连续状态列
- 新增 GET /api/dashboard 合并原 summary+targets 首屏接口
- 新增 GET /api/targets/:id/metrics 合并原 stats+trend 概览接口
- 后端指标纯函数:可用率、百分位、故障段分析、连续状态、UTC 小时分桶
- ProbeStore 窗口取数方法替代全量历史查询
- SummaryCards 扩展为 4 卡片(新增异常事件数)+ 数据新鲜度展示
- 表格新增「连续」列(Tag 渲染 capped 状态)
- OverviewTab 重构为 2×4 Statistic 多维度布局
- TrendChart 改为延迟范围面积图 + 红色异常标记点
- 删除旧路由(summary/targets/trend)和 computeTrendStats
- 同步 delta specs 到主 specs 并归档变更
2026-05-14 12:32:41 +08:00

235 lines
10 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.
# DiAL
基于 Bun + TypeScript 的多类型拨测监控工具。通过 YAML 配置文件定义 HTTP 和命令行拨测目标,后端按配置定时并发拨测,结果持久化到本地 SQLite前端 Dashboard 展示各目标实时状态、可用率、耗时趋势等。
## 快速开始
```bash
bun install
cp probes.example.yaml probes.yaml
bun run dev probes.yaml
```
`bun run dev` 启动单进程 fullstack 开发服务器(后端 API + 前端 SPA + HMR访问 `http://127.0.0.1:3000`
## 开发验证
```bash
bun run check # schema:check + typecheck + lint + bun test
bun run verify # check + build
```
`verify` 会基于当前源码重新构建生产 executable。原 smoke test 已移除executable/E2E 验证后续单独补充。
## 配置文件
程序通过 YAML 配置文件定义所有运行参数:
```yaml
# yaml-language-server: $schema=./probe-config.schema.json
server:
host: "127.0.0.1"
port: 3000
dataDir: "/tmp/probes_data"
runtime:
maxConcurrentChecks: 20
retention: "7d"
defaults:
interval: "5s"
timeout: "10s"
http:
method: GET
maxBodyBytes: "10MB"
cmd:
maxOutputBytes: "1MB"
targets:
- name: "Baidu"
type: http
http:
url: "https://www.baidu.com"
expect:
status: [200]
maxDurationMs: 10000
- name: "JSON API 示例"
type: http
http:
url: "https://httpbin.org/json"
expect:
status: [200]
headers:
Content-Type:
contains: "application/json"
body:
- contains: "slideshow"
- json:
path: "$.slideshow.title"
equals: "Sample Slide Show"
- name: "HTML 页面示例"
type: http
http:
url: "https://httpbin.org/html"
expect:
status: [200]
body:
- contains: "Moby-Dick"
- xpath:
path: "/html/body/h1/text()"
equals: "Herman Melville - Moby-Dick"
- name: "Bun 脚本检查"
type: cmd
cmd:
exec: "bun"
args: ["-e", "console.log('ok')"]
expect:
exitCode: [0]
stdout:
- contains: "ok"
```
### 配置说明
- **server**: 服务配置(均可省略,使用默认值)
- `host`: 监听地址,默认 `127.0.0.1`
- `port`: 监听端口,默认 `3000`
- `dataDir`: 数据目录,默认 `./data`,相对路径基于配置文件所在目录解析
- **runtime**: 运行时配置
- `maxConcurrentChecks`: 最大并发拨测数,默认 `20`
- `retention`: 历史数据保留时长,默认 `7d`,支持 `ms`/`s`/`m`/`h`/`d` 单位
- **defaults**: 全局默认值(均可省略)
- `interval`: 拨测间隔,默认 `30s`
- `timeout`: 超时时间,默认 `10s`
- `http`: HTTP 类型默认值
- `method`: HTTP 方法,默认 `GET`,必须使用大写枚举值,支持 `GET``HEAD``POST``PUT``PATCH``DELETE``OPTIONS`
- `maxBodyBytes`: 响应体最大字节数,默认 `100MB`
- `headers`: 默认请求头target 中的 headers 会合并覆盖 defaults 中的同名头)
- `cmd`: Cmd 类型默认值
- `maxOutputBytes`: 输出最大字节数,默认 `100MB`
- `cwd`: 默认工作目录(相对于配置文件所在目录解析,默认 `.`
- **targets**: 拨测目标列表(必填)
- `name`: 目标名称(必填,唯一)
- `type`: 目标类型,`http``cmd`(必填)
- `group`: 分组名称(可选,默认 `"default"`
- `http`: HTTP 拨测配置type 为 http 时必填)
- `url`: 目标 URL
- `method``headers``body`: 请求参数(`headers` 会与 `defaults.http.headers` 合并target 优先)
- `ignoreSSL`: 是否忽略 HTTPS 证书校验,默认 `false`,用于自签名或私有证书服务
- `maxRedirects`: 最大重定向跟随次数,默认 `0`(不跟随重定向)
- `cmd`: 命令行拨测配置type 为 cmd 时必填)
- `exec`: 可执行文件名或路径
- `args`: 命令行参数列表
- `env`: 环境变量覆盖(可选,继承进程环境变量并合并覆盖)
- `cwd`: 工作目录(可选,相对于配置文件所在目录解析,默认 `.`
- `interval``timeout`: 覆盖全局默认值
- `expect`: 期望校验
- `status`: 可接受的状态码列表HTTP支持精确状态码和范围模式`"2xx"`)混合配置;未指定时默认 `[200]`
- `exitCode`: 可接受的退出码列表Cmd未指定时不校验退出码
- `headers`: 响应头校验HTTP支持字符串精确匹配或操作符对象
- `maxDurationMs`: 最大耗时阈值(毫秒)
- HTTP覆盖完整执行含重定向、响应体读取和 expect 校验)
- Cmd覆盖命令执行耗时含 stdout/stderr 读取)
- `body`: HTTP 响应体校验(数组,可组合使用)
- `contains`: 响应体包含的文本
- `regex`: 响应体匹配的正则表达式(启动期会拒绝嵌套量词等存在 ReDoS 风险的模式)
- `json`: JSONPath 提取值比较
- `path`: JSONPath 表达式(必填,如 `$.slideshow.title`
- 比较操作符(可选,无操作符时仅检查路径对应值是否存在)
- `css`: CSS 选择器提取 HTML 元素比较
- `selector`: CSS 选择器(必填)
- `attr`: 提取元素属性值而非文本内容(可选,如 `href``class`
- 比较操作符(可选,无操作符时仅检查元素是否存在)
- `xpath`: XPath 提取 XML/HTML 节点比较
- `path`: XPath 表达式(必填,如 `/html/body/h1/text()`
- 比较操作符(可选,无操作符时仅检查节点是否存在)
- `stdout` / `stderr`: Cmd 输出校验(数组,每项为一个操作符对象)
- 比较操作符:`equals`(默认)、`contains``match`(正则,启动期会拒绝存在 ReDoS 风险的模式)、`empty``exists``gte``lte``gt``lt`
大小说明:`maxBodyBytes``maxOutputBytes` 支持单位 `KB``MB``GB`,也可直接使用数字(非负安全整数字节数)。
配置校验:系统启动时会先用 TypeBox 生成的 JSON Schema 契约校验字段类型、必填字段、枚举、数组/对象形状和未知字段,再执行语义 validator 校验 target name 唯一性、URL、正则、JSONPath、XPath、size/duration 解析等规则。非法配置会阻止启动并输出中文错误信息。
未知字段:除 `http.headers``defaults.http.headers``expect.headers``cmd.env` 等动态键值表外,未知字段会导致启动失败。配置备注请使用 YAML 注释,不要添加 `note``comment` 等未声明字段。
JSON Schema仓库根目录导出 `probe-config.schema.json`,可在 YAML 文件顶部添加 `# yaml-language-server: $schema=./probe-config.schema.json` 获取编辑器提示和静态校验。该 schema 由运行期契约 fragments 生成,提交前可用 `bun run schema:check` 检查同步。
时长格式支持:`500ms``30s``5m``2h``7d`
## API 端点
| 端点 | 说明 |
| ----------------------------------------------------------------- | ------------------------------------------------------------ |
| `GET /health` | 健康检查 |
| `GET /api/meta` | 运行时元信息checker 类型列表) |
| `GET /api/dashboard?window=24h&recentLimit=30` | Dashboard 首屏聚合数据summary + targets |
| `GET /api/targets/:id/metrics?from=ISO&to=ISO&bucket=1h` | 指定目标的统计、可靠性指标和按小时趋势 |
| `GET /api/targets/:id/history?from=ISO&to=ISO&page=1&pageSize=20` | 指定目标的拨测记录(时间范围 + 分页,`pageSize` 最大 `200` |
### 响应字段
**DashboardResponse**: `summary``targets`
**DashboardResponse.summary**: `total``up``down``lastCheckTime``incidents``window`
**MetaResponse**: `checkerTypes`(已注册 checker 类型标识符列表)
**TargetStatus**: `id``name``type`checker 类型,如 http/cmd`target`URL 或命令摘要)、`group``interval``latestCheck``stats``currentStreak``recentSamples`
**RecentSample**: `timestamp``durationMs``up`
**CheckResult**: `timestamp``matched``durationMs``statusDetail``failure`
**CheckFailure**: `kind`error/mismatch`phase``path``message``expected?`(仅 mismatch`actual?`(仅 mismatch
**TargetStats**: `totalChecks``upChecks``downChecks``availability`
**CurrentStreak**: `up``count``capped?`
**TargetMetricsResponse**: `targetId``window``stats``trend`
**TargetMetricsResponse.stats**: `totalChecks``upChecks``downChecks``availability``avgDurationMs``p95DurationMs``p99DurationMs``mttr``longestOutage``incidentCount``currentStreak`
**TrendPoint**: `bucketStart``avgDurationMs``minDurationMs``maxDurationMs``availability``totalChecks``upChecks``downChecks`
**HistoryResponse**: `items`CheckResult[])、`total``page``pageSize`
### 错误响应
API 错误返回 `ApiErrorResponse` 格式:
```json
{ "error": "描述信息", "status": 400 }
```
| 状态码 | 触发场景 |
| ------ | ------------------------------------------------------------------------------------------ |
| 400 | 参数格式错误(无效 ID、from/to 缺失或格式错误、page/pageSize 非正整数、pageSize 超过 200 |
| 404 | 目标不存在、API 路由未匹配、非 GET 方法请求 API 路由 |
## 运行参数
CLI 只接受一个参数YAML 配置文件路径。
```bash
./dist/dial-server ./probes.yaml
```
## 目标状态判定
单层判定模型,适用于 HTTP 和 Cmd 两种类型:
- **matched**: 是否符合 expect 规则HTTP 未指定 `expect.status` 时默认检查 `[200]`
- **UP** = matched
- **DOWN** = NOT matched
执行失败(网络错误、超时、进程崩溃)和 expect 不匹配都统一为 `matched=false`,通过 `failure.kind` 区分(`"error"` vs `"mismatch"`)。
---
> 开发相关文档(项目结构、构建、测试、代码规范等)请参阅 [DEVELOPMENT.md](DEVELOPMENT.md)。