fix(FN-2371): preserve log severity in dashboard TUI capture
- Add severity control markers to core and engine structured loggers while keeping info logs on stderr transport - Parse and strip internal severity markers in dashboard TUI console capture so logger.log entries render with info icons instead of error icons - Expand dashboard TUI tests to cover captured console severity mapping and structured logger behavior, plus logger unit tests in core/engine - Add a patch changeset for @runfusion/fusion describing the TUI log severity icon fix
This commit is contained in:
43
packages/core/src/logger.test.ts
Normal file
43
packages/core/src/logger.test.ts
Normal file
@@ -0,0 +1,43 @@
|
||||
import { describe, it, expect, vi, beforeEach, afterEach } from "vitest";
|
||||
import { createLogger } from "./logger.js";
|
||||
|
||||
describe("core createLogger", () => {
|
||||
let logSpy: ReturnType<typeof vi.spyOn>;
|
||||
let warnSpy: ReturnType<typeof vi.spyOn>;
|
||||
let errorSpy: ReturnType<typeof vi.spyOn>;
|
||||
|
||||
beforeEach(() => {
|
||||
logSpy = vi.spyOn(console, "log").mockImplementation(() => {});
|
||||
warnSpy = vi.spyOn(console, "warn").mockImplementation(() => {});
|
||||
errorSpy = vi.spyOn(console, "error").mockImplementation(() => {});
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
logSpy.mockRestore();
|
||||
warnSpy.mockRestore();
|
||||
errorSpy.mockRestore();
|
||||
});
|
||||
|
||||
it("emits info logs to stderr with an info severity marker", () => {
|
||||
const logger = createLogger("core-test");
|
||||
logger.log("hello");
|
||||
|
||||
expect(logSpy).not.toHaveBeenCalled();
|
||||
expect(errorSpy).toHaveBeenCalledWith("\u0000fnlvl=info\u0000[core-test] hello");
|
||||
});
|
||||
|
||||
it("emits warn logs with a warn severity marker", () => {
|
||||
const logger = createLogger("core-test");
|
||||
logger.warn("careful");
|
||||
|
||||
expect(warnSpy).toHaveBeenCalledWith("\u0000fnlvl=warn\u0000[core-test] careful");
|
||||
});
|
||||
|
||||
it("emits error logs with an error severity marker", () => {
|
||||
const logger = createLogger("core-test");
|
||||
const err = new Error("boom");
|
||||
logger.error("broken", err);
|
||||
|
||||
expect(errorSpy).toHaveBeenCalledWith("\u0000fnlvl=error\u0000[core-test] broken", err);
|
||||
});
|
||||
});
|
||||
@@ -20,6 +20,13 @@ export interface Logger {
|
||||
error(message: string, ...args: unknown[]): void;
|
||||
}
|
||||
|
||||
const LOG_LEVEL_MARKER_PREFIX = "\u0000fnlvl=";
|
||||
const LOG_LEVEL_MARKER_SUFFIX = "\u0000";
|
||||
|
||||
function withSeverityMarker(level: "info" | "warn" | "error", payload: string): string {
|
||||
return `${LOG_LEVEL_MARKER_PREFIX}${level}${LOG_LEVEL_MARKER_SUFFIX}${payload}`;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a structured logger that prefixes every message with `[prefix]`.
|
||||
*
|
||||
@@ -27,18 +34,22 @@ export interface Logger {
|
||||
* @returns A `Logger` whose output is prefixed and sent to stderr for normal
|
||||
* logs and errors. Keeping logs off stdout prevents command/test
|
||||
* output consumers from receiving Fusion execution chatter.
|
||||
*
|
||||
* The logger prepends an internal control-character severity marker
|
||||
* so dashboard TUI console-capture can preserve info/warn/error
|
||||
* semantics even when `log()` is transported via `console.error`.
|
||||
*/
|
||||
export function createLogger(prefix: string): Logger {
|
||||
const tag = `[${prefix}]`;
|
||||
return {
|
||||
log(message: string, ...args: unknown[]) {
|
||||
console.error(`${tag} ${message}`, ...args);
|
||||
console.error(withSeverityMarker("info", `${tag} ${message}`), ...args);
|
||||
},
|
||||
warn(message: string, ...args: unknown[]) {
|
||||
console.warn(`${tag} ${message}`, ...args);
|
||||
console.warn(withSeverityMarker("warn", `${tag} ${message}`), ...args);
|
||||
},
|
||||
error(message: string, ...args: unknown[]) {
|
||||
console.error(`${tag} ${message}`, ...args);
|
||||
console.error(withSeverityMarker("error", `${tag} ${message}`), ...args);
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user