fix: stabilize logging config imports

This commit is contained in:
Peter Steinberger 2026-03-24 17:20:44 +00:00
parent a1c91bdb75
commit 398d58fb8a
9 changed files with 98 additions and 45 deletions

View File

@ -13,7 +13,13 @@ import {
import { resolveUserPath } from "../utils.js";
import { normalizeSkillFilter } from "./skills/filter.js";
import { resolveDefaultAgentWorkspaceDir } from "./workspace.js";
const log = createSubsystemLogger("agent-scope");
let log: ReturnType<typeof createSubsystemLogger> | null = null;
function getLog(): ReturnType<typeof createSubsystemLogger> {
log ??= createSubsystemLogger("agent-scope");
return log;
}
/** Strip null bytes from paths to prevent ENOTDIR errors. */
function stripNullBytes(s: string): string {
@ -80,7 +86,7 @@ export function resolveDefaultAgentId(cfg: OpenClawConfig): string {
const defaults = agents.filter((agent) => agent?.default);
if (defaults.length > 1 && !defaultAgentWarned) {
defaultAgentWarned = true;
log.warn("Multiple agents marked default=true; using the first entry as default.");
getLog().warn("Multiple agents marked default=true; using the first entry as default.");
}
const chosen = (defaults[0] ?? agents[0])?.id?.trim();
return normalizeAgentId(chosen || DEFAULT_AGENT_ID);

View File

@ -23,7 +23,12 @@ import {
normalizeProviderIdForAuth,
} from "./provider-id.js";
const log = createSubsystemLogger("model-selection");
let log: ReturnType<typeof createSubsystemLogger> | null = null;
function getLog(): ReturnType<typeof createSubsystemLogger> {
log ??= createSubsystemLogger("model-selection");
return log;
}
export type ModelRef = {
provider: string;
@ -292,7 +297,7 @@ export function resolveConfiguredModelRef(params: {
// Default to anthropic if no provider is specified, but warn as this is deprecated.
const safeTrimmed = sanitizeForLog(trimmed);
log.warn(
getLog().warn(
`Model "${safeTrimmed}" specified without provider. Falling back to "anthropic/${safeTrimmed}". Please use "anthropic/${safeTrimmed}" in your config.`,
);
return { provider: "anthropic", model: trimmed };
@ -310,7 +315,9 @@ export function resolveConfiguredModelRef(params: {
// User specified a model but it could not be resolved — warn before falling back.
const safe = sanitizeForLog(trimmed);
const safeFallback = sanitizeForLog(`${params.defaultProvider}/${params.defaultModel}`);
log.warn(`Model "${safe}" could not be resolved. Falling back to default "${safeFallback}".`);
getLog().warn(
`Model "${safe}" could not be resolved. Falling back to default "${safeFallback}".`,
);
}
// Before falling back to the hardcoded default, check if the default provider
// is actually available. If it isn't but other providers are configured, prefer

View File

@ -6,7 +6,14 @@ import { FIELD_LABELS } from "./schema.labels.js";
import { applyDerivedTags } from "./schema.tags.js";
import { sensitive } from "./zod-schema.sensitive.js";
const log = createSubsystemLogger("config/schema");
let log: ReturnType<typeof createSubsystemLogger> | null = null;
function getLog(): ReturnType<typeof createSubsystemLogger> {
if (!log) {
log = createSubsystemLogger("config/schema");
}
return log;
}
export type { ConfigUiHint, ConfigUiHints } from "../shared/config-ui-hints-types.js";
@ -198,7 +205,7 @@ export function mapSensitivePaths(
if (isSensitive) {
next[path] = { ...next[path], sensitive: true };
} else if (isSensitiveConfigPath(path) && !next[path]?.sensitive) {
log.debug(`possibly sensitive key found: (${path})`);
getLog().debug(`possibly sensitive key found: (${path})`);
}
if (currentSchema instanceof z.ZodObject) {

18
src/global-state.ts Normal file
View File

@ -0,0 +1,18 @@
let globalVerbose = false;
let globalYes = false;
export function setVerbose(v: boolean) {
globalVerbose = v;
}
export function isVerbose() {
return globalVerbose;
}
export function setYes(v: boolean) {
globalYes = v;
}
export function isYes() {
return globalYes;
}

View File

@ -1,19 +1,10 @@
export { isVerbose, isYes, setVerbose, setYes } from "./global-state.js";
import { isVerbose } from "./global-state.js";
import { getLogger, isFileLogLevelEnabled } from "./logging/logger.js";
import { theme } from "./terminal/theme.js";
let globalVerbose = false;
let globalYes = false;
export function setVerbose(v: boolean) {
globalVerbose = v;
}
export function isVerbose() {
return globalVerbose;
}
export function shouldLogVerbose() {
return globalVerbose || isFileLogLevelEnabled("debug");
return isVerbose() || isFileLogLevelEnabled("debug");
}
export function logVerbose(message: string) {
@ -25,27 +16,19 @@ export function logVerbose(message: string) {
} catch {
// ignore logger failures to avoid breaking verbose printing
}
if (!globalVerbose) {
if (!isVerbose()) {
return;
}
console.log(theme.muted(message));
}
export function logVerboseConsole(message: string) {
if (!globalVerbose) {
if (!isVerbose()) {
return;
}
console.log(theme.muted(message));
}
export function setYes(v: boolean) {
globalYes = v;
}
export function isYes() {
return globalYes;
}
export const success = theme.success;
export const warn = theme.warn;
export const info = theme.info;

View File

@ -1,9 +1,16 @@
import { createSubsystemLogger } from "../logging/subsystem.js";
import { parseBooleanValue } from "../utils/boolean.js";
const log = createSubsystemLogger("env");
let log: ReturnType<typeof createSubsystemLogger> | null = null;
const loggedEnv = new Set<string>();
function getLog(): ReturnType<typeof createSubsystemLogger> {
if (!log) {
log = createSubsystemLogger("env");
}
return log;
}
type AcceptedEnvOption = {
key: string;
description: string;
@ -34,7 +41,9 @@ export function logAcceptedEnvOption(option: AcceptedEnvOption): void {
return;
}
loggedEnv.add(option.key);
log.info(`env: ${option.key}=${formatEnvValue(rawValue, option.redact)} (${option.description})`);
getLog().info(
`env: ${option.key}=${formatEnvValue(rawValue, option.redact)} (${option.description})`,
);
}
export function normalizeZaiEnv(): void {

View File

@ -1,6 +1,6 @@
import util from "node:util";
import type { OpenClawConfig } from "../config/types.js";
import { isVerbose } from "../globals.js";
import { isVerbose } from "../global-state.js";
import { stripAnsi } from "../terminal/ansi.js";
import { readLoggingConfig } from "./config.js";
import { resolveEnvLogLevelOverride } from "./env-log-level.js";

View File

@ -1,6 +1,6 @@
import { Chalk } from "chalk";
import type { Logger as TsLogger } from "tslog";
import { isVerbose } from "../globals.js";
import { isVerbose } from "../global-state.js";
import { defaultRuntime, type OutputRuntimeEnv, type RuntimeEnv } from "../runtime.js";
import { clearActiveProgressLine } from "../terminal/progress-line.js";
import {
@ -307,13 +307,13 @@ function logToFile(
export function createSubsystemLogger(subsystem: string): SubsystemLogger {
let fileLogger: TsLogger<LogObj> | null = null;
const getFileLogger = () => {
const getFileLogger = (): TsLogger<LogObj> => {
if (!fileLogger) {
fileLogger = getChildLogger({ subsystem });
}
return fileLogger;
};
const emit = (level: LogLevel, message: string, meta?: Record<string, unknown>) => {
const emit = (level: LogLevel, message: string, meta?: Record<string, unknown>): void => {
const consoleSettings = getConsoleSettings();
const consoleEnabled =
shouldLogToConsole(level, { level: consoleSettings.level }) &&
@ -366,11 +366,13 @@ export function createSubsystemLogger(subsystem: string): SubsystemLogger {
shouldLogSubsystemToConsole(subsystem)
);
};
const isFileEnabled = (level: LogLevel): boolean => isFileLogLevelEnabled(level);
const isFileEnabled = (level: LogLevel): boolean => {
return isFileLogLevelEnabled(level);
};
const logger: SubsystemLogger = {
subsystem,
isEnabled: (level, target = "any") => {
isEnabled(level, target = "any") {
if (target === "console") {
return isConsoleEnabled(level);
}
@ -379,13 +381,25 @@ export function createSubsystemLogger(subsystem: string): SubsystemLogger {
}
return isConsoleEnabled(level) || isFileEnabled(level);
},
trace: (message, meta) => emit("trace", message, meta),
debug: (message, meta) => emit("debug", message, meta),
info: (message, meta) => emit("info", message, meta),
warn: (message, meta) => emit("warn", message, meta),
error: (message, meta) => emit("error", message, meta),
fatal: (message, meta) => emit("fatal", message, meta),
raw: (message) => {
trace(message, meta) {
emit("trace", message, meta);
},
debug(message, meta) {
emit("debug", message, meta);
},
info(message, meta) {
emit("info", message, meta);
},
warn(message, meta) {
emit("warn", message, meta);
},
error(message, meta) {
emit("error", message, meta);
},
fatal(message, meta) {
emit("fatal", message, meta);
},
raw(message) {
if (isFileEnabled("info")) {
logToFile(getFileLogger(), "info", message, { raw: true });
}
@ -396,7 +410,9 @@ export function createSubsystemLogger(subsystem: string): SubsystemLogger {
writeConsoleLine("info", message);
}
},
child: (name) => createSubsystemLogger(`${subsystem}/${name}`),
child(name) {
return createSubsystemLogger(`${subsystem}/${name}`);
},
};
return logger;
}

View File

@ -0,0 +1,7 @@
declare module "@create-markdown/preview" {
export type PreviewThemeOptions = {
sanitize?: ((html: string) => string) | undefined;
};
export function applyPreviewTheme(html: string, options?: PreviewThemeOptions): string;
}