feat(日志): 任务步骤明细表 + 「日志 → 步骤明细」面板(按设备/任务/时间过滤、按运行归组、导出 CSV)
文本日志只能 grep,"这台设备这次运行为什么失败"翻起来很费劲。新增一张 **结构化**的步骤明细表,把"哪一步、什么类型、哪个选择器、结果、耗时"落库。 - core/models.py:新增 task_step_log(run_id/job/设备/step_path/selector/ result/detail/duration_ms),索引 run_id、created_at、(serial,created_at)、 (job_id,created_at); - core/step_log.py(新):**专用写线程 + 有界队列**批量落库——步骤执行是热路径, 任务线程只 put_nowait(实测 9000 次入队 31ms),队列满丢弃并计数,绝不阻塞; 另有保留期清理(默认 14 天,每日 04:13 + 每次启动); - tasks/generic/task.py:_exec_one 记一条(异常=error / handler 返回 False=miss / 未知类型=unknown / 概率未触发=skip);_exec_steps 维护路径栈得到 "2.1.3" 这样的嵌套位置;**单次运行封顶 2000 条**——forever 循环任务否则会写爆表; - 运行上下文 ctx(run_id/job_id/job_name/device_name)由 TaskManager 生成, 经 create_worker(serial, params, ctx=None) 传入 worker(扩展点向后兼容); - 接口:/api/step_logs(过滤+分页)、/runs(按运行归组)、/filters(下拉选项)、 /download(CSV,带 BOM); - 前端:日志页拆成「文件日志 / 步骤明细」子分栏 + static/admin/steplog.js。 红线:新表自动进备份覆盖清单(SUMMARY_TABLES 由元数据派生),已补 TABLE_LABELS 中文标签,导出实测 14 张表、coverage_missing 为空。 文档:DATA_MODEL §2.8/§1、API §10.2、ARCHITECTURE §1.1/§2.2/§3.1、 DEVELOPMENT §5.2 与红线表、DEPLOY §5.2、TASK_DEV §8.3、README。
This commit is contained in:
+26
@@ -141,6 +141,10 @@
|
||||
| DELETE | `/api/users/<int:uid>` | Admin | 删除用户 |
|
||||
| GET | `/api/logs` | G | 读日志(关键字/级别/时间过滤,返回结构化行) |
|
||||
| GET | `/api/logs/download` | G | 下载日志(同样支持过滤;无过滤即整个文件) |
|
||||
| GET | `/api/step_logs` | G | 任务步骤明细(按设备/任务/结果/时间/关键字过滤,分页) |
|
||||
| GET | `/api/step_logs/runs` | G | 按 `run_id` 归组的一次运行概览(几步、失败几步) |
|
||||
| GET | `/api/step_logs/filters` | G | 步骤明细的筛选项(明细里出现过的设备/任务 + 结果枚举) |
|
||||
| GET | `/api/step_logs/download` | G | 导出步骤明细 CSV(带 UTF-8 BOM,Excel 直接打开) |
|
||||
|
||||
### 2.5 devices(`web/devices_api.py`)
|
||||
|
||||
@@ -648,6 +652,28 @@
|
||||
- `matched` 是命中总数,`truncated=true` 表示更早的命中没返回(应缩小时间范围或加关键字);
|
||||
- `scanned` 是实际扫描行数(上限 50 万行)。
|
||||
|
||||
#### 10.2 任务步骤明细(`/api/step_logs*`)
|
||||
|
||||
数据源是 `task_step_log` 表(**结构化**,与上面的文本日志不是一回事):每一次步骤
|
||||
执行一条,能按设备/任务/结果/时间过滤、能按运行归组、能导出 CSV。写入侧见
|
||||
[DATA_MODEL.md](DATA_MODEL.md) §2.8 与 `core/step_log.py`。
|
||||
|
||||
| 接口 | 参数 | 返回 |
|
||||
|------|------|------|
|
||||
| `GET /api/step_logs` | `serial` `job_id` `result` `run_id` `q` `since` `until` `limit`(≤2000,默认 200) `offset` | `rows`(**最近的在前**)、`total`、`stats`(本次进程的 queued/written/dropped/failed)、`keep_days`、`max_rows_per_run` |
|
||||
| `GET /api/step_logs/runs` | `serial` `job_id` `since` `until` `limit`(≤500) | `runs[]`:`run_id` `started_at` `ended_at` `steps` `failures` |
|
||||
| `GET /api/step_logs/filters` | — | `devices[]` / `jobs[]`(**只列明细里真的出现过的**,不依赖设备池与任务表)、`results[]` |
|
||||
| `GET /api/step_logs/download` | 同列表接口 | 附件 `.csv`(UTF-8 **带 BOM**),最多 2 万行,按时间正序 |
|
||||
|
||||
`result` 取值:`ok` / `miss`(handler 返回 False,如元素没找到)/ `error`(抛异常)/
|
||||
`unknown`(未知步骤类型)/ `skip`(概率未触发)/ `cap`(本次运行已达记录上限)。
|
||||
|
||||
`run_id` 是"设备 × 任务 × 第几次尝试",同一行里能拿到 `step_path`(如 `2.1.3`)
|
||||
还原嵌套结构——**步骤明细面板的「最近运行概览 → 查看」就是按它过滤**。
|
||||
|
||||
> 稳定性:记录走异步队列(`record()` 零阻塞),**队列满会丢弃**(计数在 `stats.dropped`,
|
||||
> 页面提示栏会显示),所以明细允许缺条 —— 权威结论仍看任务状态与 [NOTIFY.md](NOTIFY.md) 的事件。
|
||||
|
||||
---
|
||||
|
||||
## 11. 运维工具(adb / 剪贴板 / 应用版本 / Tailscale)
|
||||
|
||||
Reference in New Issue
Block a user