fix(web-probe): expose slow API samples in observe analysis (#644)

Co-authored-by: Codex <codex@noreply.local>
This commit is contained in:
Lyon
2026-06-22 09:59:40 +08:00
committed by GitHub
parent 49f2926731
commit 1780cb8980
3 changed files with 143 additions and 21 deletions
+28 -7
View File
@@ -7487,10 +7487,12 @@ function runNodeWebProbeObserveAnalyze(options: NodeWebProbeObserveOptions, spec
"const stdoutJson = readJson(stdoutPath);",
"const reportJson = readJson(reportJsonPath);",
"const source = (stdoutJson && stdoutJson.ok !== false ? stdoutJson : null) || reportJson || stdoutJson || null;",
"const fullSource = reportJson || source;",
"const objectOrNull = (value) => value && typeof value === 'object' && !Array.isArray(value) ? value : null;",
"const slimRound = (item) => { const v = objectOrNull(item) || {}; return { promptIndex: v.promptIndex ?? null, sampleCount: v.sampleCount ?? null, lastTotalElapsedSeconds: v.lastTotalElapsedSeconds ?? null, lastRecentUpdateSeconds: v.lastRecentUpdateSeconds ?? null, diagnosticSamples: v.diagnosticSamples ?? null, terminalSamples: v.terminalSamples ?? null, promptTextHash: clip(v.promptTextHash, 80) }; };",
"const slimTurnColumn = (item) => { const v = objectOrNull(item) || {}; return { label: clip(v.label, 24), promptIndex: v.promptIndex ?? null, lastPromptIndex: v.lastPromptIndex ?? null, traceId: clip(v.traceId, 48), firstSeq: v.firstSeq ?? null, lastSeq: v.lastSeq ?? null, source: clip(v.source, 48) }; };",
"const slimSlowApi = (item) => { const v = objectOrNull(item) || {}; return { path: clip(v.path ?? v.route, 96), route: clip(v.route ?? v.path, 96), sampleCount: v.sampleCount ?? null, p95Ms: v.p95Ms ?? v.p95 ?? null, maxMs: v.maxMs ?? v.max ?? null, overFiveSecondCount: v.overFiveSecondCount ?? null }; };",
"const slimSlowSample = (item) => { const v = objectOrNull(item) || {}; return { ts: v.ts ?? null, seq: v.seq ?? null, path: clip(v.path ?? v.rawPath, 96), initiatorType: clip(v.initiatorType, 24), durationMs: v.durationMs ?? null, requestToResponseStartMs: v.requestToResponseStartMs ?? v.streamOpenMs ?? null, responseTransferMs: v.responseTransferMs ?? null, nextHopProtocol: clip(v.nextHopProtocol, 24) }; };",
"const slimSlowApi = (item) => { const v = objectOrNull(item) || {}; return { path: clip(v.path ?? v.route, 96), route: clip(v.route ?? v.path, 96), sampleCount: v.sampleCount ?? null, p95Ms: v.p95Ms ?? v.p95 ?? null, maxMs: v.maxMs ?? v.max ?? null, overFiveSecondCount: v.overFiveSecondCount ?? null, slowSamples: Array.isArray(v.slowSamples) ? v.slowSamples.slice(0, 3).map(slimSlowSample) : [] }; };",
"const slimFinding = (item) => { const v = objectOrNull(item) || {}; return { kind: clip(v.kind ?? v.code, 48), code: clip(v.code ?? v.kind, 48), severity: clip(v.severity ?? v.level, 24), level: clip(v.level ?? v.severity, 24), count: v.count ?? v.sampleCount ?? null, sampleCount: v.sampleCount ?? v.count ?? null, summary: clip(v.summary ?? v.message, 180), message: clip(v.message ?? v.summary, 180) }; };",
"const slimDomGroup = (item) => { const v = objectOrNull(item) || {}; return { count: v.count ?? null, firstAt: v.firstAt ?? null, lastAt: v.lastAt ?? null, text: clip(v.text ?? v.preview, 180) }; };",
"const slimNetworkGroup = (item) => { const v = objectOrNull(item) || {}; return { count: v.count ?? null, method: clip(v.method, 12), status: v.status ?? null, path: clip(v.path, 96), firstAt: v.firstAt ?? null, lastAt: v.lastAt ?? null, promptIndexes: Array.isArray(v.promptIndexes) ? v.promptIndexes.slice(0, 6) : [], failureKinds: Array.isArray(v.failureKinds) ? v.failureKinds.slice(0, 4).map((x) => clip(x, 48)) : [] }; };",
@@ -7516,7 +7518,11 @@ function runNodeWebProbeObserveAnalyze(options: NodeWebProbeObserveOptions, spec
"const srcRuntimeAlerts = objectOrNull(source?.runtimeAlerts);",
"const runtimeAlerts = srcRuntimeAlerts ? { httpErrorCount: srcRuntimeAlerts.httpErrorCount ?? null, requestFailedCount: srcRuntimeAlerts.requestFailedCount ?? null, domDiagnosticSampleCount: srcRuntimeAlerts.domDiagnosticSampleCount ?? null, consoleAlertCount: srcRuntimeAlerts.consoleAlertCount ?? null } : null;",
"const srcPagePerformance = objectOrNull(source?.pagePerformance);",
"const pagePerformance = srcPagePerformance ? { sameOriginApiPaths: srcPagePerformance.sameOriginApiPaths ?? null, slowPathCount: srcPagePerformance.slowPathCount ?? null, slowSampleCount: srcPagePerformance.slowSampleCount ?? null, worstP95Ms: srcPagePerformance.worstP95Ms ?? null } : null;",
"const srcPagePerformanceSummary = objectOrNull(srcPagePerformance?.summary);",
"const pagePerformance = srcPagePerformance ? { sameOriginApiPaths: srcPagePerformance.sameOriginApiPaths ?? srcPagePerformanceSummary?.sameOriginApiPathCount ?? null, slowPathCount: srcPagePerformance.slowPathCount ?? srcPagePerformanceSummary?.slowPathCount ?? null, slowSampleCount: srcPagePerformance.slowSampleCount ?? srcPagePerformanceSummary?.slowSampleCount ?? null, worstP95Ms: srcPagePerformance.worstP95Ms ?? srcPagePerformanceSummary?.worstP95Ms ?? null } : null;",
"const fullRecentWindow = objectOrNull(fullSource?.windows?.recent);",
"const fullPagePerformance = objectOrNull(fullRecentWindow?.pagePerformance) || objectOrNull(fullSource?.pagePerformance);",
"const sourceSlowApi = Array.isArray(source?.pagePerformanceSlowApi) && source.pagePerformanceSlowApi.some((item) => Array.isArray(item?.slowSamples) && item.slowSamples.length > 0) ? source.pagePerformanceSlowApi : (Array.isArray(fullPagePerformance?.sameOriginApiByPath) ? fullPagePerformance.sameOriginApiByPath.filter((item) => Number(item?.overFiveSecondCount ?? 0) > 0) : []);",
"const srcPromptNetwork = objectOrNull(source?.promptNetwork);",
"const promptNetwork = srcPromptNetwork ? { promptSegments: srcPromptNetwork.promptSegments ?? null } : null;",
"const compact = source ? {",
@@ -7528,11 +7534,11 @@ function runNodeWebProbeObserveAnalyze(options: NodeWebProbeObserveOptions, spec
" runtimeAlerts,",
" pagePerformance,",
" promptNetwork,",
" pagePerformanceSlowApi: takeHead(source.pagePerformanceSlowApi, 5).map(slimSlowApi),",
" findings: takeHead(source.findings, 8).map(slimFinding),",
" httpErrorGroups: takeHead(source.httpErrorGroups, 8).map(slimNetworkGroup),",
" requestFailedGroups: takeHead(source.requestFailedGroups, 8).map(slimNetworkGroup),",
" domDiagnosticGroups: takeHead(source.domDiagnosticGroups, 5).map(slimDomGroup),",
" pagePerformanceSlowApi: takeHead(sourceSlowApi, 4).map(slimSlowApi),",
" findings: takeHead(source.findings, 6).map(slimFinding),",
" httpErrorGroups: takeHead(source.httpErrorGroups, 4).map(slimNetworkGroup),",
" requestFailedGroups: takeHead(source.requestFailedGroups, 5).map(slimNetworkGroup),",
" domDiagnosticGroups: takeHead(source.domDiagnosticGroups, 3).map(slimDomGroup),",
" domDiagnosticSamples: takeHead(source.domDiagnosticSamples, 5).map(slimDomSample),",
" consoleAlertGroups: takeHead(source.consoleAlertGroups, 5).map(slimConsoleGroup),",
" consoleAlertSamples: takeHead(source.consoleAlertSamples, 5).map(slimConsoleSample),",
@@ -7799,6 +7805,21 @@ function renderWebObserveAnalyzeTable(value: Record<string, unknown>): string {
webObserveText(item.overFiveSecondCount),
]) : [["-", "-", "-", "-", "-"]]),
"",
"Slow API samples (>5s):",
webObserveTable(["TS", "SEQ", "PATH", "DURATION", "REQ_WAIT", "RESP_XFER", "INIT", "PROTO"], (() => {
const rows = slowApis.flatMap((item) => (Array.isArray(item.slowSamples) ? item.slowSamples : []).map((sample) => ({ ...sample, path: sample.path ?? item.path ?? item.route }))).slice(0, 8).map((sample) => [
webObserveShort(webObserveText(sample.ts), 24),
webObserveText(sample.seq),
webObserveShort(webObserveText(sample.path), 44),
webObserveText(sample.durationMs),
webObserveText(sample.requestToResponseStartMs ?? sample.streamOpenMs),
webObserveText(sample.responseTransferMs),
webObserveShort(webObserveText(sample.initiatorType), 12),
webObserveShort(webObserveText(sample.nextHopProtocol), 12),
]);
return rows.length > 0 ? rows : [["-", "-", "-", "-", "-", "-", "-", "-"]];
})()),
"",
"DOM diagnostics:",
webObserveTable(domDiagnostics.length > 0 ? ["COUNT", "FIRST", "LAST", "TEXT"] : ["SEQ", "TS", "META", "TEXT"], domDiagnosticRows.length > 0 ? domDiagnosticRows : [["-", "-", "-", "-"]]),
"",