Logging
For a user-facing overview (CLI + Control UI + config), see /logging. OpenClaw has two log “surfaces”:- Console output (what you see in the terminal / Debug UI).
- File logs (JSON lines) written by the gateway logger.
File-based logger
- Default rolling log file is under
/tmp/openclaw/(one file per day):openclaw-YYYY-MM-DD.log- Date uses the gateway host’s local timezone.
- The log file path and level can be configured via
~/.openclaw/openclaw.json:logging.filelogging.levellogging.maxFileByteslogging.maxBackups
logs.tail).
CLI can do the same:
- File logs are controlled exclusively by
logging.level. --verboseonly affects console verbosity (and WS log style); it does not raise the file log level.- To capture verbose-only details in file logs, set
logging.leveltodebugortrace.
Rotation and resource controls
Gateway file logging is bounded by size rotation. The primary log uses:logging.maxFileBytes: active file cap in bytes. Default: 10 MB.logging.maxBackups: number of rotated backups to retain. Default: 5; use0to truncate without keeping backups.
logging.fileLogs:
file: profile file path. Some stateful logs intentionally ignore this to keep readers pointed at canonical paths.maxFileBytes: active file cap before rotation.maxBackups: retained backup count;0truncates without backups.compress:"gzip"orfalse.maxQueuedBytes: per-writer in-memory queue budget before new writes are dropped by non-strict writers.keepLines: visible-tail retention for logs that still expose legacy tail views, such as cron run logs.mode:"jsonl"or"text".
primary, cron.run, config.audit, hooks.command,
agents.rawStream, extensions.learningCore, and
extensions.voiceCall.calls. Sessions and conversations are not controlled by
logging.fileLogs; they use their own storage retention and maintenance
settings.
Console capture
The CLI capturesconsole.log/info/warn/error/debug/trace and writes them to file logs,
while still printing to stdout/stderr.
You can tune console verbosity independently via:
logging.consoleLevel(defaultinfo)logging.consoleStyle(pretty|compact|json)
Tool summary redaction
Verbose tool summaries (e.g.🛠️ Exec: ...) can mask sensitive tokens before they hit the
console stream. This is tools-only and does not alter file logs.
logging.redactSensitive:off|tools(default:tools)logging.redactPatterns: array of regex strings (overrides defaults)- Use raw regex strings (auto
gi), or/pattern/flagsif you need custom flags. - Matches are masked by keeping the first 6 + last 4 chars (length >= 18), otherwise
***. - Defaults cover common key assignments, CLI flags, JSON fields, bearer headers, PEM blocks, and popular token prefixes.
- Use raw regex strings (auto
Gateway WebSocket logs
The gateway prints WebSocket protocol logs in two modes:- Normal mode (no
--verbose): only “interesting” RPC results are printed:- errors (
ok=false) - slow calls (default threshold:
>= 50ms) - parse errors
- errors (
- Verbose mode (
--verbose): prints all WS request/response traffic.
WS log style
openclaw gateway supports a per-gateway style switch:
--ws-log auto(default): normal mode is optimized; verbose mode uses compact output--ws-log compact: compact output (paired request/response) when verbose--ws-log full: full per-frame output when verbose--compact: alias for--ws-log compact
Console formatting (subsystem logging)
The console formatter is TTY-aware and prints consistent, prefixed lines. Subsystem loggers keep output grouped and scannable. Behavior:-
Subsystem prefixes on every line (e.g.
[gateway],[canvas],[tailscale]) - Subsystem colors (stable per subsystem) plus level coloring
-
Color when output is a TTY or the environment looks like a rich terminal (
TERM/COLORTERM/TERM_PROGRAM), respectsNO_COLOR -
Shortened subsystem prefixes: drops leading
gateway/+channels/, keeps last 2 segments (e.g.whatsapp/outbound) -
Sub-loggers by subsystem (auto prefix + structured field
{ subsystem }) -
logRaw()for QR/UX output (no prefix, no formatting) -
Console styles (e.g.
pretty | compact | json) -
Structured metadata on
prettyandcompact(and therefore on journald, which captures the same stdout/stderr stream): a call such aslog.warn("recovery incident", { incidentKey: "session-restart:abc", kind: "restart", reasonCode: 2 })prints the message followed by a dimmedkey=valuesuffix, for example[gateway] recovery incident incidentKey=session-restart:abc kind=restart reasonCode=2. Bare-looking string values (letters, digits,_,.,/,:,@,+,-) print unquoted; anything else is JSON-quoted (for exampledetail="two words").undefined, functions, and symbols are omitted, matching thejsonconsole style and the JSONL file log. A value that cannot be serialized prints as"[unserializable]". Hostile metadata (throwing getters or Proxy traps) degrades to[meta unavailable]rather than throwing. Long values are truncated per key and across the whole suffix without splitting a UTF-16 surrogate pair. Treat structured metadata as operator-visible. Thejsonconsole style and the JSONL file log already carried these fields, butprettyandcompactare the default styles, so on those the fields now reach stdout/stderr and therefore journald. Nothing redacts them: the renderer writes the values it is given, and the tool-summary redaction described in Tool summary redaction covers tool output, not log metadata. Do not put secrets, tokens, or raw credentials in a log call’s metadata object; hash or truncate identifiers before logging them. -
Console log level separate from file log level (file keeps full detail when
logging.levelis set todebug/trace) -
WhatsApp message bodies are logged at
debug(use--verboseto see them)