diff --git a/README.md b/README.md index b2acb32..2905dd4 100644 --- a/README.md +++ b/README.md @@ -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": { @@ -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. diff --git a/index.ts b/index.ts index 80df86e..8f76c53 100644 --- a/index.ts +++ b/index.ts @@ -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, @@ -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, @@ -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, @@ -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, @@ -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, @@ -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,