feat(telemetry): anonymous usage telemetry — documented schema, opt-out, public ingest worker (#834)
Adds anonymous usage statistics (commands/tools used, languages indexed, connecting agents) with a strict, auditable allowlist. Never code, paths, file/symbol names, queries, or IPs. - src/telemetry/: zero-dep client — consent resolution (DO_NOT_TRACK > CODEGRAPH_TELEMETRY > stored choice > default-on), random machine UUID, in-memory counters → capped JSONL buffer → completed-day rollups; sync exit-append (survives process.exit) + opportunistic bounded sends; the first-run notice gates the first SEND, never local buffering, so the installer's consent toggle always precedes it. Off is off: no recording, no socket, buffered data deleted. - codegraph telemetry status|on|off; per-command counting via preAction hook. - MCP: tool counting after the reply is on the wire (session + proxy in-process fallback), agent attribution from initialize clientInfo, unref'd daemon flush interval. Zero hot-path cost, zero stdout. - Installer: visible default-on consent toggle (asked once, never re-asked), install/index/uninstall lifecycle events. - telemetry-worker/: public Cloudflare Worker behind telemetry.getcodegraph.com — allowlist validation, IP stripping, per-machine rate limit, forwards to PostHog as anonymous events. Ships nowhere with the npm package. - TELEMETRY.md (field-by-field contract) + README section + design doc. - 20 unit tests; suite-wide CODEGRAPH_TELEMETRY=0 guard so tests never pollute real telemetry. Full suite: 1448 passing. Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 4.8
parent
7db4c1d2f8
commit
848fde9f59
@@ -0,0 +1,60 @@
|
||||
# codegraph telemetry ingest worker
|
||||
|
||||
The first-party endpoint behind `telemetry.getcodegraph.com`. This directory is in the
|
||||
public repo **on purpose**: it is the exact code that receives codegraph's anonymous usage
|
||||
telemetry, so anyone can audit what is stored. The schema contract (every event, every
|
||||
field, and everything that is never collected) is in
|
||||
[`docs/design/telemetry.md`](../docs/design/telemetry.md).
|
||||
|
||||
What it does, in one breath: validates incoming batches against a strict allowlist (unknown
|
||||
events dropped, unknown properties stripped), never reads or forwards the client IP,
|
||||
rate-limits per machine ID, and forwards to PostHog off the response path. It ships nowhere
|
||||
with the npm package — the engine's `files` allowlist excludes it.
|
||||
|
||||
## Endpoint contract
|
||||
|
||||
- `POST /v1/events` — JSON body: envelope (`machine_id` UUID, `codegraph_version`, `os`,
|
||||
`arch`, `node_major`, `ci`, `schema_version`) + `events: [{event, ts?, props?}]`.
|
||||
Responds `204` when accepted (including events dropped by the allowlist), honest `4xx`
|
||||
for malformed/oversized/rate-limited requests. Clients treat every response as final —
|
||||
no retries.
|
||||
- `GET /` — plain-text pointer to the docs and the off-switches.
|
||||
|
||||
## Deploy
|
||||
|
||||
Prereqs: the `getcodegraph.com` zone on the deploying Cloudflare account (the custom
|
||||
domain route auto-provisions DNS + cert), wrangler ≥ 4.36 (the `ratelimits` binding).
|
||||
|
||||
```bash
|
||||
cd telemetry-worker
|
||||
npm install
|
||||
npx wrangler login # once
|
||||
npx wrangler secret put POSTHOG_KEY # the phc_… project write key — never committed
|
||||
npm run deploy
|
||||
```
|
||||
|
||||
The PostHog project itself must have **"Discard client IP data"** enabled — defense in
|
||||
depth on top of this worker never forwarding IPs (`$geoip_disable` is also set per event).
|
||||
|
||||
## Local dev & checks
|
||||
|
||||
```bash
|
||||
cp .dev.vars.example .dev.vars # placeholder key; also feeds `wrangler types`
|
||||
npm run check # wrangler types + tsc --noEmit + deploy --dry-run
|
||||
npm run dev # http://localhost:8787
|
||||
|
||||
curl -i localhost:8787/v1/events -H 'content-type: application/json' -d '{
|
||||
"machine_id": "00000000-0000-4000-8000-000000000000",
|
||||
"codegraph_version": "0.9.9", "os": "darwin", "arch": "arm64",
|
||||
"node_major": 22, "ci": false, "schema_version": 1,
|
||||
"events": [{ "event": "usage_rollup",
|
||||
"props": { "kind": "mcp_tool", "name": "codegraph_explore",
|
||||
"count": 12, "error_count": 0, "client_name": "Claude Code" } }]
|
||||
}'
|
||||
```
|
||||
|
||||
## Changing the schema
|
||||
|
||||
The allowlist in `src/index.ts` mirrors `docs/design/telemetry.md` (and the user-facing
|
||||
`TELEMETRY.md`). A field is added by one PR touching all of them together — that is the
|
||||
whole point of the design.
|
||||
Reference in New Issue
Block a user