██╗ ██╗███╗ ██╗ ██████╗ ███████╗████████╗██╗ ██████╗
██║ ██╔╝████╗ ██║██╔═══██╗██╔════╝╚══██╔══╝██║██╔════╝
█████╔╝ ██╔██╗ ██║██║ ██║███████╗ ██║ ██║██║
██╔═██╗ ██║╚██╗██║██║ ██║╚════██║ ██║ ██║██║
██║ ██╗██║ ╚████║╚██████╔╝███████║ ██║ ██║╚██████╗
╚═╝ ╚═╝╚═╝ ╚═══╝ ╚═════╝ ╚══════╝ ╚═╝ ╚═╝ ╚═════╝
By Knostic
Observability for OpenClaw. Capture every tool call, LLM request, and agent session — with built-in redaction, tamper-proof hash chains, syslog/SIEM forwarding, and rate limiting. Drop it in and know exactly what your agents are doing.
Like the tool? Check out how Knostic helps you with visibility and control of your coding agents and MCP/extensions, from Cursor and Claude Code, to Copilot.
Captures tool calls, LLM usage, agent lifecycle, and message events. Outputs to JSONL file and optionally to syslog for SIEM integration.
openclaw plugins install ./openclaw-telemetryOr copy manually:
cp -R ./openclaw-telemetry ~/.openclaw/extensions/telemetryVia Control UI: Settings → Config → plugins.entries.telemetry
Or edit ~/.openclaw/config.json:
{
"plugins": {
"entries": {
"telemetry": {
"enabled": true,
"config": {
"enabled": true
}
}
}
}
}openclaw gatewayLogs write to ~/.openclaw/logs/telemetry.jsonl by default.
openclaw plugins install @openclaw/telemetry| Option | Type | Default | Description |
|---|---|---|---|
enabled |
boolean | false |
Enable telemetry capture |
filePath |
string | ~/.openclaw/logs/telemetry.jsonl |
JSONL output file path |
| Option | Type | Default | Description |
|---|---|---|---|
syslog.enabled |
boolean | false |
Enable syslog output |
syslog.host |
string | required | Syslog server hostname |
syslog.port |
number | 514 |
Syslog server port |
syslog.protocol |
string | udp |
Transport: udp, tcp, or tcp-tls |
syslog.format |
string | cef |
Message format: cef or json |
syslog.facility |
number | 16 |
Syslog facility (16 = local0) |
syslog.appName |
string | openclaw |
App name in syslog messages |
Automatically redacts sensitive data (API keys, tokens, passwords) from tool parameters before logging.
| Option | Type | Default | Description |
|---|---|---|---|
redact.enabled |
boolean | false |
Enable redaction |
redact.patterns |
string[] | (built-in) | Regex patterns to match. Prefix with (?i) for case-insensitive |
redact.replacement |
string | [REDACTED] |
Replacement text |
Default patterns detect:
- OpenAI keys (
sk-...) - GitHub tokens (
ghp_...,gho_...) - GitLab tokens (
glpat-...) - Slack tokens (
xox[baprs]-...) - AWS credentials
- Bearer tokens
- Common
api_key,password,secret,tokenpatterns
Adds cryptographic hash chain to events for tamper detection. Each event includes prevHash and hash fields, forming a verifiable chain.
| Option | Type | Default | Description |
|---|---|---|---|
integrity.enabled |
boolean | false |
Enable hash chain |
integrity.algorithm |
string | sha256 |
Hash algorithm |
Prevents runaway agents from flooding outputs. Uses token bucket algorithm.
| Option | Type | Default | Description |
|---|---|---|---|
rateLimit.enabled |
boolean | false |
Enable rate limiting |
rateLimit.maxEventsPerSecond |
number | 100 |
Sustained event rate |
rateLimit.burstSize |
number | 200 |
Burst capacity |
Rotates JSONL files to prevent unbounded growth.
| Option | Type | Default | Description |
|---|---|---|---|
rotate.enabled |
boolean | false |
Enable rotation |
rotate.maxSizeBytes |
number | 10485760 |
Max file size (10MB) |
rotate.maxFiles |
number | 5 |
Rotated files to keep |
rotate.compress |
boolean | true |
Gzip rotated files |
{
"plugins": {
"telemetry": {
"enabled": true
}
}
}{
"plugins": {
"telemetry": {
"enabled": true,
"redact": {
"enabled": true
},
"integrity": {
"enabled": true
},
"rateLimit": {
"enabled": true,
"maxEventsPerSecond": 50
},
"rotate": {
"enabled": true,
"maxSizeBytes": 52428800,
"maxFiles": 10
},
"syslog": {
"enabled": true,
"host": "siem.company.com",
"port": 6514,
"protocol": "tcp-tls",
"format": "cef"
}
}
}
}{
"plugins": {
"telemetry": {
"enabled": true,
"redact": {
"enabled": true,
"patterns": [
"(?i)internal-secret-[a-z0-9]+",
"COMPANY-[A-Z]{4}-[0-9]{8}"
],
"replacement": "***"
}
}
}
}| Event | Description |
|---|---|
tool.start |
Tool invocation started |
tool.end |
Tool invocation completed (success/failure, duration) |
message.in |
Inbound message received |
message.out |
Outbound message sent |
llm.usage |
LLM API call (tokens, cost, duration) |
agent.start |
Agent session started |
agent.end |
Agent session completed |
Basic event:
{"type":"tool.start","toolName":"bash","params":{"cmd":"ls"},"sessionKey":"telegram:123","seq":1,"ts":1738517700000}With integrity enabled:
{"type":"tool.start","toolName":"bash","params":{"cmd":"ls"},"seq":1,"ts":1738517700000,"prevHash":"0000000000000000000000000000000000000000000000000000000000000000","hash":"a1b2c3d4e5f6..."}With redaction (before):
{"type":"tool.start","toolName":"bash","params":{"cmd":"curl -H 'Authorization: Bearer sk-abc123...'"}}With redaction (after):
{"type":"tool.start","toolName":"bash","params":{"cmd":"curl -H 'Authorization: [REDACTED]'"}}CEF:0|OpenClaw|openclaw|1.0|1001|Tool Invocation Started|3|rt=1738517700000 cs1=telegram:123 cs1Label=sessionKey act=bash cs5=a1b2c3... cs5Label=hash cs6=0000... cs6Label=prevHash
# Verify chain integrity with jq
jq -s '
reduce .[] as $evt (
{valid: true, prev: ("0" * 64)};
if .valid and $evt.prevHash == .prev
then {valid: true, prev: $evt.hash}
else {valid: false, prev: .prev, broken_at: $evt.seq}
end
)
' ~/.openclaw/logs/telemetry.jsonl# Follow live events
tail -f ~/.openclaw/logs/telemetry.jsonl | jq .
# Filter by event type
jq 'select(.type=="tool.end")' ~/.openclaw/logs/telemetry.jsonl
# Get LLM costs
jq 'select(.type=="llm.usage") | {model, costUsd}' ~/.openclaw/logs/telemetry.jsonl
# Correlate by session
jq 'select(.sessionKey=="telegram:123456")' ~/.openclaw/logs/telemetry.jsonl
# Find failed tool calls
jq 'select(.type=="tool.end" and .success==false)' ~/.openclaw/logs/telemetry.jsonlWhen rotation is enabled, files are named:
telemetry.jsonl- current filetelemetry.jsonl.1.gz- most recent rotated (compressed)telemetry.jsonl.2.gz- older- ...up to
maxFiles
To read compressed logs:
zcat ~/.openclaw/logs/telemetry.jsonl.1.gz | jq .The file-based output works with log shippers:
- Filebeat: Configure a
filestreaminput pointing to the JSONL file - Fluentd: Use
in_tailwith JSON parser - Splunk Universal Forwarder: Monitor the file path
The syslog output connects directly to:
-
Splunk (syslog input)
-
QRadar (CEF supported natively)
-
ArcSight (CEF supported natively)
-
Elastic SIEM (via Logstash syslog input)
-
Any RFC 5424 compliant collector
Apache 2.0 — see LICENSE for details.