mirror of
https://github.com/openclaw/openclaw.git
synced 2026-08-20 01:21:41 -06:00
1f0c6a66a6
* fix(plugins): plugin loggers drop writes after the log level is raised at runtime The plugin runtime logging facade captured a single tslog child logger per getChildLogger() call. tslog snapshots a sublogger's min level at creation, so a long-lived plugin logger (e.g. a channel monitor that runs for the whole gateway session) kept dropping debug/verbose writes after the log level was raised at runtime, even though shouldLogVerbose()/isFileLogLevelEnabled() reported the new level. This made channels like Mattermost go dark while core subsystem loggers (which re-resolve per emit) kept logging. Resolve the child logger per call so it always reflects the current level, with a cheap isFileLogLevelEnabled pre-gate (skipped for explicit overrides) to avoid building a sublogger when the level is disabled. Fixes every channel that holds a long-lived monitor logger (mattermost, matrix, msteams, irc, nextcloud-talk) at the facade boundary with no plugin-code changes. * test(plugins): type runtime log-level mock --------- Co-authored-by: Alex Knight <15041791+amknight@users.noreply.github.com> Co-authored-by: Vincent Koc <vincentkoc@ieee.org>
50 lines
1.8 KiB
TypeScript
50 lines
1.8 KiB
TypeScript
// Runtime logging helpers route plugin runtime logs through OpenClaw verbosity controls.
|
|
import { shouldLogVerbose } from "../../globals.js";
|
|
import { getChildLogger, isFileLogLevelEnabled } from "../../logging.js";
|
|
import { normalizeLogLevel } from "../../logging/levels.js";
|
|
import type { PluginRuntime } from "./types.js";
|
|
|
|
function writeRuntimeLog(
|
|
log: (...args: unknown[]) => void,
|
|
message: string,
|
|
meta?: Record<string, unknown>,
|
|
): void {
|
|
if (meta && Object.keys(meta).length > 0) {
|
|
log(meta, message);
|
|
return;
|
|
}
|
|
log(message);
|
|
}
|
|
|
|
type RuntimeLogMethod = "debug" | "info" | "warn" | "error";
|
|
|
|
/** Creates the plugin runtime logging facade. */
|
|
export function createRuntimeLogging(): PluginRuntime["logging"] {
|
|
return {
|
|
shouldLogVerbose,
|
|
getChildLogger: (bindings, opts) => {
|
|
const overrideLevel = opts?.level ? normalizeLogLevel(opts.level) : undefined;
|
|
const childOpts = overrideLevel ? { level: overrideLevel } : undefined;
|
|
// Resolve the child logger per call: tslog snapshots a sublogger's min level at
|
|
// creation, so a long-lived plugin logger (e.g. a channel monitor) would keep
|
|
// dropping writes after the log level is raised at runtime even though
|
|
// shouldLogVerbose() reports the new level. Skip the pre-gate when an override is
|
|
// set since it may be more permissive than the current file level.
|
|
const emit =
|
|
(level: RuntimeLogMethod) => (message: string, meta?: Record<string, unknown>) => {
|
|
if (!overrideLevel && !isFileLogLevelEnabled(level)) {
|
|
return;
|
|
}
|
|
const logger = getChildLogger(bindings, childOpts);
|
|
writeRuntimeLog(logger[level].bind(logger), message, meta);
|
|
};
|
|
return {
|
|
debug: emit("debug"),
|
|
info: emit("info"),
|
|
warn: emit("warn"),
|
|
error: emit("error"),
|
|
};
|
|
},
|
|
};
|
|
}
|