diff --git a/apps/fabro-web/app/routes/run-logs.tsx b/apps/fabro-web/app/routes/run-logs.tsx index 9bdf6cfb2..b363737fb 100644 --- a/apps/fabro-web/app/routes/run-logs.tsx +++ b/apps/fabro-web/app/routes/run-logs.tsx @@ -57,6 +57,7 @@ function renderBody(logsQuery: ReturnType) { function LogPanel({ text }: { text: string }) { const byteCount = new Blob([text]).size; + const lines = useMemo(() => text.split("\n"), [text]); return (
@@ -67,12 +68,60 @@ function LogPanel({ text }: { text: string }) {
-        {text}
+        {lines.map((line, i) => (
+          
+        ))}
       
); } +const LOG_LINE_RE = + /^(\S+)(\s+)(TRACE|DEBUG|INFO|WARN|ERROR)(\s+)(.*)$/; + +const LEVEL_COLOR: Record = { + ERROR: "text-coral", + WARN: "text-amber", + INFO: "text-teal-500", + DEBUG: "text-fg-3", + TRACE: "text-fg-muted", +}; + +function LogLine({ line, trailingNewline }: { line: string; trailingNewline: boolean }) { + const newline = trailingNewline ? "\n" : ""; + const match = LOG_LINE_RE.exec(line); + if (!match) { + return {line}{newline}; + } + const [, timestamp, gap1, level, gap2, rest] = match; + return ( + + {timestamp} + {gap1} + {level} + {gap2} + + {newline} + + ); +} + +const LOG_REST_RE = /^([a-zA-Z_][\w:]*):(\s+)(.*)$/; + +function LogRest({ text }: { text: string }) { + const match = LOG_REST_RE.exec(text); + if (!match) return <>{text}; + const [, target, gap, message] = match; + return ( + <> + {target} + : + {gap} + {message} + + ); +} + function errorMessage(error: unknown): string | undefined { return error instanceof Error ? error.message : undefined; }