diff --git a/docs/help/environment.md b/docs/help/environment.md index 4ad054ebf73..e678ab957e4 100644 --- a/docs/help/environment.md +++ b/docs/help/environment.md @@ -82,6 +82,12 @@ See [Configuration: Env var substitution](/gateway/configuration#env-var-substit | `OPENCLAW_STATE_DIR` | Override the state directory (default `~/.openclaw`). | | `OPENCLAW_CONFIG_PATH` | Override the config file path (default `~/.openclaw/openclaw.json`). | +## Logging + +| Variable | Purpose | +| -------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `OPENCLAW_LOG_LEVEL` | Override log level for both file and console (e.g. `debug`, `trace`). Takes precedence over `logging.level` and `logging.consoleLevel` in config. Useful for temporary debugging or CI. | + ### `OPENCLAW_HOME` When set, `OPENCLAW_HOME` replaces the system home directory (`$HOME` / `os.homedir()`) for all internal path resolution. This enables full filesystem isolation for headless service accounts. diff --git a/docs/logging.md b/docs/logging.md index dafa1d878a5..0c22a54fef2 100644 --- a/docs/logging.md +++ b/docs/logging.md @@ -118,6 +118,8 @@ All logging configuration lives under `logging` in `~/.openclaw/openclaw.json`. - `logging.level`: **file logs** (JSONL) level. - `logging.consoleLevel`: **console** verbosity level. +You can override both via the **`OPENCLAW_LOG_LEVEL`** environment variable (e.g. `OPENCLAW_LOG_LEVEL=debug`). The env var takes precedence over the config file, so you can raise verbosity for a single run without editing `openclaw.json`. On `openclaw gateway run`, **`--log-level `** (e.g. `--log-level debug`) applies the same override for that process. + `--verbose` only affects console output; it does not change file log levels. ### Console styles diff --git a/src/cli/gateway-cli/run.ts b/src/cli/gateway-cli/run.ts index 74c8394b5e4..aec50de87c6 100644 --- a/src/cli/gateway-cli/run.ts +++ b/src/cli/gateway-cli/run.ts @@ -17,6 +17,8 @@ import { setVerbose } from "../../globals.js"; import { GatewayLockError } from "../../infra/gateway-lock.js"; import { formatPortDiagnostics, inspectPortUsage } from "../../infra/ports.js"; import { setConsoleSubsystemFilter, setConsoleTimestampPrefix } from "../../logging/console.js"; +import { normalizeLogLevel } from "../../logging/levels.js"; +import { setLoggerOverride } from "../../logging/logger.js"; import { createSubsystemLogger } from "../../logging/subsystem.js"; import { defaultRuntime } from "../../runtime.js"; import { formatCliCommand } from "../command-format.js"; @@ -50,6 +52,7 @@ type GatewayRunOpts = { rawStreamPath?: unknown; dev?: boolean; reset?: boolean; + logLevel?: string; }; const gatewayLog = createSubsystemLogger("gateway"); @@ -63,6 +66,7 @@ const GATEWAY_RUN_VALUE_KEYS = [ "tailscale", "wsLog", "rawStreamPath", + "logLevel", ] as const; const GATEWAY_RUN_BOOLEAN_KEYS = [ @@ -87,6 +91,15 @@ function resolveGatewayRunOptions(opts: GatewayRunOpts, command?: Command): Gate resolved[key] = inherited ?? resolved[key]; continue; } + if (key === "logLevel") { + resolved.logLevel = + typeof resolved.logLevel === "string" + ? resolved.logLevel + : typeof inherited === "string" + ? inherited + : undefined; + continue; + } resolved[key] = resolved[key] ?? inherited; } @@ -109,6 +122,11 @@ async function runGatewayCommand(opts: GatewayRunOpts) { setConsoleTimestampPrefix(true); setVerbose(Boolean(opts.verbose)); + const logLevelRaw = typeof opts.logLevel === "string" ? opts.logLevel.trim() : undefined; + if (logLevelRaw) { + const level = normalizeLogLevel(logLevelRaw, "info"); + setLoggerOverride({ level, consoleLevel: level }); + } if (opts.claudeCliLogs) { setConsoleSubsystemFilter(["agent/claude-cli"]); process.env.OPENCLAW_CLAUDE_CLI_LOG_OUTPUT = "1"; @@ -383,6 +401,10 @@ export function addGatewayRunCommand(cmd: Command): Command { false, ) .option("--force", "Kill any existing listener on the target port before starting", false) + .option( + "--log-level ", + "Log level for file and console (silent|fatal|error|warn|info|debug|trace)", + ) .option("--verbose", "Verbose logging to stdout/stderr", false) .option( "--claude-cli-logs", diff --git a/src/logging/console.ts b/src/logging/console.ts index ef57d5057fe..dc28c3abfe9 100644 --- a/src/logging/console.ts +++ b/src/logging/console.ts @@ -71,7 +71,10 @@ function resolveConsoleSettings(): ConsoleSettings { } } } - const level = normalizeConsoleLevel(cfg?.consoleLevel); + const envLevel = process.env.OPENCLAW_LOG_LEVEL?.trim(); + const level = envLevel + ? normalizeLogLevel(envLevel, "info") + : normalizeConsoleLevel(cfg?.consoleLevel); const style = normalizeConsoleStyle(cfg?.consoleStyle); return { level, style }; } diff --git a/src/logging/logger.ts b/src/logging/logger.ts index cfb920bac61..4a4d2b3ce44 100644 --- a/src/logging/logger.ts +++ b/src/logging/logger.ts @@ -67,7 +67,9 @@ function resolveSettings(): ResolvedSettings { } const defaultLevel = process.env.VITEST === "true" && process.env.OPENCLAW_TEST_FILE_LOG !== "1" ? "silent" : "info"; - const level = normalizeLogLevel(cfg?.level, defaultLevel); + const fromConfig = normalizeLogLevel(cfg?.level, defaultLevel); + const envLevel = process.env.OPENCLAW_LOG_LEVEL?.trim(); + const level = envLevel ? normalizeLogLevel(envLevel, fromConfig) : fromConfig; const file = cfg?.file ?? defaultRollingPathForToday(); return { level, file }; }