feat: 结构化 observation 替代 statusDetail,API 层动态构造 detail
- CheckResult: statusDetail -> observation (持久化) + detail (API 动态派生) - 存储: status_detail 列 -> observation TEXT (JSON) - CheckerDefinition: 新增 buildDetail(observation) 方法 - 各 checker 返回结构化 observation,API 层通过 registry 调用 buildDetail - HTTP: bodyPreview 在 status/header 失败时也提前采集 - UDP: observation 包含 durationMs,未响应归为 error failure - CMD: 超时/输出超限时保留已收集 observation - TCP: connectTimeMs 仅含连接建立耗时,不含 banner 等待 - 新增 buildDetail 单测和 mapCheckResult 覆盖测试 - 同步 openspec 主规范,归档 checker-observation 变更
This commit is contained in:
@@ -1,6 +1,8 @@
|
||||
import type { ApiErrorResponse, CheckFailure, CheckResult, HealthResponse, RuntimeMode } from "../shared/api";
|
||||
import type { StoredCheckResult } from "./checker/types";
|
||||
|
||||
import { checkerRegistry } from "./checker/runner";
|
||||
|
||||
export function createApiError(error: string, status: number): ApiErrorResponse {
|
||||
return { error, status };
|
||||
}
|
||||
@@ -45,7 +47,7 @@ export function jsonResponse(
|
||||
});
|
||||
}
|
||||
|
||||
export function mapCheckResult(row: StoredCheckResult): CheckResult {
|
||||
export function mapCheckResult(row: StoredCheckResult, type: string): CheckResult {
|
||||
let failure: CheckFailure | null = null;
|
||||
if (row.failure) {
|
||||
try {
|
||||
@@ -56,11 +58,32 @@ export function mapCheckResult(row: StoredCheckResult): CheckResult {
|
||||
}
|
||||
}
|
||||
|
||||
let observation: null | Record<string, unknown> = null;
|
||||
if (row.observation) {
|
||||
try {
|
||||
observation = JSON.parse(row.observation) as Record<string, unknown>;
|
||||
} catch {
|
||||
console.warn(`无法解析 observation 数据: target_id=${row.target_id}, timestamp=${row.timestamp}`);
|
||||
observation = null;
|
||||
}
|
||||
}
|
||||
|
||||
let detail: null | string = null;
|
||||
if (observation !== null) {
|
||||
try {
|
||||
const checker = checkerRegistry.get(type);
|
||||
detail = checker.buildDetail(observation);
|
||||
} catch {
|
||||
detail = null;
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
detail,
|
||||
durationMs: row.duration_ms,
|
||||
failure,
|
||||
matched: row.matched === 1,
|
||||
statusDetail: row.status_detail,
|
||||
observation,
|
||||
timestamp: row.timestamp,
|
||||
};
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user