Spaces:
Paused
Paused
File size: 4,023 Bytes
fb4d8fe | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 | import crypto from "node:crypto";
import os from "node:os";
import path from "node:path";
import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
import {
enableConsoleCapture,
resetLogger,
routeLogsToStderr,
setConsoleTimestampPrefix,
setLoggerOverride,
} from "../logging.js";
import { loggingState } from "./state.js";
type ConsoleSnapshot = {
log: typeof console.log;
info: typeof console.info;
warn: typeof console.warn;
error: typeof console.error;
debug: typeof console.debug;
trace: typeof console.trace;
};
let snapshot: ConsoleSnapshot;
beforeEach(() => {
snapshot = {
log: console.log,
info: console.info,
warn: console.warn,
error: console.error,
debug: console.debug,
trace: console.trace,
};
loggingState.consolePatched = false;
loggingState.forceConsoleToStderr = false;
loggingState.consoleTimestampPrefix = false;
loggingState.rawConsole = null;
resetLogger();
});
afterEach(() => {
console.log = snapshot.log;
console.info = snapshot.info;
console.warn = snapshot.warn;
console.error = snapshot.error;
console.debug = snapshot.debug;
console.trace = snapshot.trace;
loggingState.consolePatched = false;
loggingState.forceConsoleToStderr = false;
loggingState.consoleTimestampPrefix = false;
loggingState.rawConsole = null;
resetLogger();
setLoggerOverride(null);
vi.restoreAllMocks();
});
describe("enableConsoleCapture", () => {
it("swallows EIO from stderr writes", () => {
setLoggerOverride({ level: "info", file: tempLogPath() });
vi.spyOn(process.stderr, "write").mockImplementation(() => {
throw eioError();
});
routeLogsToStderr();
enableConsoleCapture();
expect(() => console.log("hello")).not.toThrow();
});
it("swallows EIO from original console writes", () => {
setLoggerOverride({ level: "info", file: tempLogPath() });
console.log = () => {
throw eioError();
};
enableConsoleCapture();
expect(() => console.log("hello")).not.toThrow();
});
it("prefixes console output with timestamps when enabled", () => {
setLoggerOverride({ level: "info", file: tempLogPath() });
const now = new Date("2026-01-17T18:01:02.000Z");
vi.useFakeTimers();
vi.setSystemTime(now);
const warn = vi.fn();
console.warn = warn;
setConsoleTimestampPrefix(true);
enableConsoleCapture();
console.warn("[EventQueue] Slow listener detected");
expect(warn).toHaveBeenCalledTimes(1);
const firstArg = String(warn.mock.calls[0]?.[0] ?? "");
expect(firstArg.startsWith("2026-01-17T18:01:02.000Z [EventQueue]")).toBe(true);
vi.useRealTimers();
});
it("suppresses discord EventQueue slow listener duplicates", () => {
setLoggerOverride({ level: "info", file: tempLogPath() });
const warn = vi.fn();
console.warn = warn;
enableConsoleCapture();
console.warn(
"[EventQueue] Slow listener detected: DiscordMessageListener took 12.3 seconds for event MESSAGE_CREATE",
);
expect(warn).not.toHaveBeenCalled();
});
it("does not double-prefix timestamps", () => {
setLoggerOverride({ level: "info", file: tempLogPath() });
const warn = vi.fn();
console.warn = warn;
setConsoleTimestampPrefix(true);
enableConsoleCapture();
console.warn("12:34:56 [exec] hello");
expect(warn).toHaveBeenCalledWith("12:34:56 [exec] hello");
});
it("leaves JSON output unchanged when timestamp prefix is enabled", () => {
setLoggerOverride({ level: "info", file: tempLogPath() });
const log = vi.fn();
console.log = log;
setConsoleTimestampPrefix(true);
enableConsoleCapture();
const payload = JSON.stringify({ ok: true });
console.log(payload);
expect(log).toHaveBeenCalledWith(payload);
});
});
function tempLogPath() {
return path.join(os.tmpdir(), `openclaw-log-${crypto.randomUUID()}.log`);
}
function eioError() {
const err = new Error("EIO") as NodeJS.ErrnoException;
err.code = "EIO";
return err;
}
|