openclaw
Version:
Multi-channel AI gateway with extensible messaging integrations
277 lines (276 loc) • 10.9 kB
JavaScript
import { a as normalizeLowercaseStringOrEmpty } from "./string-coerce-mnp54Vah.js";
import { c as redactSensitiveText } from "./redact-DduLliKq.js";
import { t as clearActiveProgressLine } from "./progress-line-DiTuCPbL.js";
import { n as defaultRuntime } from "./runtime-B4lgFmsS.js";
import { t as isVerbose } from "./global-state-BAD7XgmL.js";
import { g as levelToMinLevel, o as isFileLogLevelEnabled, r as getChildLogger } from "./logger-Brhy0cvC.js";
import { t as loggingState } from "./state-CHRYWIGY.js";
import { l as shouldLogSubsystemToConsole, n as formatConsoleTimestamp, r as getConsoleSettings } from "./console-BOsG6sD1.js";
import { Chalk } from "chalk";
//#region src/logging/subsystem.ts
function normalizeSubsystemLabel(subsystem) {
if (typeof subsystem !== "string") return "unknown";
const normalized = subsystem.trim();
return normalized.length > 0 ? normalized : "unknown";
}
function shouldLogToConsole(level, settings) {
if (level === "silent") return false;
if (settings.level === "silent") return false;
return levelToMinLevel(level) >= levelToMinLevel(settings.level);
}
const inspectValue = (() => {
const getBuiltinModule = process.getBuiltinModule;
if (typeof getBuiltinModule !== "function") return null;
try {
const utilNamespace = getBuiltinModule("util");
return typeof utilNamespace.inspect === "function" ? utilNamespace.inspect : null;
} catch {
return null;
}
})();
function formatRuntimeArg(arg) {
if (typeof arg === "string") return arg;
if (inspectValue) return inspectValue(arg);
try {
return JSON.stringify(arg);
} catch {
return String(arg);
}
}
function isRichConsoleEnv() {
const term = normalizeLowercaseStringOrEmpty(process.env.TERM);
if (process.env.COLORTERM || process.env.TERM_PROGRAM) return true;
return term.length > 0 && term !== "dumb";
}
function getColorForConsole() {
const hasForceColor = typeof process.env.FORCE_COLOR === "string" && process.env.FORCE_COLOR.trim().length > 0 && process.env.FORCE_COLOR.trim() !== "0";
if (hasForceColor) return new Chalk({ level: 1 });
if (process.env.NO_COLOR && !hasForceColor) return new Chalk({ level: 0 });
return process.stdout.isTTY || process.stderr.isTTY || isRichConsoleEnv() ? new Chalk({ level: 1 }) : new Chalk({ level: 0 });
}
const SUBSYSTEM_COLORS = [
"cyan",
"green",
"yellow",
"blue",
"magenta",
"red"
];
const SUBSYSTEM_COLOR_OVERRIDES = { "gmail-watcher": "blue" };
const SUBSYSTEM_PREFIXES_TO_DROP = [
"gateway",
"channels",
"providers"
];
const SUBSYSTEM_MAX_SEGMENTS = 2;
const CHANNEL_SUBSYSTEM_PREFIXES = new Set([
"clickclack",
"discord",
"feishu",
"googlechat",
"imessage",
"irc",
"line",
"matrix",
"mattermost",
"msteams",
"nextcloud-talk",
"nostr",
"openclaw-weixin",
"qqbot",
"signal",
"slack",
"synology-chat",
"telegram",
"tlon",
"twitch",
"webchat",
"wecom",
"whatsapp",
"yuanbao",
"zalo",
"zalouser"
]);
function isChannelSubsystemPrefix(value) {
const normalized = normalizeLowercaseStringOrEmpty(value);
if (!normalized) return false;
return CHANNEL_SUBSYSTEM_PREFIXES.has(normalized);
}
function pickSubsystemColor(color, subsystem) {
const override = SUBSYSTEM_COLOR_OVERRIDES[subsystem];
if (override) return color[override];
let hash = 0;
for (let i = 0; i < subsystem.length; i += 1) hash = hash * 31 + subsystem.charCodeAt(i) | 0;
return color[SUBSYSTEM_COLORS[Math.abs(hash) % SUBSYSTEM_COLORS.length]];
}
function formatSubsystemForConsole(subsystem) {
const parts = subsystem.split("/").filter(Boolean);
const original = parts.join("/") || subsystem;
while (parts.length > 0 && SUBSYSTEM_PREFIXES_TO_DROP.includes(parts[0])) parts.shift();
if (parts.length === 0) return original;
if (isChannelSubsystemPrefix(parts[0])) return parts[0];
if (parts.length > SUBSYSTEM_MAX_SEGMENTS) return parts.slice(-2).join("/");
return parts.join("/");
}
function stripRedundantSubsystemPrefixForConsole(message, displaySubsystem) {
if (!displaySubsystem) return message;
if (message.startsWith("[")) {
const closeIdx = message.indexOf("]");
if (closeIdx > 1) {
if (normalizeLowercaseStringOrEmpty(message.slice(1, closeIdx)) === normalizeLowercaseStringOrEmpty(displaySubsystem)) {
let i = closeIdx + 1;
while (message[i] === " ") i += 1;
return message.slice(i);
}
}
}
if (normalizeLowercaseStringOrEmpty(message.slice(0, displaySubsystem.length)) !== normalizeLowercaseStringOrEmpty(displaySubsystem)) return message;
const next = message.slice(displaySubsystem.length, displaySubsystem.length + 1);
if (next !== ":" && next !== " ") return message;
let i = displaySubsystem.length;
while (message[i] === " ") i += 1;
if (message[i] === ":") i += 1;
while (message[i] === " ") i += 1;
return message.slice(i);
}
function formatConsoleLine(opts) {
const displaySubsystem = opts.style === "json" ? opts.subsystem : formatSubsystemForConsole(opts.subsystem);
if (opts.style === "json") return redactSensitiveText(JSON.stringify({
time: formatConsoleTimestamp("json"),
level: opts.level,
subsystem: displaySubsystem,
message: opts.message,
...opts.meta
}));
const color = getColorForConsole();
const prefix = `[${displaySubsystem}]`;
const prefixColor = pickSubsystemColor(color, displaySubsystem);
const levelColor = opts.level === "error" || opts.level === "fatal" ? color.red : opts.level === "warn" ? color.yellow : opts.level === "debug" || opts.level === "trace" ? color.gray : color.cyan;
const displayMessage = stripRedundantSubsystemPrefixForConsole(redactSensitiveText(opts.message), displaySubsystem);
return `${[(() => {
if (opts.style === "pretty") return color.gray(formatConsoleTimestamp("pretty"));
if (loggingState.consoleTimestampPrefix) return color.gray(formatConsoleTimestamp(opts.style));
return "";
})(), prefixColor(prefix)].filter(Boolean).join(" ")} ${levelColor(displayMessage)}`;
}
function writeConsoleLine(level, line, opts = {}) {
clearActiveProgressLine();
const sanitized = process.platform === "win32" && process.env.GITHUB_ACTIONS === "true" ? line.replace(/[\uD800-\uDBFF][\uDC00-\uDFFF]/g, "?").replace(/[\uD800-\uDFFF]/g, "?") : line;
const redacted = opts.redacted ? sanitized : redactSensitiveText(sanitized);
const sink = loggingState.rawConsole ?? console;
if (loggingState.forceConsoleToStderr || level === "error" || level === "fatal") (sink.error ?? console.error)(redacted);
else if (level === "warn") (sink.warn ?? console.warn)(redacted);
else (sink.log ?? console.log)(redacted);
}
function shouldSuppressProbeConsoleLine(params) {
if (isVerbose()) return false;
if (params.level === "error" || params.level === "fatal") return false;
const subsystem = normalizeSubsystemLabel(params.subsystem);
const message = typeof params.message === "string" ? params.message : "";
if (!(subsystem === "agent/embedded" || subsystem.startsWith("agent/embedded/") || subsystem === "model-fallback" || subsystem.startsWith("model-fallback/"))) return false;
if ((typeof params.meta?.runId === "string" ? params.meta.runId : typeof params.meta?.sessionId === "string" ? params.meta.sessionId : void 0)?.startsWith("probe-")) return true;
return /(sessionId|runId)=probe-/.test(message);
}
function logToFile(fileLogger, level, message, meta) {
if (level === "silent") return;
const method = fileLogger[level];
if (typeof method !== "function") return;
if (meta && Object.keys(meta).length > 0) method.call(fileLogger, meta, message);
else method.call(fileLogger, message);
}
function createSubsystemLogger(subsystem) {
const resolvedSubsystem = normalizeSubsystemLabel(subsystem);
const emitLog = (level, message, meta) => {
const consoleSettings = getConsoleSettings();
const consoleEnabled = shouldLogToConsole(level, { level: consoleSettings.level }) && shouldLogSubsystemToConsole(resolvedSubsystem);
const fileEnabled = isFileLogLevelEnabled(level);
if (!consoleEnabled && !fileEnabled) return;
let consoleMessageOverride;
let fileMeta = meta;
if (meta && Object.keys(meta).length > 0) {
const { consoleMessage, ...rest } = meta;
if (typeof consoleMessage === "string") consoleMessageOverride = consoleMessage;
fileMeta = Object.keys(rest).length > 0 ? rest : void 0;
}
if (fileEnabled) logToFile(getChildLogger({ subsystem: resolvedSubsystem }), level, message, fileMeta);
if (!consoleEnabled) return;
const consoleMessage = consoleMessageOverride ?? message;
if (shouldSuppressProbeConsoleLine({
level,
subsystem: resolvedSubsystem,
message: consoleMessage,
meta: fileMeta
})) return;
writeConsoleLine(level, formatConsoleLine({
level,
subsystem: resolvedSubsystem,
message: consoleSettings.style === "json" ? message : consoleMessage,
style: consoleSettings.style,
meta: fileMeta
}), { redacted: true });
};
return {
subsystem: resolvedSubsystem,
isEnabled(level, target = "any") {
const isConsoleEnabled = shouldLogToConsole(level, { level: getConsoleSettings().level }) && shouldLogSubsystemToConsole(resolvedSubsystem);
const isFileEnabled = isFileLogLevelEnabled(level);
if (target === "console") return isConsoleEnabled;
if (target === "file") return isFileEnabled;
return isConsoleEnabled || isFileEnabled;
},
trace(message, meta) {
emitLog("trace", message, meta);
},
debug(message, meta) {
emitLog("debug", message, meta);
},
info(message, meta) {
emitLog("info", message, meta);
},
warn(message, meta) {
emitLog("warn", message, meta);
},
error(message, meta) {
emitLog("error", message, meta);
},
fatal(message, meta) {
emitLog("fatal", message, meta);
},
raw(message) {
if (isFileLogLevelEnabled("info")) logToFile(getChildLogger({ subsystem: resolvedSubsystem }), "info", message, { raw: true });
if (shouldLogToConsole("info", { level: getConsoleSettings().level }) && shouldLogSubsystemToConsole(resolvedSubsystem)) {
if (shouldSuppressProbeConsoleLine({
level: "info",
subsystem: resolvedSubsystem,
message
})) return;
writeConsoleLine("info", message);
}
},
child(name) {
return createSubsystemLogger(`${resolvedSubsystem}/${name}`);
}
};
}
function runtimeForLogger(logger, exit = defaultRuntime.exit) {
return {
log(...args) {
logger.info(args.map((arg) => formatRuntimeArg(arg)).join(" ").trim());
},
error(...args) {
logger.error(args.map((arg) => formatRuntimeArg(arg)).join(" ").trim());
},
writeStdout(value) {
logger.info(value);
},
writeJson(value, space = 2) {
logger.info(JSON.stringify(value, null, space > 0 ? space : void 0));
},
exit
};
}
function createSubsystemRuntime(subsystem, exit = defaultRuntime.exit) {
return runtimeForLogger(createSubsystemLogger(subsystem), exit);
}
//#endregion
export { stripRedundantSubsystemPrefixForConsole as i, createSubsystemRuntime as n, runtimeForLogger as r, createSubsystemLogger as t };