Three coordinated things:
1. Resolve the committed upstream/main merge conflicts. 94 files were
sitting with raw <<<<<<< HEAD ... >>>>>>> upstream/main blocks. Every
conflict had HanzoBot/Bot on HEAD and OpenClaw on upstream. Resolved
by keeping HEAD everywhere — 540 conflict blocks.
2. Rewrite remaining OpenClaw text refs.
OPENCLAW → HANZO_BOT
OpenClaw → HanzoBot (PascalCase type identifiers)
openclaw → bot (codebase convention — botToken,
botUsername etc.; avoids invalid
hyphenated JS identifiers)
openclaw[_]/openclaw[A-Z] → bot[_]/bot[A-Z] (compound)
ai.openclaw.x → ai.hanzo.bot.x (JVM package path)
3. Delete or rename openclaw-named file paths (116 of them). Dead
duplicates with a Bot-named canonical from the partial migration:
deleted. Otherwise renamed.
ai/openclaw/** → deleted (ai/hanzo/bot/** canonical)
Sources/OpenClaw*/ → deleted (Sources/Bot* canonical)
Tests/OpenClawIPCTests/ → deleted (Tests/BotIPCTests canonical)
OpenClawKit/ → deleted (BotKit canonical)
openclaw-tools.*.ts → deleted (bot-tools.*.ts canonical)
openclaw-root.ts etc. → deleted (bot-root.ts canonical)
types.openclaw.ts → deleted (types.bot.ts canonical)
extensions/*/openclaw.plugin.json → renamed hanzo-bot.plugin.json
docs/start/openclaw.md → renamed hanzo-bot.md (+ zh-CN)
docs/assets/openclaw-*.png, whatsapp-openclaw*.jpg → deleted
scripts/.../openclaw-* → deleted (bot/hanzo-bot parallels)
openclaw.mjs → deleted (hanzo-bot.mjs is package.bin)
Then patched 65 broken JS/TS import strings where hanzo-bot had ended
up inside an import path ('./types.hanzo-bot.js' → './types.bot.js'
etc., since the on-disk filename uses the brand-neutral bot- prefix).
Pre-existing lint debt cleaned up to get oxlint --type-aware to 0/0:
removed the dead i18n test that referenced a path no longer existing;
defined the missing DIDConfig and WalletConfig types in types.base.ts
(they were imported but never declared); dropped unused imports;
collapsed redundant type assertion and a tautological meta.bot lookup
that the openclaw→bot rename made redundant.
The a2ui.bundle.js generated artifact is kept at its pre-rebrand
contents — it gets regenerated by 'pnpm canvas:a2ui:bundle' from
sources I cannot rebuild in this commit; the source side is clean.
Verified: 0 occurrences of openclaw (case-insensitive) in tree source
content, 0 file or directory paths with openclaw in the name; oxlint
--type-aware src test reports 0/0.
11 KiB
summary, read_when, title
| summary | read_when | title | |||
|---|---|---|---|---|---|
| Logging overview: file logs, console output, CLI tailing, and the Control UI |
|
Logging |
Logging
HanzoBot 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 and formats.
Where logs live
By default, the Gateway writes a rolling log file under:
/tmp/hanzo-bot/hanzo-bot-YYYY-MM-DD.log
The date uses the gateway host's local timezone.
You can override this in ~/.hanzo-bot/hanzo-bot.json:
{
"logging": {
"file": "/path/to/hanzo-bot.log"
}
}
How to read logs
CLI: live tail (recommended)
Use the CLI to tail the gateway log file via RPC:
hanzo-bot logs --follow
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 entrynotice: truncation / rotation hintsraw: unparsed log line
If the Gateway is unreachable, the CLI prints a short hint to run:
hanzo-bot 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:
hanzo-bot 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.
Configuring logging
All logging configuration lives under logging in ~/.hanzo-bot/hanzo-bot.json.
{
"logging": {
"level": "info",
"file": "/tmp/hanzo-bot/hanzo-bot-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 BOT_LOG_LEVEL environment variable (e.g. BOT_LOG_LEVEL=debug). The env var takes precedence over the config file, so you can raise verbosity for a single run without editing hanzo-bot.json. You can also pass the global CLI option --log-level <level> (for example, hanzo-bot --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.
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.
- HanzoBot 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.
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.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).
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):
BOT_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": "hanzo-bot-gateway",
"traces": true,
"metrics": true,
"logs": true,
"sampleRate": 0.2,
"flushIntervalMs": 60000
}
}
}
Notes:
- You can also enable the plugin with
hanzo-bot 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).
- Traces/metrics can be toggled with
traces/metrics(default: on). Traces include model usage spans plus webhook/message processing spans when enabled. - Set
headerswhen your collector requires auth. - Environment variables supported:
OTEL_EXPORTER_OTLP_ENDPOINT,OTEL_SERVICE_NAME,OTEL_EXPORTER_OTLP_PROTOCOL.
Exported metrics (names + types)
Model usage:
hanzo-bot.tokens(counter, attrs:hanzo-bot.token,hanzo-bot.channel,hanzo-bot.provider,hanzo-bot.model)hanzo-bot.cost.usd(counter, attrs:hanzo-bot.channel,hanzo-bot.provider,hanzo-bot.model)hanzo-bot.run.duration_ms(histogram, attrs:hanzo-bot.channel,hanzo-bot.provider,hanzo-bot.model)hanzo-bot.context.tokens(histogram, attrs:hanzo-bot.context,hanzo-bot.channel,hanzo-bot.provider,hanzo-bot.model)
Message flow:
hanzo-bot.webhook.received(counter, attrs:hanzo-bot.channel,hanzo-bot.webhook)hanzo-bot.webhook.error(counter, attrs:hanzo-bot.channel,hanzo-bot.webhook)hanzo-bot.webhook.duration_ms(histogram, attrs:hanzo-bot.channel,hanzo-bot.webhook)hanzo-bot.message.queued(counter, attrs:hanzo-bot.channel,hanzo-bot.source)hanzo-bot.message.processed(counter, attrs:hanzo-bot.channel,hanzo-bot.outcome)hanzo-bot.message.duration_ms(histogram, attrs:hanzo-bot.channel,hanzo-bot.outcome)
Queues + sessions:
hanzo-bot.queue.lane.enqueue(counter, attrs:hanzo-bot.lane)hanzo-bot.queue.lane.dequeue(counter, attrs:hanzo-bot.lane)hanzo-bot.queue.depth(histogram, attrs:hanzo-bot.laneorhanzo-bot.channel=heartbeat)hanzo-bot.queue.wait_ms(histogram, attrs:hanzo-bot.lane)hanzo-bot.session.state(counter, attrs:hanzo-bot.state,hanzo-bot.reason)hanzo-bot.session.stuck(counter, attrs:hanzo-bot.state)hanzo-bot.session.stuck_age_ms(histogram, attrs:hanzo-bot.state)hanzo-bot.run.attempt(counter, attrs:hanzo-bot.attempt)
Exported spans (names + key attributes)
hanzo-bot.model.usagehanzo-bot.channel,hanzo-bot.provider,hanzo-bot.modelhanzo-bot.sessionKey,hanzo-bot.sessionIdhanzo-bot.tokens.*(input/output/cache_read/cache_write/total)
hanzo-bot.webhook.processedhanzo-bot.channel,hanzo-bot.webhook,hanzo-bot.chatId
hanzo-bot.webhook.errorhanzo-bot.channel,hanzo-bot.webhook,hanzo-bot.chatId,hanzo-bot.error
hanzo-bot.message.processedhanzo-bot.channel,hanzo-bot.outcome,hanzo-bot.chatId,hanzo-bot.messageId,hanzo-bot.sessionKey,hanzo-bot.sessionId,hanzo-bot.reason
hanzo-bot.session.stuckhanzo-bot.state,hanzo-bot.ageMs,hanzo-bot.queueDepth,hanzo-bot.sessionKey,hanzo-bot.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.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. 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
hanzo-bot 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.