# `CMDC.Telemetry`
[🔗](https://github.com/tuplehq/cmdc/blob/v0.4.0/lib/cmdc/telemetry.ex#L1)

CMDC 标准 `:telemetry` 事件契约 — Phase 12 12G.

对标 deepagents 的 OTel 集成模式 + LangSmith/Langfuse 同源消费协议。
CMDC 核心库只**广播事件**，不内嵌任何 sink；用户可挂任意 handler
到 Langfuse / LangSmith / Grafana Tempo / Datadog / Splunk 等。

## 设计原则

1. **零强制依赖**：`:telemetry` 已是 BEAM 生态事实标准，CMDC 仅广播
2. **事件命名稳定**：v0.4 锁定 schema，向后兼容
3. **metadata 白名单**：明确列出 metadata 字段，避免泄露敏感数据
4. **与现有 EventBus 互补**：EventBus 走 PubSub 给业务订阅者，
   Telemetry 走 handler 给可观测性栈

## 事件清单（v0.4.0）

| 事件名 | 触发时机 | metadata |
|---|---|---|
| `[:cmdc, :agent, :turn, :start]` | Agent 单 turn 开始 | session_id, turn |
| `[:cmdc, :agent, :turn, :stop]` | Agent 单 turn 结束 | session_id, turn, duration_ms, outcome |
| `[:cmdc, :llm, :request, :start]` | LLM 调用前 | session_id, turn, model |
| `[:cmdc, :llm, :request, :stop]` | LLM 调用后 | session_id, turn, model, tokens_in, tokens_out, duration_ms |
| `[:cmdc, :tool, :exec, :start]` | 工具开始执行 | session_id, tool, call_id |
| `[:cmdc, :tool, :exec, :stop]` | 工具结束 | session_id, tool, call_id, duration_ms, error? |

## 与 11G.01 :tool_execution_metrics 的关系

11G.01 通过 `EventBus` 广播 `:tool_execution_metrics` 业务事件（per-session 订阅）。
12G.3 通过 `:telemetry.execute/3` 广播 `[:cmdc, :tool, :exec, :*]` 全局事件
（system-wide 监控）。两者数据字段一致，触发点合并在 `Agent.ToolRunner` 内。

## v0.4.0 实现说明

- **emitter 桥接模式**：`Agent.Emitter.broadcast/2` 在广播 EventBus 事件的同时，
  把 6 个核心事件映射到 telemetry（无需改 ToolRunner / Provider）
- **schema 版本号**：所有事件 metadata 含 `schema_version: 1`
- 用户用 `:telemetry.attach/4` 或 `CMDC.Telemetry.attach_logger/0` 接入

## Quick Start

    # 1. attach 默认 logger（开发期）
    CMDC.Telemetry.attach_logger()

    # 2. attach 自定义 handler（接入 Langfuse）
    :telemetry.attach_many(
      "my-langfuse-handler",
      CMDC.Telemetry.all_events(),
      &MyApp.LangfuseHandler.handle/4,
      nil
    )

    # 3. detach
    :telemetry.detach("my-langfuse-handler")

完整可观测性配方见 `docs/recipes/observability/`（v0.4.0 提供 Langfuse 示例）。

# `all_events`

```elixir
@spec all_events() :: [[atom()]]
```

返回 CMDC.Telemetry 所有事件列表。

# `attach_logger`

```elixir
@spec attach_logger(keyword()) :: :ok | {:error, term()}
```

附加一个开发期 Logger handler，把所有 CMDC telemetry 事件打到 console。

生产环境请用 `:telemetry.attach_many/4` 接入实际可观测性栈。

# `bridge_event`

```elixir
@spec bridge_event(String.t(), term()) :: :ok
```

从 EventBus 事件桥接到 telemetry。

由 `Agent.Emitter.broadcast/2` 调用。映射规则：

| EventBus 事件 | Telemetry 事件 |
|---|---|
| `{:agent_start, session_id, turn}` | `[:cmdc, :agent, :turn, :start]` |
| `{:agent_end, payload}` (success) | `[:cmdc, :agent, :turn, :stop]` |
| `{:llm_request_start, ...}` | `[:cmdc, :llm, :request, :start]` |
| `{:llm_response, payload}` | `[:cmdc, :llm, :request, :stop]` |
| `{:tool_started, name, call_id, ...}` | `[:cmdc, :tool, :exec, :start]` |
| `{:tool_ended, name, call_id, ...}` | `[:cmdc, :tool, :exec, :stop]` |
| `{:tool_execution_metrics, ...}` | `[:cmdc, :tool, :exec, :stop]`（11G.01 兼容路径）|

其他事件不映射（继续走 EventBus）。

# `detach_logger`

```elixir
@spec detach_logger(keyword()) :: :ok | {:error, :not_found}
```

Detach Logger handler。

# `execute`

```elixir
@spec execute([atom()], map(), map()) :: :ok
```

执行 telemetry 事件 — 内部桥接使用。

自动加 `schema_version: 1` 到 metadata。

# `schema_version`

```elixir
@spec schema_version() :: pos_integer()
```

返回 telemetry schema 版本号。

---

*Consult [api-reference.md](api-reference.md) for complete listing*
