openclaw
Version:
Multi-channel AI gateway with extensible messaging integrations
205 lines (204 loc) • 8.46 kB
JavaScript
import { r as stripAnsi } from "./ansi-DrXAcdMD.js";
import { t as clearActiveProgressLine } from "./progress-line-DiTuCPbL.js";
import { n as loggingState } from "./state-UxwJeH7V.js";
import { p as redactSensitiveText } from "./redact-BtvPPfTi.js";
import { t as isVerbose } from "./global-state-BAD7XgmL.js";
import { n as formatTimestamp } from "./timestamps-CD_Oo5x3.js";
import { r as formatJsonConsoleLine } from "./json-console-line-C0Xvs26k.js";
import { r as normalizeLogLevel } from "./levels-qpAN12Fm.js";
import { l as readLoggerConfig, o as getLogger, v as resolveEnvLogLevelOverride } from "./logger-DK-iouVT.js";
import util from "node:util";
//#region src/logging/console.ts
function normalizeConsoleLevel(level) {
if (isVerbose()) return "debug";
if (!level && process.env.VITEST === "true" && process.env.OPENCLAW_TEST_CONSOLE !== "1") return "silent";
return normalizeLogLevel(level, "info");
}
function normalizeConsoleStyle(style) {
if (style === "compact" || style === "json" || style === "pretty") return style;
if (!process.stdout.isTTY) return "compact";
return "pretty";
}
function resolveConsoleSettings() {
const envLevel = resolveEnvLogLevelOverride();
if (process.env.VITEST === "true" && process.env.OPENCLAW_TEST_CONSOLE !== "1" && !isVerbose() && !envLevel && !loggingState.overrideSettings) return {
level: "silent",
style: normalizeConsoleStyle(void 0)
};
const cfg = loggingState.overrideSettings ?? readLoggerConfig();
return {
level: envLevel ?? normalizeConsoleLevel(cfg?.consoleLevel),
style: normalizeConsoleStyle(cfg?.consoleStyle)
};
}
function getConsoleSettings() {
const cached = loggingState.cachedConsoleSettings;
if (cached) return cached;
const settings = resolveConsoleSettings();
loggingState.cachedConsoleSettings = settings;
return loggingState.cachedConsoleSettings;
}
function getResolvedConsoleSettings() {
return getConsoleSettings();
}
function routeLogsToStderr() {
loggingState.forceConsoleToStderr = true;
}
function setConsoleSubsystemFilter(filters) {
if (!filters || filters.length === 0) {
loggingState.consoleSubsystemFilter = null;
return;
}
const normalized = filters.map((value) => value.trim()).filter((value) => value.length > 0);
loggingState.consoleSubsystemFilter = normalized.length > 0 ? normalized : null;
}
/** Hides subsystem console lines for TTY-owned work while preserving file logging. */
async function withConsoleSubsystemsSuppressed(work) {
const previousFilter = loggingState.consoleSubsystemFilter ? [...loggingState.consoleSubsystemFilter] : null;
setConsoleSubsystemFilter(["__openclaw_tui_quiet__"]);
try {
return await work();
} finally {
setConsoleSubsystemFilter(previousFilter);
}
}
function setConsoleTimestampPrefix(enabled) {
loggingState.consoleTimestampPrefix = enabled;
}
function normalizeConsoleSubsystem(subsystem) {
if (typeof subsystem !== "string") return null;
const normalized = subsystem.trim();
return normalized.length > 0 ? normalized : null;
}
function shouldLogSubsystemToConsole(subsystem) {
const filter = loggingState.consoleSubsystemFilter;
if (!filter || filter.length === 0) return true;
const normalizedSubsystem = normalizeConsoleSubsystem(subsystem);
if (!normalizedSubsystem) return false;
return filter.some((prefix) => normalizedSubsystem === prefix || normalizedSubsystem.startsWith(`${prefix}/`));
}
const SUPPRESSED_CONSOLE_PREFIXES = [
"Closing session:",
"Opening session:",
"Removing old closed session:",
"Session already closed",
"Session already open"
];
const NODE_PROCESS_WARNING_PREFIX = `(${process.release.name}:${process.pid}) `;
function shouldSuppressConsoleMessage(message) {
return SUPPRESSED_CONSOLE_PREFIXES.some((prefix) => message.startsWith(prefix));
}
function isEpipeError(err) {
const code = err?.code;
return code === "EPIPE" || code === "EIO";
}
function formatConsoleTimestamp(style) {
const now = /* @__PURE__ */ new Date();
if (style === "pretty") return formatTimestamp(now, { style: "short" }).replace(/[+-]\d{2}:\d{2}$/, "");
return formatTimestamp(now, { style: "long" });
}
function captureConsoleTraceStack(message, caller) {
const trace = new Error(message);
trace.name = "Trace";
Error.captureStackTrace(trace, caller);
return trace.stack === void 0 ? `Trace: ${message}` : typeof trace.stack === "string" ? trace.stack : util.format(trace.stack);
}
function hasTimestampPrefix(value) {
return /^(?:\d{2}:\d{2}:\d{2}|\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(?:\.\d+)?(?:Z|[+-]\d{2}:\d{2})?)/.test(value);
}
function writeFormattedConsoleOutput(params) {
const consoleStyle = getConsoleSettings().style;
const trimmed = consoleStyle !== "json" && loggingState.consoleTimestampPrefix ? stripAnsi(params.formatted).trimStart() : "";
const timestamp = trimmed && !hasTimestampPrefix(trimmed) ? formatConsoleTimestamp(consoleStyle) : "";
const stack = params.level === "trace" && params.caller ? captureConsoleTraceStack(params.formatted, params.caller) : void 0;
try {
const rendered = consoleStyle === "json" ? formatJsonConsoleLine({
level: params.level,
message: stripAnsi(params.formatted),
meta: stack === void 0 ? void 0 : { stack: stripAnsi(stack) }
}) : redactSensitiveText(stack ?? params.formatted);
const line = timestamp ? `${timestamp} ${rendered}` : rendered;
if (loggingState.forceConsoleToStderr) process.stderr.write(`${line}\n`);
else if (consoleStyle !== "json" && !timestamp && params.args.length === 0 && stack === void 0) params.write.apply(console, params.args);
else params.write.call(console, line);
} catch (err) {
if (isEpipeError(err)) return;
throw err;
}
}
/** Writes a root logger line to the pre-capture console sink without re-entering file capture. */
function writeRootConsoleLine(method, line) {
const rawConsole = loggingState.rawConsole;
if (!rawConsole) return false;
clearActiveProgressLine();
if (shouldSuppressConsoleMessage(line)) return true;
writeFormattedConsoleOutput({
level: method === "error" ? "error" : "info",
args: [line],
formatted: line,
write: rawConsole[method]
});
return true;
}
/**
* Route console.* calls through file logging while still emitting to stdout/stderr.
* This keeps user-facing output unchanged but guarantees every console call is captured in log files.
*/
function enableConsoleCapture() {
if (loggingState.consolePatched) return;
loggingState.consolePatched = true;
if (!loggingState.streamErrorHandlersInstalled) {
loggingState.streamErrorHandlersInstalled = true;
for (const stream of [process.stdout, process.stderr]) stream.on("error", (err) => {
if (isEpipeError(err)) {
const exitCode = process.exitCode;
process.exit(exitCode !== void 0 && exitCode !== 0 && exitCode !== "0" ? exitCode : 0);
return;
}
throw err;
});
}
const original = {
log: console.log,
info: console.info,
warn: console.warn,
error: console.error,
debug: console.debug
};
loggingState.rawConsole = {
log: original.log,
info: original.info,
warn: original.warn,
error: original.error
};
const forward = (level, orig) => {
const forwardedConsoleCall = (...args) => {
const formatted = util.format(...args);
let routedLevel = level;
if (level === "error" && formatted.startsWith(NODE_PROCESS_WARNING_PREFIX) && typeof util.getCallSites === "function") {
const caller = util.getCallSites(2, { sourceMap: false })[1];
if (caller?.functionName === "writeOut" && caller.scriptName === "node:internal/process/warning") routedLevel = "warn";
}
if (shouldSuppressConsoleMessage(formatted)) return;
try {
getLogger()[routedLevel](formatted);
} catch {}
writeFormattedConsoleOutput({
level: routedLevel,
args,
formatted,
write: orig,
caller: forwardedConsoleCall
});
};
return forwardedConsoleCall;
};
console.log = forward("info", original.log);
console.info = forward("info", original.info);
console.warn = forward("warn", original.warn);
console.error = forward("error", original.error);
console.debug = forward("debug", original.debug);
console.trace = forward("trace", original.error);
}
//#endregion
export { routeLogsToStderr as a, shouldLogSubsystemToConsole as c, getResolvedConsoleSettings as i, withConsoleSubsystemsSuppressed as l, formatConsoleTimestamp as n, setConsoleSubsystemFilter as o, getConsoleSettings as r, setConsoleTimestampPrefix as s, enableConsoleCapture as t, writeRootConsoleLine as u };