Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 12 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,8 @@ cp -R ./openclaw-telemetry ~/.openclaw/extensions/telemetry

Via Control UI: **Settings → Config → plugins.entries.telemetry**

Or edit `~/.openclaw/config.json`:
Or edit `~/.openclaw/openclaw.json` (note the path — some older docs say
`config.json`, but the actual file is `openclaw.json`):
```json
{
"plugins": {
Expand All @@ -56,10 +57,19 @@ Or edit `~/.openclaw/config.json`:
}
```

**Important** — both the outer `enabled` (OpenClaw's "plugin is active"
flag) and the inner `config.enabled` (this plugin's "capture events" flag)
must be `true`. If you omit the nested `config` object entirely — e.g. you
have only `{ "enabled": true }` at `plugins.entries.telemetry` — the
plugin's `start()` silently bails and **no events are written**. This is
the most common misconfiguration; if `~/.openclaw/logs/telemetry.jsonl`
never appears after an agent turn, check that the nested `config.enabled`
is present.

### 3. Restart Gateway

```bash
openclaw gateway
systemctl --user restart openclaw-gateway
```

Logs write to `~/.openclaw/logs/telemetry.jsonl` by default.
Expand Down
23 changes: 15 additions & 8 deletions index.ts
Original file line number Diff line number Diff line change
@@ -1,16 +1,23 @@
import type { OpenClawPluginApi } from "openclaw/plugin-sdk";
import { createTelemetryService } from "./src/service.js";
import { createTelemetryService, type TelemetryService } from "./src/service.js";

// Module-level singleton so re-registrations share the same service instance.
// OpenClaw may call register() multiple times per plugin lifetime (e.g., CLI
// metadata vs gateway full load); keeping svc at module scope ensures hooks
// reference the same service that receives start()/stop().
let svc: TelemetryService | null = null;

export default {
id: "telemetry",
name: "OpenClaw Telemetry",
description: "Captures tool calls, LLM usage, and message events to JSONL",
register(api: OpenClawPluginApi) {
const svc = createTelemetryService();
if (!svc) svc = createTelemetryService();
api.registerService(svc);
const s = svc;

api.on("before_tool_call", (evt, ctx) => {
svc.write({
s.write({
type: "tool.start",
toolName: evt.toolName,
params: evt.params,
Expand All @@ -20,7 +27,7 @@ export default {
});

api.on("after_tool_call", (evt, ctx) => {
svc.write({
s.write({
type: "tool.end",
toolName: evt.toolName,
durationMs: evt.durationMs,
Expand All @@ -32,7 +39,7 @@ export default {
});

api.on("message_received", (evt, ctx) => {
svc.write({
s.write({
type: "message.in",
channel: ctx.channelId,
from: evt.from,
Expand All @@ -41,7 +48,7 @@ export default {
});

api.on("message_sent", (evt, ctx) => {
svc.write({
s.write({
type: "message.out",
channel: ctx.channelId,
to: evt.to,
Expand All @@ -51,7 +58,7 @@ export default {
});

api.on("before_agent_start", (evt, ctx) => {
svc.write({
s.write({
type: "agent.start",
sessionKey: ctx.sessionKey,
agentId: ctx.agentId,
Expand All @@ -60,7 +67,7 @@ export default {
});

api.on("agent_end", (evt, ctx) => {
svc.write({
s.write({
type: "agent.end",
sessionKey: ctx.sessionKey,
agentId: ctx.agentId,
Expand Down