mirror of
https://github.com/openclaw/openclaw.git
synced 2026-05-11 02:24:31 +00:00
perf(logging): skip config/fs work in default silent test path
This commit is contained in:
@@ -26,6 +26,7 @@ type ConsoleSnapshot = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
let originalIsTty: boolean | undefined;
|
let originalIsTty: boolean | undefined;
|
||||||
|
let originalOpenClawTestConsole: string | undefined;
|
||||||
let snapshot: ConsoleSnapshot;
|
let snapshot: ConsoleSnapshot;
|
||||||
let logging: typeof import("../logging.js");
|
let logging: typeof import("../logging.js");
|
||||||
let state: typeof import("./state.js");
|
let state: typeof import("./state.js");
|
||||||
@@ -46,6 +47,8 @@ beforeEach(() => {
|
|||||||
trace: console.trace,
|
trace: console.trace,
|
||||||
};
|
};
|
||||||
originalIsTty = process.stdout.isTTY;
|
originalIsTty = process.stdout.isTTY;
|
||||||
|
originalOpenClawTestConsole = process.env.OPENCLAW_TEST_CONSOLE;
|
||||||
|
process.env.OPENCLAW_TEST_CONSOLE = "1";
|
||||||
Object.defineProperty(process.stdout, "isTTY", { value: false, configurable: true });
|
Object.defineProperty(process.stdout, "isTTY", { value: false, configurable: true });
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -56,6 +59,11 @@ afterEach(() => {
|
|||||||
console.error = snapshot.error;
|
console.error = snapshot.error;
|
||||||
console.debug = snapshot.debug;
|
console.debug = snapshot.debug;
|
||||||
console.trace = snapshot.trace;
|
console.trace = snapshot.trace;
|
||||||
|
if (originalOpenClawTestConsole === undefined) {
|
||||||
|
delete process.env.OPENCLAW_TEST_CONSOLE;
|
||||||
|
} else {
|
||||||
|
process.env.OPENCLAW_TEST_CONSOLE = originalOpenClawTestConsole;
|
||||||
|
}
|
||||||
Object.defineProperty(process.stdout, "isTTY", { value: originalIsTty, configurable: true });
|
Object.defineProperty(process.stdout, "isTTY", { value: originalIsTty, configurable: true });
|
||||||
logging.setConsoleConfigLoaderForTests();
|
logging.setConsoleConfigLoaderForTests();
|
||||||
vi.restoreAllMocks();
|
vi.restoreAllMocks();
|
||||||
|
|||||||
@@ -58,6 +58,19 @@ function normalizeConsoleStyle(style?: string): ConsoleStyle {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function resolveConsoleSettings(): ConsoleSettings {
|
function resolveConsoleSettings(): ConsoleSettings {
|
||||||
|
const envLevel = resolveEnvLogLevelOverride();
|
||||||
|
// Test runs default to silent console logging unless explicitly overridden.
|
||||||
|
// Skip config-file and full config fallback reads in this fast path.
|
||||||
|
if (
|
||||||
|
process.env.VITEST === "true" &&
|
||||||
|
process.env.OPENCLAW_TEST_CONSOLE !== "1" &&
|
||||||
|
!isVerbose() &&
|
||||||
|
!envLevel &&
|
||||||
|
!loggingState.overrideSettings
|
||||||
|
) {
|
||||||
|
return { level: "silent", style: normalizeConsoleStyle(undefined) };
|
||||||
|
}
|
||||||
|
|
||||||
let cfg: OpenClawConfig["logging"] | undefined =
|
let cfg: OpenClawConfig["logging"] | undefined =
|
||||||
(loggingState.overrideSettings as LoggerSettings | null) ?? readLoggingConfig();
|
(loggingState.overrideSettings as LoggerSettings | null) ?? readLoggingConfig();
|
||||||
if (!cfg) {
|
if (!cfg) {
|
||||||
@@ -72,7 +85,6 @@ function resolveConsoleSettings(): ConsoleSettings {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
const envLevel = resolveEnvLogLevelOverride();
|
|
||||||
const level = envLevel ?? normalizeConsoleLevel(cfg?.consoleLevel);
|
const level = envLevel ?? normalizeConsoleLevel(cfg?.consoleLevel);
|
||||||
const style = normalizeConsoleStyle(cfg?.consoleStyle);
|
const style = normalizeConsoleStyle(cfg?.consoleStyle);
|
||||||
return { level, style };
|
return { level, style };
|
||||||
|
|||||||
66
src/logging/logger-settings.test.ts
Normal file
66
src/logging/logger-settings.test.ts
Normal file
@@ -0,0 +1,66 @@
|
|||||||
|
import { afterEach, beforeAll, beforeEach, describe, expect, it, vi } from "vitest";
|
||||||
|
|
||||||
|
const { fallbackRequireMock, readLoggingConfigMock } = vi.hoisted(() => ({
|
||||||
|
readLoggingConfigMock: vi.fn(() => undefined),
|
||||||
|
fallbackRequireMock: vi.fn(() => {
|
||||||
|
throw new Error("config fallback should not be used in this test");
|
||||||
|
}),
|
||||||
|
}));
|
||||||
|
|
||||||
|
vi.mock("./config.js", () => ({
|
||||||
|
readLoggingConfig: readLoggingConfigMock,
|
||||||
|
}));
|
||||||
|
|
||||||
|
vi.mock("./node-require.js", () => ({
|
||||||
|
resolveNodeRequireFromMeta: () => fallbackRequireMock,
|
||||||
|
}));
|
||||||
|
|
||||||
|
let originalTestFileLog: string | undefined;
|
||||||
|
let originalOpenClawLogLevel: string | undefined;
|
||||||
|
let logging: typeof import("../logging.js");
|
||||||
|
|
||||||
|
beforeAll(async () => {
|
||||||
|
logging = await import("../logging.js");
|
||||||
|
});
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
originalTestFileLog = process.env.OPENCLAW_TEST_FILE_LOG;
|
||||||
|
originalOpenClawLogLevel = process.env.OPENCLAW_LOG_LEVEL;
|
||||||
|
delete process.env.OPENCLAW_TEST_FILE_LOG;
|
||||||
|
delete process.env.OPENCLAW_LOG_LEVEL;
|
||||||
|
readLoggingConfigMock.mockClear();
|
||||||
|
fallbackRequireMock.mockClear();
|
||||||
|
logging.resetLogger();
|
||||||
|
logging.setLoggerOverride(null);
|
||||||
|
});
|
||||||
|
|
||||||
|
afterEach(() => {
|
||||||
|
if (originalTestFileLog === undefined) {
|
||||||
|
delete process.env.OPENCLAW_TEST_FILE_LOG;
|
||||||
|
} else {
|
||||||
|
process.env.OPENCLAW_TEST_FILE_LOG = originalTestFileLog;
|
||||||
|
}
|
||||||
|
if (originalOpenClawLogLevel === undefined) {
|
||||||
|
delete process.env.OPENCLAW_LOG_LEVEL;
|
||||||
|
} else {
|
||||||
|
process.env.OPENCLAW_LOG_LEVEL = originalOpenClawLogLevel;
|
||||||
|
}
|
||||||
|
logging.resetLogger();
|
||||||
|
logging.setLoggerOverride(null);
|
||||||
|
vi.restoreAllMocks();
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("getResolvedLoggerSettings", () => {
|
||||||
|
it("uses a silent fast path in default Vitest mode without config reads", () => {
|
||||||
|
const settings = logging.getResolvedLoggerSettings();
|
||||||
|
expect(settings.level).toBe("silent");
|
||||||
|
expect(readLoggingConfigMock).not.toHaveBeenCalled();
|
||||||
|
expect(fallbackRequireMock).not.toHaveBeenCalled();
|
||||||
|
});
|
||||||
|
|
||||||
|
it("reads logging config when test file logging is explicitly enabled", () => {
|
||||||
|
process.env.OPENCLAW_TEST_FILE_LOG = "1";
|
||||||
|
const settings = logging.getResolvedLoggerSettings();
|
||||||
|
expect(settings.level).toBe("info");
|
||||||
|
});
|
||||||
|
});
|
||||||
@@ -55,7 +55,27 @@ function attachExternalTransport(logger: TsLogger<LogObj>, transport: LogTranspo
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function canUseSilentVitestFileLogFastPath(envLevel: LogLevel | undefined): boolean {
|
||||||
|
return (
|
||||||
|
process.env.VITEST === "true" &&
|
||||||
|
process.env.OPENCLAW_TEST_FILE_LOG !== "1" &&
|
||||||
|
!envLevel &&
|
||||||
|
!loggingState.overrideSettings
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
function resolveSettings(): ResolvedSettings {
|
function resolveSettings(): ResolvedSettings {
|
||||||
|
const envLevel = resolveEnvLogLevelOverride();
|
||||||
|
// Test runs default file logs to silent. Skip config reads and fallback load in the
|
||||||
|
// common case to avoid pulling heavy config/schema stacks on startup.
|
||||||
|
if (canUseSilentVitestFileLogFastPath(envLevel)) {
|
||||||
|
return {
|
||||||
|
level: "silent",
|
||||||
|
file: defaultRollingPathForToday(),
|
||||||
|
maxFileBytes: DEFAULT_MAX_LOG_FILE_BYTES,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
let cfg: OpenClawConfig["logging"] | undefined =
|
let cfg: OpenClawConfig["logging"] | undefined =
|
||||||
(loggingState.overrideSettings as LoggerSettings | null) ?? readLoggingConfig();
|
(loggingState.overrideSettings as LoggerSettings | null) ?? readLoggingConfig();
|
||||||
if (!cfg) {
|
if (!cfg) {
|
||||||
@@ -73,7 +93,6 @@ function resolveSettings(): ResolvedSettings {
|
|||||||
const defaultLevel =
|
const defaultLevel =
|
||||||
process.env.VITEST === "true" && process.env.OPENCLAW_TEST_FILE_LOG !== "1" ? "silent" : "info";
|
process.env.VITEST === "true" && process.env.OPENCLAW_TEST_FILE_LOG !== "1" ? "silent" : "info";
|
||||||
const fromConfig = normalizeLogLevel(cfg?.level, defaultLevel);
|
const fromConfig = normalizeLogLevel(cfg?.level, defaultLevel);
|
||||||
const envLevel = resolveEnvLogLevelOverride();
|
|
||||||
const level = envLevel ?? fromConfig;
|
const level = envLevel ?? fromConfig;
|
||||||
const file = cfg?.file ?? defaultRollingPathForToday();
|
const file = cfg?.file ?? defaultRollingPathForToday();
|
||||||
const maxFileBytes = resolveMaxLogFileBytes(cfg?.maxFileBytes);
|
const maxFileBytes = resolveMaxLogFileBytes(cfg?.maxFileBytes);
|
||||||
@@ -99,6 +118,20 @@ export function isFileLogLevelEnabled(level: LogLevel): boolean {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function buildLogger(settings: ResolvedSettings): TsLogger<LogObj> {
|
function buildLogger(settings: ResolvedSettings): TsLogger<LogObj> {
|
||||||
|
const logger = new TsLogger<LogObj>({
|
||||||
|
name: "openclaw",
|
||||||
|
minLevel: levelToMinLevel(settings.level),
|
||||||
|
type: "hidden", // no ansi formatting
|
||||||
|
});
|
||||||
|
|
||||||
|
// Silent logging does not write files; skip all filesystem setup in this path.
|
||||||
|
if (settings.level === "silent") {
|
||||||
|
for (const transport of externalTransports) {
|
||||||
|
attachExternalTransport(logger, transport);
|
||||||
|
}
|
||||||
|
return logger;
|
||||||
|
}
|
||||||
|
|
||||||
fs.mkdirSync(path.dirname(settings.file), { recursive: true });
|
fs.mkdirSync(path.dirname(settings.file), { recursive: true });
|
||||||
// Clean up stale rolling logs when using a dated log filename.
|
// Clean up stale rolling logs when using a dated log filename.
|
||||||
if (isRollingPath(settings.file)) {
|
if (isRollingPath(settings.file)) {
|
||||||
@@ -106,11 +139,6 @@ function buildLogger(settings: ResolvedSettings): TsLogger<LogObj> {
|
|||||||
}
|
}
|
||||||
let currentFileBytes = getCurrentLogFileBytes(settings.file);
|
let currentFileBytes = getCurrentLogFileBytes(settings.file);
|
||||||
let warnedAboutSizeCap = false;
|
let warnedAboutSizeCap = false;
|
||||||
const logger = new TsLogger<LogObj>({
|
|
||||||
name: "openclaw",
|
|
||||||
minLevel: levelToMinLevel(settings.level),
|
|
||||||
type: "hidden", // no ansi formatting
|
|
||||||
});
|
|
||||||
|
|
||||||
logger.attachTransport((logObj: LogObj) => {
|
logger.attachTransport((logObj: LogObj) => {
|
||||||
try {
|
try {
|
||||||
|
|||||||
Reference in New Issue
Block a user