{"version":"2.1.284","anchor":"hooks-modules-static-checks-for-telemetry-hook-destinations","canonical_anchor":"hooks-modules-static-checks-for-telemetry-hook-destinations","heading":"Telemetry moves onto the plugin hook system, with a built-in cc-plugin-otlp and new rules for plugin telemetry hooks","tier":"use","area":"Plugins","url":"https:\/\/changelogs.core-directive.com\/v\/2.1.284\/e\/hooks-modules-static-checks-for-telemetry-hook-destinations","release_url":"https:\/\/changelogs.core-directive.com\/v\/2.1.284","markdown":"### Telemetry moves onto the plugin hook system, with a built-in cc-plugin-otlp and new rules for plugin telemetry hooks\n\nA built-in cc-plugin-otlp can send OpenTelemetry records through plugin hooks, and plugin telemetry hooks must name a stream, with anthropic reserved\n\n**Unclear.** Whether plugin hook modules are available to everyone or sit behind their own switch is not clear.\n\n**What**\n\nOpenTelemetry is the standard Claude Code uses to send usage data to a collector you set up. Plugins can register hooks, small pieces of code that run when certain events happen. Telemetry now runs through that same hook system.\n\n- New built-in plugin `cc-plugin-otlp`, registered next to \"sec-default\", \"agents-md\" and \"telemetry\". It registers a `telemetry.log` hook on the \"collector\" stream and sends each record from core or built-in origins to the OpenTelemetry log exporter. When it is loaded and hooks `telemetry.log`, Claude Code's own event records go through that hook; otherwise they take the old path.\n\n- It is available only when `CLAUDE_CODE_ENABLE_TELEMETRY` is set, a further check is false, and the gate `tengu_basalt_plover` passes. That gate's built-in fallback is off, and nothing has been read about it for this release.\n\n- Plugins get a telemetry interface: `$.telemetry.log` takes an entry `{ to?, event, props? }` or a collector record, and `$.telemetry.mark` takes `{ feature, kind, reason?, props? }`. Calls run through the handler chain and can be denied. `telemetry.log` and `telemetry.mark` become hookable events, and a hook's return value must have a `value` key.\n\n- A telemetry hook's `to` must be a plain string, or list of them, from \"anthropic\" and \"collector\". Anything else is rejected with a message naming what was written (for example \"a template string\" or \"the variable x\"). A hook that changes `to` is rejected as \"a changed to (pinned)\".\n\n- A hook with no `to` stands on every stream. The \"anthropic\" stream is reserved for plugins built into the CLI: a non-built-in plugin on it is refused and told to write `on(\"telemetry.log\", { to: \"collector\" }, hook)`.\n\n- Wildcard hook patterns from non-built-in plugins no longer match `telemetry.*` events unless the pattern itself starts with `telemetry.`.\n\n**Why**\n\nPlugin authors who write telemetry hooks must now add `{ to: \"collector\" }`, and third-party plugins cannot tap Anthropic's telemetry stream through a broad wildcard. The built-in plugin shows telemetry export becoming a plugin rather than fixed code, though it only runs when its gate passes.\n\n- Area: Plugins\n- Tier: Use it now\n- Useful: 4\/5\n- Signal: 4\/5"}