diff --git a/scripts/native/cicd/taskrun-drilldown.mjs b/scripts/native/cicd/taskrun-drilldown.mjs index 9cb9abf4..6d8c7786 100644 --- a/scripts/native/cicd/taskrun-drilldown.mjs +++ b/scripts/native/cicd/taskrun-drilldown.mjs @@ -59,8 +59,12 @@ async function main() { for (const container of logContainers) { const name = container.containerName || container.name; if (!podName || !name) continue; - const text = await readPodLog(podName, name, logsTailLines, perContainerBytes); + const read = await readPodLog(podName, name, logsTailLines, perContainerBytes); + const text = read.tail || ""; logs.push({ + ok: read.ok, + degradedReason: read.degradedReason, + message: read.message, pod: podName, container: name, lineCount: text.length === 0 ? 0 : text.split(/\r?\n/u).filter((line) => line.length > 0).length, @@ -70,8 +74,16 @@ async function main() { }); } const timing = lastTiming(logs); + const logFailures = logs.filter((item) => item.ok === false); console.log(JSON.stringify({ - ok: true, + ok: logFailures.length === 0, + degradedReason: logFailures.length === 0 ? null : "log-read-failed", + errors: logFailures.map((item) => ({ + pod: item.pod, + container: item.container, + degradedReason: item.degradedReason, + message: item.message, + })), taskRun: { name: metadata.name || null, namespace: metadata.namespace || namespace, @@ -222,9 +234,15 @@ function selectLogContainers(containers) { async function readPodLog(podName, container, tailLines, limitBytes) { const path = `/api/v1/namespaces/${encodeURIComponent(namespace)}/pods/${encodeURIComponent(podName)}/log?container=${encodeURIComponent(container)}&tailLines=${tailLines}&limitBytes=${limitBytes}`; try { - return tailBytes(await getText(path, false), limitBytes); + const text = tailBytes(await getText(path, false), limitBytes); + return { ok: true, degradedReason: null, message: null, tail: text }; } catch (error) { - return `log-read-failed: ${shortText(error?.message || String(error))}`; + return { + ok: false, + degradedReason: isNotFoundError(error) ? "log-not-found" : error instanceof KubeReadError ? error.reason : "log-read-failed", + message: shortText(error?.message || String(error)), + tail: "", + }; } } diff --git a/scripts/src/cicd-drilldown-render.ts b/scripts/src/cicd-drilldown-render.ts index a0a33229..72f8d4ba 100644 --- a/scripts/src/cicd-drilldown-render.ts +++ b/scripts/src/cicd-drilldown-render.ts @@ -34,6 +34,7 @@ function renderTaskRunHuman(payload: Record): string { const policy = asOptionalRecord(payload.policy); const containers = arrayRecords(result?.containers); const logs = arrayRecords(result?.logs); + const errors = arrayRecords(result?.errors); const timing = asOptionalRecord(result?.nodeCicdTiming); const query = asOptionalRecord(payload.query); const command = asOptionalRecord(payload.command); @@ -55,7 +56,8 @@ function renderTaskRunHuman(payload: Record): string { ]], ), containers.length === 0 ? "" : `\nCONTAINERS\n${table(["NAME", "CONTAINER", "STATE", "REASON", "EXIT", "STARTED", "FINISHED", "MESSAGE"], containers.map(containerRow))}`, - logs.length === 0 ? "" : `\nLOG TAILS\n${table(["POD", "CONTAINER", "LINES", "BYTES", "TIMING"], logs.map((item) => [item.pod, item.container, item.lineCount, item.bytes, asOptionalRecord(item.nodeCicdTiming) === null ? "-" : "node-cicd-timing"]))}`, + logs.length === 0 ? "" : `\nLOG TAILS\n${table(["POD", "CONTAINER", "STATUS", "REASON", "LINES", "BYTES", "TIMING", "MESSAGE"], logs.map(logRow))}`, + errors.length === 0 ? "" : `\nERRORS\n${table(["POD", "CONTAINER", "REASON", "MESSAGE"], errors.map((item) => [item.pod, item.container, item.degradedReason, item.message]))}`, timing === null ? "" : `\nNODE_CICD_TIMING\n${JSON.stringify(timing, null, 2)}`, "", `policy: tailLines=${policy?.logsTailLines ?? "-"} maxLogBytes=${policy?.maxLogBytes ?? "-"} timeoutSeconds=${policy?.taskRunTimeoutSeconds ?? "-"} maxContainers=${policy?.maxContainers ?? "-"}`, @@ -64,6 +66,19 @@ function renderTaskRunHuman(payload: Record): string { ].filter((line) => line !== "").join("\n"); } +function logRow(item: Record): unknown[] { + return [ + item.pod, + item.container, + item.ok === false ? "failed" : "ok", + item.degradedReason ?? "-", + item.lineCount, + item.bytes, + asOptionalRecord(item.nodeCicdTiming) === null ? "-" : "node-cicd-timing", + item.message ?? "-", + ]; +} + function containerRow(item: Record): unknown[] { const terminated = asOptionalRecord(item.terminated); const waiting = asOptionalRecord(item.waiting);