17 KiB
summary, read_when, title
| summary | read_when | title | |||
|---|---|---|---|---|---|
| Logging overview: file logs, console output, CLI tailing, and the Control UI |
|
Logging overview |
Logging
OpenClaw has two main log surfaces:
- File logs (JSON lines) written by the Gateway.
- Console output shown in terminals and the Gateway Debug UI.
The Control UI Logs tab tails the gateway file log. This page explains where logs live, how to read them, and how to configure log levels and formats.
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.
You can override this in ~/.openclaw/openclaw.json:
{
"logging": {
"file": "/path/to/openclaw.log"
}
}
How to read logs
CLI: live tail (recommended)
Use the CLI to tail the gateway log file via RPC:
openclaw logs --follow
Useful current options:
--local-time: render timestamps in your local timezone--url <url>/--token <token>/--timeout <ms>: standard Gateway RPC flags--expect-final: agent-backed RPC final-response wait flag (accepted here via the shared client layer)
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.
When you pass an explicit --url, the CLI does not auto-apply config or
environment credentials; include --token yourself if the target Gateway
requires auth.
In JSON mode, the CLI emits type-tagged objects:
meta: stream metadata (file, cursor, size)log: parsed log entrynotice: truncation / rotation hintsraw: unparsed log line
If the local loopback Gateway asks for pairing, openclaw logs falls back to
the configured local log file automatically. Explicit --url targets do not
use this fallback.
If the Gateway is unreachable, the CLI prints a short hint to run:
openclaw doctor
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:
openclaw channels logs --channel whatsapp
Log formats
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).
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.
Gateway WebSocket logs
openclaw gateway also has WebSocket protocol logging for RPC traffic:
- normal mode: only interesting results (errors, parse errors, slow calls)
--verbose: all request/response traffic--ws-log auto|compact|full: pick the verbose rendering style--compact: alias for--ws-log compact
Examples:
openclaw gateway
openclaw gateway --verbose --ws-log compact
openclaw gateway --verbose --ws-log full
Configuring logging
All logging configuration lives under logging in ~/.openclaw/openclaw.json.
{
"logging": {
"level": "info",
"file": "/tmp/openclaw/openclaw-YYYY-MM-DD.log",
"consoleLevel": "info",
"consoleStyle": "pretty",
"redactSensitive": "tools",
"redactPatterns": ["sk-.*"]
}
}
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 and WS log verbosity; it does not change
file log levels.
Console styles
logging.consoleStyle:
pretty: human-friendly, colored, with timestamps.compact: tighter output (best for long sessions).json: JSON per line (for log processors).
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.
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.logsis enabled. Log volume can be high; keeplogging.leveland exporter filters in mind.
Diagnostic event catalog
Model usage:
model.usage: tokens, cost, duration, context, provider/model/channel, session ids.usageis provider/turn accounting for cost and telemetry;context.usedis the current prompt/context snapshot and can be lower than providerusage.totalwhen cached input or tool-loop calls are involved.
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.message.delivery.started: outbound delivery attempt started.message.delivery.completed: outbound delivery attempt finished + duration/result count.message.delivery.error: outbound delivery attempt failed + duration/bounded error category.
Queue + session:
queue.lane.enqueue: command queue lane enqueue + depth.queue.lane.dequeue: command queue lane dequeue + wait time.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).
Exec:
exec.process.completed: terminal exec process outcome, duration, target, mode, exit code, and failure kind. Command text and working directories are not included.
Enable diagnostics (no exporter)
Use this if you want diagnostics events available to plugins or custom sinks:
{
"diagnostics": {
"enabled": true
}
}
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 *).
{
"diagnostics": {
"flags": ["telegram.http"]
}
}
Env override (one-off):
OPENCLAW_DIAGNOSTICS=telegram.http,telegram.payload
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.
{
"plugins": {
"allow": ["diagnostics-otel"],
"entries": {
"diagnostics-otel": {
"enabled": true
}
}
},
"diagnostics": {
"enabled": true,
"otel": {
"enabled": true,
"endpoint": "http://otel-collector:4318",
"protocol": "http/protobuf",
"serviceName": "openclaw-gateway",
"traces": true,
"metrics": true,
"logs": true,
"sampleRate": 0.2,
"flushIntervalMs": 60000,
"captureContent": {
"enabled": false,
"inputMessages": false,
"outputMessages": false,
"toolInputs": false,
"toolOutputs": false,
"systemPrompt": false
}
}
}
}
Notes:
- You can also enable the plugin with
openclaw plugins enable diagnostics-otel. protocolcurrently supportshttp/protobufonly.grpcis ignored.- Metrics include token usage, cost, context size, run duration, and message-flow counters/histograms (webhooks, queueing, session state, queue depth/wait), plus GenAI token usage and model-call duration histograms.
- Traces/metrics can be toggled with
traces/metrics(default: on). Traces include model usage spans plus webhook/message processing spans when enabled. - Raw model/tool content is not exported by default. Use
diagnostics.otel.captureContentonly when your collector and retention policy are approved for prompt, response, tool, or system prompt text. - Set
headerswhen your collector requires auth. - Environment variables supported:
OTEL_EXPORTER_OTLP_ENDPOINT,OTEL_SERVICE_NAME,OTEL_EXPORTER_OTLP_PROTOCOL. - Set
OTEL_SEMCONV_STABILITY_OPT_IN=gen_ai_latest_experimentalto emit the latest experimental GenAI provider span attribute (gen_ai.provider.name) instead of the legacy span attribute (gen_ai.system). GenAI metrics always use bounded, low-cardinality semantic attributes. - Set
OPENCLAW_OTEL_PRELOADED=1when another preload or host process already registered the global OpenTelemetry SDK. In that mode the plugin does not start or shut down its own SDK, but it still wires OpenClaw diagnostic listeners and honorsdiagnostics.otel.traces,metrics, andlogs.
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)gen_ai.client.token.usage(histogram, GenAI semantic-conventions metric, attrs:gen_ai.token.type=input/output,gen_ai.provider.name,gen_ai.operation.name,gen_ai.request.model)gen_ai.client.operation.duration(histogram, seconds, GenAI semantic-conventions metric, attrs:gen_ai.provider.name,gen_ai.operation.name,gen_ai.request.model, optionalerror.type)
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)openclaw.message.delivery.started(counter, attrs:openclaw.channel,openclaw.delivery.kind)openclaw.message.delivery.duration_ms(histogram, attrs:openclaw.channel,openclaw.delivery.kind,openclaw.outcome,openclaw.errorCategory)
Queues + sessions:
openclaw.queue.lane.enqueue(counter, attrs:openclaw.lane)openclaw.queue.lane.dequeue(counter, attrs:openclaw.lane)openclaw.queue.depth(histogram, attrs:openclaw.laneoropenclaw.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)
Exec:
openclaw.exec.duration_ms(histogram, attrs:openclaw.exec.target,openclaw.exec.mode,openclaw.outcome,openclaw.failureKind)
Diagnostics internals (memory + tool loop):
openclaw.memory.heap_used_bytes(histogram, attrs:openclaw.memory.kind)openclaw.memory.rss_bytes(histogram)openclaw.memory.pressure(counter, attrs:openclaw.memory.level)openclaw.tool.loop.iterations(counter, attrs:openclaw.toolName,openclaw.outcome)openclaw.tool.loop.duration_ms(histogram, attrs:openclaw.toolName,openclaw.outcome)
Exported spans (names + key attributes)
openclaw.model.usageopenclaw.channel,openclaw.provider,openclaw.modelopenclaw.tokens.*(input/output/cache_read/cache_write/total)gen_ai.systemby default, orgen_ai.provider.namewhen latest GenAI semantic conventions are opted ingen_ai.request.model,gen_ai.operation.name,gen_ai.usage.*
openclaw.runopenclaw.outcome,openclaw.channel,openclaw.provider,openclaw.model,openclaw.errorCategory
openclaw.model.callgen_ai.systemby default, orgen_ai.provider.namewhen latest GenAI semantic conventions are opted ingen_ai.request.model,gen_ai.operation.name,openclaw.provider,openclaw.model,openclaw.api,openclaw.transport,openclaw.provider.request_id_hash(bounded SHA-based hash of the upstream provider request id; raw ids are not exported)
openclaw.tool.executiongen_ai.tool.name,openclaw.toolName,openclaw.errorCategory,openclaw.tool.params.*
openclaw.execopenclaw.exec.target,openclaw.exec.mode,openclaw.outcome,openclaw.failureKind,openclaw.exec.command_length,openclaw.exec.exit_code,openclaw.exec.timed_out
openclaw.webhook.processedopenclaw.channel,openclaw.webhook,openclaw.chatId
openclaw.webhook.erroropenclaw.channel,openclaw.webhook,openclaw.chatId,openclaw.error
openclaw.message.processedopenclaw.channel,openclaw.outcome,openclaw.chatId,openclaw.messageId,openclaw.reason
openclaw.message.deliveryopenclaw.channel,openclaw.delivery.kind,openclaw.outcome,openclaw.errorCategory,openclaw.delivery.result_count
openclaw.session.stuckopenclaw.state,openclaw.ageMs,openclaw.queueDepth
openclaw.context.assembledopenclaw.prompt.size,openclaw.history.size,openclaw.context.tokens,openclaw.errorCategory(no prompt, history, response, or session-key content)
openclaw.tool.loopopenclaw.toolName,openclaw.outcome,openclaw.iterations,openclaw.errorCategory(no loop messages, params, or tool output)
openclaw.memory.pressureopenclaw.memory.level,openclaw.memory.heap_used_bytes,openclaw.memory.rss_bytes
When content capture is explicitly enabled, model/tool spans can also include
bounded, redacted openclaw.content.* attributes for the specific content
classes you opted into.
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.endpointorOTEL_EXPORTER_OTLP_ENDPOINT. - If the endpoint already contains
/v1/tracesor/v1/metrics, it is used as-is. - If the endpoint already contains
/v1/logs, it is used as-is for logs. OTEL_SEMCONV_STABILITY_OPT_IN=gen_ai_latest_experimentalcontrols only the GenAI span provider attribute shape. Existing dashboards that readgen_ai.systemcan keep the default until they migrate.OPENCLAW_OTEL_PRELOADED=1reuses an externally registered OpenTelemetry SDK for traces/metrics instead of starting a plugin-owned NodeSDK.diagnostics.otel.logsenables OTLP log export for the main logger output.
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 doctorfirst. - Logs empty? Check that the Gateway is running and writing to the file path
in
logging.file. - Need more detail? Set
logging.leveltodebugortraceand retry.
Related
- Gateway Logging Internals — WS log styles, subsystem prefixes, and console capture
- Diagnostics — OpenTelemetry export and cache trace config