Logging
OpenClaw logs in two places:
- File logs (JSON lines) written by the Gateway.
- Console output shown in terminals and the Control UI.
This page explains where logs live, how to read them, and how to configure log
levels, formats, rotation, and retention.
Where logs live
By default, the Gateway writes a rolling log file under:
/tmp/openclaw/openclaw-YYYY-MM-DD.log
The date uses the gateway host’s local timezone.
Note: /tmp is periodically purged by the OS. For persistent log retention, use openclaw logs --follow for live output, or override the log path to a stable location such as ~/.openclaw/logs/openclaw.log.
You can override this in ~/.openclaw/openclaw.json:
How to read logs
CLI: live tail (recommended)
Use the CLI to tail the gateway log file via RPC:
Output modes:
- TTY sessions: pretty, colorized, structured log lines.
- Non-TTY sessions: plain text.
--json: line-delimited JSON (one log event per line).
--plain: force plain text in TTY sessions.
--no-color: disable ANSI colors.
In JSON mode, the CLI emits type-tagged objects:
meta: stream metadata (file, cursor, size)
log: parsed log entry
notice: truncation / rotation hints
raw: unparsed log line
If the Gateway is unreachable, the CLI prints a short hint to run:
Control UI (web)
The Control UI’s Logs tab tails the same file using logs.tail.
See /web/control-ui for how to open it.
Channel-only logs
To filter channel activity (WhatsApp/Telegram/etc), use:
File logs (JSONL)
Each line in the log file is a JSON object. The CLI and Control UI parse these
entries to render structured output (time, level, subsystem, message).
Rotation and retention
The main Gateway file log rotates before an append would push the active file
over logging.maxFileBytes. Defaults are:
logging.maxFileBytes: 10485760 bytes (10 MB)
logging.maxBackups: 5
- Backup compression: gzip
When rotation happens, the active file is moved to .1.gz, older backups move
to higher numbers, and backups beyond the retention count are deleted. If
logging.maxBackups is 0, WednesdayAI truncates the active file at rotation
time and keeps no backup.
Other durable diagnostic and audit logs use the same shared file-log controls
through logging.fileLogs. These controls do not apply to session transcripts
or conversation storage.
Console output
Console logs are TTY-aware and formatted for readability:
- Subsystem prefixes (e.g.
gateway/channels/whatsapp)
- Level coloring (info/warn/error)
- Optional compact or JSON mode
Console formatting is controlled by logging.consoleStyle.
Configuring logging
All logging configuration lives under logging in ~/.openclaw/openclaw.json.
Log levels
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. You can also pass the global CLI option --log-level <level> (for example, openclaw --log-level debug gateway run), which overrides the environment variable for that command.
--verbose only affects console output; it does not change file log levels.
File-log limits
Use logging.fileLogs.defaults to set a global budget for durable file logs
outside sessions and conversations. Use logging.fileLogs.profiles when one log
needs a tighter or looser policy.
Common built-in profile ids:
primary: the main Gateway log.
cron.run: cron run JSONL logs.
config.audit: config write audit records.
hooks.command: bundled command logger output.
agents.rawStream: raw-stream diagnostic JSONL.
agents.modelPayload: model payload debug log JSONL (off by default; see below).
agents.cacheTrace: cache-trace debug JSONL.
extensions.learningCore: learning-core JSONL records.
extensions.voiceCall.calls: voice-call legacy call records.
For path-indexed logs such as cron.run, extensions.learningCore, and
extensions.voiceCall.calls, the file profile field is ignored so readers and
recovery paths keep using the canonical log path. Tune their size, backup,
compression, queue, and line-retention fields instead.
Console styles
logging.consoleStyle:
pretty: human-friendly, colored, with timestamps.
compact: tighter output (best for long sessions).
json: JSON per line (for log processors).
On pretty and compact (the defaults), structured metadata passed with a log
call is appended as a dimmed key=value suffix after the message, so it reaches
stdout/stderr and journald — for example
[gateway] recovery incident incidentKey=session-restart:abc kind=restart reasonCode=2.
Bare-looking strings print unquoted; anything else is JSON-quoted
(detail="two words"). undefined, functions, and symbols are omitted. An
unserializable value prints "[unserializable]". Hostile metadata 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.
The json console style and the JSONL file log already emitted these fields. On
json, each line is one object carrying time, level, subsystem, and
message alongside the metadata fields, and those four envelope fields always
win: metadata using the same key cannot overwrite what a log shipper routes on.
Formatting details are also in Gateway logging.
These fields are now operator-visible on the default styles. Nothing redacts
them, and the tool-summary redaction below covers tool output, not log metadata.
Do not put secrets, tokens, or raw credentials in a log call’s metadata.
Redaction
Tool summaries can redact sensitive tokens before they hit the console:
logging.redactSensitive: off | tools (default: tools)
logging.redactPatterns: list of regex strings to override the default set
Redaction affects console output only and does not alter file logs.
Model payload logging (debug escape hatch)
diagnostics.modelPayloadLog is an off-by-default, bounded, rotating local capture of model
request payloads, written through logging.fileLogs (profile agents.modelPayload).
It is a short-lived debugging tool, not a telemetry path. For tokens, cost, latency, and spans use
diagnostics OpenTelemetry / Langfuse (below) — those are the supported, production-grade signals.
Enable payload logging only while reproducing a provider-side payload bug, then turn it off.
Safe by default, in layers:
- Off unless
enabled: true. With no config and no env var, nothing is written and no file is created.
- When
enabled: true, only provider-neutral usage summaries (tokens, latency, provider/model)
are written, never message content.
- Raw request bodies require a second explicit flag,
rawPayloads: true. Even then content is
redacted via the shared redactor, and sections are stripped unless captureContent opts them in
(the system prompt stays off even when captureContent is true).
usageSummaries (default true): write usage/cost/latency summary events when enabled.
rawPayloads (default false): the separate opt-in for full request bodies.
captureContent (default false): true for a default set, or an object to gate per type
(inputMessages, outputMessages, toolInputs, toolOutputs, systemPrompt, toolDefinitions).
providers (default all): optional allowlist; when non-empty, only listed providers are logged.
file (default $OPENCLAW_STATE_DIR/logs/model-payload.jsonl): JSONL output path.
maxQueuedBytes: hard cap on in-memory queued bytes before entries are dropped (with a throttled
warning). Rotation, retention, and compression follow the agents.modelPayload profile and the
logging.fileLogs controls above.
Environment overrides (config takes precedence): OPENCLAW_MODEL_PAYLOAD_LOG and
OPENCLAW_MODEL_PAYLOAD_LOG_FILE. The older OPENCLAW_ANTHROPIC_PAYLOAD_LOG[_FILE] names are
deprecated aliases, still honoured with a one-time deprecation warning.
Diagnostics + OpenTelemetry
Diagnostics are structured, machine-readable events for model runs and
message-flow telemetry (webhooks, queueing, session state). They do not
replace logs; they exist to feed metrics, traces, and other exporters.
Diagnostics events are emitted in-process, but exporters only attach when
diagnostics + the exporter plugin are enabled.
OpenTelemetry vs OTLP
- OpenTelemetry (OTel): the data model + SDKs for traces, metrics, and logs.
- OTLP: the wire protocol used to export OTel data to a collector/backend.
- OpenClaw exports via OTLP/HTTP (protobuf) today.
Signals exported
- Metrics: counters + histograms (token usage, message flow, queueing).
- Traces: spans for model usage + webhook/message processing.
- Logs: exported over OTLP when
diagnostics.otel.logs is enabled. Log
volume can be high; keep logging.level and exporter filters in mind.
Diagnostic event catalog
Model usage:
model.usage: tokens, cost, duration, context, provider/model/channel, session ids.
Message flow:
webhook.received: webhook ingress per channel.
webhook.processed: webhook handled + duration.
webhook.error: webhook handler errors.
message.queued: message enqueued for processing.
message.processed: outcome + duration + optional error.
Queue + session:
queue.lane.enqueue: command queue lane enqueue + depth/active/queued counts.
queue.lane.dequeue: command queue lane dequeue + wait time and depth/active/queued counts.
queue.lane.task.completed: command queue lane task completion with duration and outcome.
session.state: session state transition + reason.
session.stuck: session stuck warning + age.
run.attempt: run retry/attempt metadata.
diagnostic.heartbeat: aggregate counters (webhooks/queue/session).
Enable diagnostics (no exporter)
Use this if you want diagnostics events available to plugins or custom sinks:
Diagnostics flags (targeted logs)
Use flags to turn on extra, targeted debug logs without raising logging.level.
Flags are case-insensitive and support wildcards (e.g. telegram.* or *).
Env override (one-off):
Notes:
- Flag logs go to the standard log file (same as
logging.file).
- Output is still redacted according to
logging.redactSensitive.
- Full guide: /diagnostics/flags.
Export to OpenTelemetry
Diagnostics can be exported via the diagnostics-otel plugin (OTLP/HTTP). This
works with any OpenTelemetry collector/backend that accepts OTLP/HTTP.
Notes:
- You can also enable the plugin with
openclaw plugins enable diagnostics-otel.
protocol currently supports http/protobuf only. grpc is ignored.
- Metrics include token usage, cost, context size, run duration, and message-flow
counters/histograms (webhooks, queueing, session state, queue depth/wait, lane
active/queued/duration pressure).
- Traces/metrics can be toggled with
traces / metrics (default: on). Traces
include model usage spans plus webhook/message processing spans when enabled.
- Set
headers when your collector requires auth.
- Environment variables supported:
OTEL_EXPORTER_OTLP_ENDPOINT,
OTEL_EXPORTER_OTLP_TRACES_ENDPOINT, OTEL_EXPORTER_OTLP_METRICS_ENDPOINT,
OTEL_EXPORTER_OTLP_LOGS_ENDPOINT, OTEL_SERVICE_NAME,
OTEL_EXPORTER_OTLP_PROTOCOL, and OTEL_SDK_DISABLED.
Exported metrics (names + types)
Model usage:
openclaw.tokens (counter, attrs: openclaw.token, openclaw.channel,
openclaw.provider, openclaw.model)
openclaw.cost.usd (counter, attrs: openclaw.channel, openclaw.provider,
openclaw.model)
openclaw.run.duration_ms (histogram, attrs: openclaw.channel,
openclaw.provider, openclaw.model)
openclaw.context.tokens (histogram, attrs: openclaw.context,
openclaw.channel, openclaw.provider, openclaw.model)
Message flow:
openclaw.webhook.received (counter, attrs: openclaw.channel,
openclaw.webhook)
openclaw.webhook.error (counter, attrs: openclaw.channel,
openclaw.webhook)
openclaw.webhook.duration_ms (histogram, attrs: openclaw.channel,
openclaw.webhook)
openclaw.message.queued (counter, attrs: openclaw.channel,
openclaw.source)
openclaw.message.processed (counter, attrs: openclaw.channel,
openclaw.outcome)
openclaw.message.duration_ms (histogram, attrs: openclaw.channel,
openclaw.outcome)
Queues + sessions:
openclaw.queue.lane.enqueue (counter, attrs: openclaw.lane)
openclaw.queue.lane.dequeue (counter, attrs: openclaw.lane)
openclaw.queue.lane.task.completed (counter, attrs: openclaw.lane,
openclaw.outcome)
openclaw.queue.lane.active (histogram, attrs: openclaw.lane)
openclaw.queue.lane.queued (histogram, attrs: openclaw.lane)
openclaw.queue.lane.duration_ms (histogram, attrs: openclaw.lane,
openclaw.outcome)
openclaw.queue.depth (histogram, attrs: openclaw.lane or
openclaw.channel=heartbeat)
openclaw.queue.wait_ms (histogram, attrs: openclaw.lane)
openclaw.session.state (counter, attrs: openclaw.state, openclaw.reason)
openclaw.session.stuck (counter, attrs: openclaw.state)
openclaw.session.stuck_age_ms (histogram, attrs: openclaw.state)
openclaw.run.attempt (counter, attrs: openclaw.attempt)
Exported spans (names + key attributes)
openclaw.model.usage
openclaw.channel, openclaw.provider, openclaw.model
openclaw.sessionKey, openclaw.sessionId
openclaw.tokens.* (input/output/cache_read/cache_write/total)
openclaw.webhook.processed
openclaw.channel, openclaw.webhook, openclaw.chatId
openclaw.webhook.error
openclaw.channel, openclaw.webhook, openclaw.chatId,
openclaw.error
openclaw.message.processed
openclaw.channel, openclaw.outcome, openclaw.chatId,
openclaw.messageId, openclaw.sessionKey, openclaw.sessionId,
openclaw.reason
openclaw.session.stuck
openclaw.state, openclaw.ageMs, openclaw.queueDepth,
openclaw.sessionKey, openclaw.sessionId
Sampling + flushing
- Trace sampling:
diagnostics.otel.sampleRate (0.0–1.0, root spans only).
- Metric export interval:
diagnostics.otel.flushIntervalMs (min 1000ms).
Protocol notes
- OTLP/HTTP endpoints can be set via
diagnostics.otel.endpoint or
OTEL_EXPORTER_OTLP_ENDPOINT.
- Per-signal OTLP/HTTP endpoints can be set with
diagnostics.otel.tracesEndpoint,
diagnostics.otel.metricsEndpoint, and diagnostics.otel.logsEndpoint; matching
OTEL_EXPORTER_OTLP_*_ENDPOINT variables can also override signal routing.
- If the endpoint already contains
/v1/traces or /v1/metrics, it is used as-is.
- If the endpoint already contains
/v1/logs, it is used as-is for logs.
diagnostics.otel.logs enables OTLP log export for the main logger output.
- At gateway startup,
diagnostics-otel logs a redacted exporter summary with
resolved signal URLs, header presence, OTEL_SDK_DISABLED, preloaded SDK state,
and whether the NodeSDK started. Use that line to distinguish “no traces
configured” from “traces routed somewhere else.”
Log export behavior
- OTLP logs use the same structured records written to
logging.file.
- Respect
logging.level (file log level). Console redaction does not apply
to OTLP logs.
- High-volume installs should prefer OTLP collector sampling/filtering.
Troubleshooting tips
- Gateway not reachable? Run
openclaw doctor first.
- Logs empty? Check that the Gateway is running and writing to the file path
in
logging.file.
- Need more detail? Set
logging.level to debug or trace and retry.