# Monitoring CodeBuddy Code with OpenTelemetry

CodeBuddy Code 支持把 traces 通过标准 OTLP 协议上报到用户自有的 OpenTelemetry Collector，便于企业自建可观测性平台对接。

> **当前范围**：支持 **traces**（链路追踪）+ 4 个隐私 opt-in 开关。暂不支持 metrics 与 logs 的自定义上报。

## 快速开始

```bash
# 1. 启用 telemetry
export CODEBUDDY_CODE_ENABLE_TELEMETRY=1

# 2. 配置 OTLP endpoint
export OTEL_EXPORTER_OTLP_ENDPOINT=http://localhost:4318

# 3. (可选) 启用隐私 opt-in 内容记录
export OTEL_LOG_USER_PROMPTS=1
export OTEL_LOG_TOOL_DETAILS=1
export OTEL_LOG_TOOL_CONTENT=1

# 4. 运行
codebuddy
```

> 兼容 Claude Code 配置：`CLAUDE_CODE_ENABLE_TELEMETRY` 与 `CODEBUDDY_CODE_ENABLE_TELEMETRY` 等价。

## 配置变量

### 基础配置

| 变量 | 用途 | 示例 |
|------|------|------|
| `CODEBUDDY_CODE_ENABLE_TELEMETRY` | 启用 OTel 上报（必需） | `1` |
| `OTEL_TRACES_EXPORTER` | Exporter 类型 | `otlp`（默认）、`console`、`none` |
| `OTEL_EXPORTER_OTLP_ENDPOINT` | OTLP Collector 地址，自动追加 `/v1/traces` | `http://localhost:4318` |
| `OTEL_EXPORTER_OTLP_TRACES_ENDPOINT` | Traces 专用完整 URL，优先级更高 | `http://localhost:4318/v1/traces` |
| `OTEL_EXPORTER_OTLP_HEADERS` | 请求头 `k1=v1,k2=v2`，value 支持 URL 编码 | `Authorization=Bearer%20token` |
| `OTEL_EXPORTER_OTLP_TRACES_PROTOCOL` | 传输协议 | `http/protobuf`（仅支持） |
| `OTEL_SERVICE_NAME` | 覆盖默认 `service.name` | `codebuddy-code` |
| `OTEL_RESOURCE_ATTRIBUTES` | 附加 resource 属性 | `team=platform,env=prod` |

### 隐私 opt-in 开关

Span 默认不记录任何敏感信息（prompt 内容、工具参数、工具输出等），需要通过以下环境变量逐级 opt-in：

| 变量 | 用途 | 记录的内容 |
|------|------|-----------|
| `OTEL_LOG_USER_PROMPTS=1` | 记录用户 prompt | `user_prompt` 属性（默认为不记录，仅记录 `user_prompt_length`） |
| `OTEL_LOG_TOOL_DETAILS=1` | 记录工具参数 | `tool_input` 属性（~4KB 截断）+ 工具特定属性（`file.path`、`command` 等） |
| `OTEL_LOG_TOOL_CONTENT=1` | 记录工具输入输出全文 | `tool_input`/`tool_result` span events（60KB 截断） |
| `OTEL_LOG_RAW_API_BODIES=1` | 记录完整 API 请求/响应体 | 预留，暂未实现 |

## Span 结构

每个用户 prompt 产生一个 `codebuddy_code.interaction` 根 span。工具调用记录为其子 span：

```
codebuddy_code.interaction
├── codebuddy_code.tool (Read)
├── codebuddy_code.tool (Bash)
└── codebuddy_code.tool (Agent -> 子 agent 的 tool spans)
```

### Span 属性

所有 span 都包含 `span.type` 属性标识类型。

**`codebuddy_code.interaction`**

| 属性 | 描述 | 受控于 |
|------|------|--------|
| `span.type` | 固定值 `"interaction"` | |
| `conversation.id` | 会话 ID | |
| `conversation.agent` | Agent 名称 | |
| `user_prompt` | 用户 prompt 内容（未启用时不记录） | `OTEL_LOG_USER_PROMPTS` |
| `user_prompt_length` | Prompt 长度（始终记录） | |
| `conversation.cancelled` | 会话被取消时为 `true` | |

**`codebuddy_code.tool`**

| 属性 | 描述 | 受控于 |
|------|------|--------|
| `span.type` | 固定值 `"tool"` | |
| `tool_name` | 工具名称 | |
| `tool.call_id` | 工具调用 ID（始终记录） | |
| `file.path` | 文件路径（Read/Write/Edit） | `OTEL_LOG_TOOL_DETAILS` |
| `command` | Bash 命令 | `OTEL_LOG_TOOL_DETAILS` |
| `command.timeout` | 命令超时（毫秒） | `OTEL_LOG_TOOL_DETAILS` |
| `glob.pattern` | Glob 搜索模式 | `OTEL_LOG_TOOL_DETAILS` |
| `grep.pattern` | Grep 正则模式 | `OTEL_LOG_TOOL_DETAILS` |
| `http.url` | WebFetch URL | `OTEL_LOG_TOOL_DETAILS` |
| `search.query` | WebSearch 查询 | `OTEL_LOG_TOOL_DETAILS` |
| `agent.prompt` | 子 Agent prompt | `OTEL_LOG_TOOL_DETAILS` |
| `agent.type` | 子 Agent 类型 | `OTEL_LOG_TOOL_DETAILS` |
| `mcp.server` | MCP 服务器名 | `OTEL_LOG_TOOL_DETAILS` |
| `mcp.tool` | MCP 工具名 | `OTEL_LOG_TOOL_DETAILS` |
| `tool_input` | 工具输入 JSON（~4KB 截断） | `OTEL_LOG_TOOL_DETAILS` |
| `tool_input_truncated` | 输入是否被截断 | `OTEL_LOG_TOOL_DETAILS` |
| `tool_input_original_length` | 截断前原始长度 | `OTEL_LOG_TOOL_DETAILS` |

**`codebuddy_code.tool` span events**（需要 `OTEL_LOG_TOOL_CONTENT=1`）

| 事件名 | 属性 | 描述 |
|--------|------|------|
| `tool_input` | `content` | 完整工具输入（60KB 截断） |
| `tool_input` | `content_truncated` | 是否被截断 |
| `tool_input` | `content_original_length` | 截断前长度 |
| `tool_result` | `content` | 完整工具输出（60KB 截断） |
| `tool_result` | `content_truncated` | 是否被截断 |
| `tool_result` | `content_original_length` | 截断前长度 |

## 典型场景

### 上报到企业自建 Collector

```bash
export CODEBUDDY_CODE_ENABLE_TELEMETRY=1
export OTEL_EXPORTER_OTLP_ENDPOINT=https://otel.corp.example.com
export OTEL_EXPORTER_OTLP_HEADERS=Authorization=Bearer%20<TOKEN>
export OTEL_SERVICE_NAME=codebuddy-code
export OTEL_RESOURCE_ATTRIBUTES=deployment.environment=prod,team=copilot
```

### 本地调试（console 输出）

```bash
export CODEBUDDY_CODE_ENABLE_TELEMETRY=1
export OTEL_TRACES_EXPORTER=console
export OTEL_LOG_USER_PROMPTS=1
export OTEL_LOG_TOOL_DETAILS=1
export OTEL_LOG_TOOL_CONTENT=1
```

### 关闭 telemetry

```bash
export OTEL_TRACES_EXPORTER=none
# 或全局禁用：
export DISABLE_TELEMETRY=1
```

## 优先级与回退

1. `DISABLE_TELEMETRY=1` 拥有最高优先级，关闭所有遥测。
2. 启用判定：内置 product 配置启用 **或** `CODEBUDDY_CODE_ENABLE_TELEMETRY` / `CLAUDE_CODE_ENABLE_TELEMETRY` 设置为 truthy 值（`1` / `true` / `yes` / `on`）。
3. Endpoint 优先级：`OTEL_EXPORTER_OTLP_TRACES_ENDPOINT` > `OTEL_EXPORTER_OTLP_ENDPOINT` > 内置 product 配置中的 `telemetry.tracing.url`。
4. Headers：env 与 product 配置合并，env 同名 key 覆盖 product。

## 协议支持

仅支持 **`http/protobuf`**（OTLP/HTTP + Protobuf 编码），与 Claude Code 默认一致。

设置 `OTEL_EXPORTER_OTLP_PROTOCOL=grpc` 或 `http/json` 会被忽略并写入告警日志，回退到默认 protobuf。

## 安全与隐私

- Span 默认只记录工具名称和调用 ID，**不包含**用户 prompt、工具参数、文件内容或源代码
- `user_prompt_length` 始终记录（仅长度），prompt 文本需要 `OTEL_LOG_USER_PROMPTS=1` 才会写入
- 工具参数（文件路径、命令等）需要 `OTEL_LOG_TOOL_DETAILS=1`，个别值超过 512 字符会被截断，总量限制 ~4KB
- 工具输入输出全文需要 `OTEL_LOG_TOOL_CONTENT=1`，通过 span events 记录，截断于 60KB
- 所有 opt-in 开关默认关闭，企业管理员可通过 managed settings 统一配置

## FAQ

### 与企业内部上报通道是否冲突？

不冲突。OTel 自定义上报与内置 standard 报告（`telemetry.report.standard`）是两套独立通道，可同时启用。

### 是否支持 metrics / logs？

暂不支持，规划中。如有强诉求请反馈到对应 Issue。

### 与 Claude Code 的 OTEL 格式兼容吗？

是的。Span 命名、属性命名、截断策略均对齐 Claude Code 的约定（`{product}.interaction` / `{product}.tool`），确保上游分析平台可统一处理。
