██████╗███████╗ █████╗ ██╗ ██╗███╗ ██╗ ██████╗ ███████╗████████╗██╗ ██████╗
██╔════╝██╔════╝██╔══██╗ ██╗ ██║ ██╔╝████╗ ██║██╔═══██╗██╔════╝╚══██╔══╝██║██╔════╝
██║ ███████╗███████║ ██████╗ █████╔╝ ██╔██╗ ██║██║ ██║███████╗ ██║ ██║██║
██║ ╚════██║██╔══██║ ╚═██╔═╝ ██╔═██╗ ██║╚██╗██║██║ ██║╚════██║ ██║ ██║██║
╚██████╗███████║██║ ██║ ╚═╝ ██║ ██╗██║ ╚████║╚██████╔╝███████║ ██║ ██║╚██████╗
╚═════╝╚══════╝╚═╝ ╚═╝ ╚═╝ ╚═╝╚═╝ ╚═══╝ ╚═════╝ ╚══════╝ ╚═╝ ╚═╝ ╚═════╝
By Cloud Security Alliance + 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.
Also check out:
- openclaw-detect: https://github.com/CloudSecurityAlliance/openclaw-detect/
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.