fix(web-probe): bound collect output and split partial timing (#719)
Co-authored-by: Codex <codex@noreply.local>
This commit is contained in:
@@ -8305,6 +8305,7 @@ function renderWebObserveAnalyzeTable(value: Record<string, unknown>): string {
|
||||
const roundCount = Array.isArray(sampleMetrics?.rounds) ? sampleMetrics.rounds.length : sampleMetrics?.rounds;
|
||||
const turnColumnCount = Array.isArray(sampleMetrics?.turnColumns) ? sampleMetrics.turnColumns.length : sampleMetrics?.turnColumns;
|
||||
const slowApis = Array.isArray(analysis?.pagePerformanceSlowApi) ? analysis.pagePerformanceSlowApi.map(record).filter((item): item is Record<string, unknown> => item !== null).slice(0, 8) : [];
|
||||
const partialApis = Array.isArray(analysis?.pagePerformancePartialApi) ? analysis.pagePerformancePartialApi.map(record).filter((item): item is Record<string, unknown> => item !== null).slice(0, 8) : [];
|
||||
const sseStreams = Array.isArray(analysis?.pagePerformanceSseStreams) ? analysis.pagePerformanceSseStreams.map(record).filter((item): item is Record<string, unknown> => item !== null).slice(0, 8) : [];
|
||||
const findings = Array.isArray(analysis?.findings) ? analysis.findings.map(record).filter((item): item is Record<string, unknown> => item !== null).slice(0, 8) : [];
|
||||
const httpErrorGroups = Array.isArray(analysis?.httpErrorGroups) ? analysis.httpErrorGroups.map(record).filter((item): item is Record<string, unknown> => item !== null).slice(0, 8) : [];
|
||||
@@ -8626,6 +8627,29 @@ function renderWebObserveAnalyzeTable(value: Record<string, unknown>): string {
|
||||
return rows.length > 0 ? rows : [["-", "-", "-", "-", "-", "-", "-", "-", "-", "-", "-"]];
|
||||
})()),
|
||||
"",
|
||||
"Partial API timing (>5s, not counted as completed slow API):",
|
||||
webObserveTable(["PATH", "SAMPLES", "COMPLETE", "PARTIAL", "PARTIAL>5S"], partialApis.length > 0 ? partialApis.map((item) => [
|
||||
webObserveShort(webObserveText(item.path ?? item.route), 52),
|
||||
webObserveText(item.sampleCount),
|
||||
webObserveText(item.completeTimingSampleCount),
|
||||
webObserveText(item.partialTimingSampleCount),
|
||||
webObserveText(item.partialOverFiveSecondCount),
|
||||
]) : [["-", "-", "-", "-", "-"]]),
|
||||
"",
|
||||
"Partial API samples:",
|
||||
webObserveTable(["TS", "SEQ", "PATH", "DURATION", "TIMING", "INIT", "PROTO"], (() => {
|
||||
const rows = partialApis.flatMap((item) => (Array.isArray(item.partialSamples) ? item.partialSamples : []).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),
|
||||
webObserveShort(webObserveText(sample.timingStatus), 12),
|
||||
webObserveShort(webObserveText(sample.initiatorType), 12),
|
||||
webObserveShort(webObserveText(sample.nextHopProtocol), 12),
|
||||
]);
|
||||
return rows.length > 0 ? rows : [["-", "-", "-", "-", "-", "-", "-"]];
|
||||
})()),
|
||||
"",
|
||||
"Long-lived streams (SSE):",
|
||||
webObserveTable(["PATH", "SAMPLES", "OPEN_P95", "OPEN_MAX", "OPEN>5S", "LIFE>5S"], sseStreams.length > 0 ? sseStreams.map((item) => [
|
||||
webObserveShort(webObserveText(item.path ?? item.route), 52),
|
||||
@@ -9403,7 +9427,19 @@ const slimJsonValue=(value,depth=0)=>{
|
||||
}
|
||||
return short(value,180);
|
||||
};
|
||||
const slimFinding=(item)=>item&&typeof item==='object'?{kind:short(item.kind||item.code||item.id,80),severity:short(item.severity||item.level,24),count:item.count??item.sampleCount??null,summary:short(item.summary||item.message,240)}:null;
|
||||
const slimFinding=(item)=>{
|
||||
if(!item||typeof item!=='object') return null;
|
||||
const samples=Array.isArray(item.samples)?item.samples.length:null;
|
||||
const groups=Array.isArray(item.groups)?item.groups.length:null;
|
||||
return {
|
||||
kind:short(item.kind||item.code||item.id,80),
|
||||
severity:short(item.severity||item.level,24),
|
||||
count:item.count??item.sampleCount??null,
|
||||
summary:short(item.summary||item.message,240),
|
||||
sampleRows:samples,
|
||||
groupRows:groups
|
||||
};
|
||||
};
|
||||
const slimRunnerError=(item)=>item&&typeof item==='object'?{ts:short(item.ts||item.at,32),type:short(item.type,48),retry:item.retry||item.lastRetryLabel||null,retryExhausted:item.retryExhausted===true,attemptCount:item.attemptCount??(Array.isArray(item.attempts)?item.attempts.length:null),lastFailureKind:short(item.lastFailureKind||item.failureKind,80),lastReadinessReason:short(item.lastReadinessReason,80),message:short(item.message||item.lastError,240)}:null;
|
||||
const slimJsonl=(value)=>{
|
||||
if(!value||typeof value!=='object'||Array.isArray(value)) return {value:short(value)};
|
||||
@@ -9444,16 +9480,17 @@ if(selected){
|
||||
const lines=text.split(/\\r?\\n/).filter(Boolean);
|
||||
if(isJsonl&&truncated&&lines.length>0) lines.shift();
|
||||
let jsonSummary=null; let jsonContent=null;
|
||||
if(isJson){try{const parsed=JSON.parse(raw.toString('utf8')); jsonContent=slimJsonValue(parsed); jsonSummary={topLevelKeys:parsed&&typeof parsed==='object'&&!Array.isArray(parsed)?Object.keys(parsed).slice(0,40):[],counts:slimObject(parsed&&parsed.counts),sampleMetrics:slimObject(parsed&&parsed.sampleMetrics),runtimeAlerts:slimObject(parsed&&parsed.runtimeAlerts),pagePerformance:slimObject(parsed&&parsed.pagePerformance),runnerErrors:Array.isArray(parsed&&parsed.runnerErrors)?parsed.runnerErrors.slice(-8).map(slimRunnerError).filter(Boolean):[],findings:Array.isArray(parsed&&parsed.findings)?parsed.findings.slice(0,8).map(slimFinding).filter(Boolean):[]}}catch(error){jsonSummary={parseError:String(error&&error.message||error).slice(0,160)}}}
|
||||
const jsonlTail=isJsonl?lines.slice(-20).map((line,index)=>{try{return slimJsonl(JSON.parse(line))}catch(error){return {parseError:true,index,lineTail:line.slice(-240),error:String(error&&error.message||error).slice(0,160)}}}):null;
|
||||
if(isJson){try{const parsed=JSON.parse(raw.toString('utf8')); jsonContent=raw.length<=4096?slimJsonValue(parsed):null; jsonSummary={topLevelKeys:parsed&&typeof parsed==='object'&&!Array.isArray(parsed)?Object.keys(parsed).slice(0,24):[],counts:slimObject(parsed&&parsed.counts,16),sampleMetrics:slimObject(parsed&&parsed.sampleMetrics,16),runtimeAlerts:slimObject(parsed&&parsed.runtimeAlerts,16),pagePerformance:slimObject(parsed&&parsed.pagePerformance,16),runnerErrors:Array.isArray(parsed&&parsed.runnerErrors)?parsed.runnerErrors.slice(-4).map(slimRunnerError).filter(Boolean):[],findings:Array.isArray(parsed&&parsed.findings)?parsed.findings.slice(0,6).map(slimFinding).filter(Boolean):[]}}catch(error){jsonSummary={parseError:String(error&&error.message||error).slice(0,160)}}}
|
||||
const jsonlTail=isJsonl?lines.slice(-8).map((line,index)=>{try{return slimJsonl(JSON.parse(line))}catch(error){return {parseError:true,index,lineTail:line.slice(-240),error:String(error&&error.message||error).slice(0,160)}}}):null;
|
||||
console.log(JSON.stringify({ok:true,command:'web-probe-observe collect',stateDir:dir,mode:'file',file:{path:file,relative,byteCount:st.size,sha256:shaFile(file),truncated,content:isJsonl||isJson||jsonSummary?undefined:text.slice(0,maxTextPreviewBytes),contentTruncated:!isJsonl&&!isJson&&!jsonSummary&&text.length>maxTextPreviewBytes,jsonlTail,jsonSummary,jsonContent,lineCount:lines.length},valuesRedacted:true},null,2));
|
||||
process.exit(0);
|
||||
}
|
||||
const out=[]; const walk=(p)=>{for(const ent of fs.readdirSync(p,{withFileTypes:true})){const full=path.join(p,ent.name); if(ent.isDirectory()) walk(full); else out.push(full); if(out.length>=maxFiles) return;}};
|
||||
walk(dir);
|
||||
const files=out.slice(0,maxFiles).map(file=>{const st=fs.statSync(file); return {path:file,relative:path.relative(dir,file),byteCount:st.size,sha256:shaFile(file)}});
|
||||
const totalBytes=files.reduce((sum,item)=>sum+item.byteCount,0);
|
||||
console.log(JSON.stringify({ok:true,command:'web-probe-observe collect',stateDir:dir,fileCount:files.length,totalBytes,files,valuesRedacted:true},null,2));
|
||||
const selectedFiles=out.slice(0,maxFiles);
|
||||
const files=selectedFiles.slice(0,24).map(file=>{const st=fs.statSync(file); return {relative:path.relative(dir,file),byteCount:st.size,sha256:shaFile(file)}});
|
||||
const totalBytes=selectedFiles.reduce((sum,file)=>sum+fs.statSync(file).size,0);
|
||||
console.log(JSON.stringify({ok:true,command:'web-probe-observe collect',stateDir:dir,fileCount:selectedFiles.length,listedFileCount:files.length,omittedFileCount:Math.max(0,selectedFiles.length-files.length),totalBytes,files,valuesRedacted:true},null,2));
|
||||
`)} "$state_dir" ${shellQuote(collectFile ?? "")}`;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user