# Monitoring CodeBuddy Code with OpenTelemetry

CodeBuddy Code supports exporting traces to your own OpenTelemetry Collector via the standard OTLP protocol, making it easy to integrate with self-hosted observability platforms.

> **Current Scope**: Supports **traces** (distributed tracing) + 4 privacy opt-in switches. Custom export of metrics and logs is not yet supported.

## Quick Start

```bash
# 1. Enable telemetry
export CODEBUDDY_CODE_ENABLE_TELEMETRY=1

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

# 3. (Optional) Enable privacy opt-in content recording
export OTEL_LOG_USER_PROMPTS=1
export OTEL_LOG_TOOL_DETAILS=1
export OTEL_LOG_TOOL_CONTENT=1

# 4. Run
codebuddy
```

> Claude Code compatibility: `CLAUDE_CODE_ENABLE_TELEMETRY` is equivalent to `CODEBUDDY_CODE_ENABLE_TELEMETRY`.

## Configuration Variables

### Basic Configuration

| Variable | Purpose | Example |
|----------|---------|---------|
| `CODEBUDDY_CODE_ENABLE_TELEMETRY` | Enable OTel export (required) | `1` |
| `OTEL_TRACES_EXPORTER` | Exporter type | `otlp` (default), `console`, `none` |
| `OTEL_EXPORTER_OTLP_ENDPOINT` | OTLP Collector address; `/v1/traces` is appended automatically | `http://localhost:4318` |
| `OTEL_EXPORTER_OTLP_TRACES_ENDPOINT` | Full URL specific to traces; takes higher priority | `http://localhost:4318/v1/traces` |
| `OTEL_EXPORTER_OTLP_HEADERS` | Request headers `k1=v1,k2=v2`; values support URL encoding | `Authorization=Bearer%20token` |
| `OTEL_EXPORTER_OTLP_TRACES_PROTOCOL` | Transport protocol | `http/protobuf` (only supported) |
| `OTEL_SERVICE_NAME` | Override the default `service.name` | `codebuddy-code` |
| `OTEL_RESOURCE_ATTRIBUTES` | Additional resource attributes | `team=platform,env=prod` |

### Privacy Opt-in Switches

Spans do not record any sensitive information by default (prompt content, tool parameters, tool output, etc.). You need to opt in progressively via the following environment variables:

| Variable | Purpose | Recorded Content |
|----------|---------|-----------------|
| `OTEL_LOG_USER_PROMPTS=1` | Record user prompts | `user_prompt` attribute (not recorded by default; only `user_prompt_length` is recorded) |
| `OTEL_LOG_TOOL_DETAILS=1` | Record tool parameters | `tool_input` attribute (~4KB truncation) + tool-specific attributes (`file.path`, `command`, etc.) |
| `OTEL_LOG_TOOL_CONTENT=1` | Record full tool input/output | `tool_input`/`tool_result` span events (60KB truncation) |
| `OTEL_LOG_RAW_API_BODIES=1` | Record full API request/response bodies | Reserved, not yet implemented |

## Span Structure

Each user prompt produces a `codebuddy_code.interaction` root span. Tool calls are recorded as child spans:

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

### Span Attributes

All spans include a `span.type` attribute to identify the type.

**`codebuddy_code.interaction`**

| Attribute | Description | Controlled By |
|-----------|-------------|---------------|
| `span.type` | Fixed value `"interaction"` | |
| `conversation.id` | Conversation ID | |
| `conversation.agent` | Agent name | |
| `user_prompt` | User prompt content (not recorded when disabled) | `OTEL_LOG_USER_PROMPTS` |
| `user_prompt_length` | Prompt length (always recorded) | |
| `conversation.cancelled` | `true` when conversation is cancelled | |

**`codebuddy_code.tool`**

| Attribute | Description | Controlled By |
|-----------|-------------|---------------|
| `span.type` | Fixed value `"tool"` | |
| `tool_name` | Tool name | |
| `tool.call_id` | Tool call ID (always recorded) | |
| `file.path` | File path (Read/Write/Edit) | `OTEL_LOG_TOOL_DETAILS` |
| `command` | Bash command | `OTEL_LOG_TOOL_DETAILS` |
| `command.timeout` | Command timeout (milliseconds) | `OTEL_LOG_TOOL_DETAILS` |
| `glob.pattern` | Glob search pattern | `OTEL_LOG_TOOL_DETAILS` |
| `grep.pattern` | Grep regex pattern | `OTEL_LOG_TOOL_DETAILS` |
| `http.url` | WebFetch URL | `OTEL_LOG_TOOL_DETAILS` |
| `search.query` | WebSearch query | `OTEL_LOG_TOOL_DETAILS` |
| `agent.prompt` | Sub-agent prompt | `OTEL_LOG_TOOL_DETAILS` |
| `agent.type` | Sub-agent type | `OTEL_LOG_TOOL_DETAILS` |
| `mcp.server` | MCP server name | `OTEL_LOG_TOOL_DETAILS` |
| `mcp.tool` | MCP tool name | `OTEL_LOG_TOOL_DETAILS` |
| `tool_input` | Tool input JSON (~4KB truncation) | `OTEL_LOG_TOOL_DETAILS` |
| `tool_input_truncated` | Whether input was truncated | `OTEL_LOG_TOOL_DETAILS` |
| `tool_input_original_length` | Original length before truncation | `OTEL_LOG_TOOL_DETAILS` |

**`codebuddy_code.tool` span events** (requires `OTEL_LOG_TOOL_CONTENT=1`)

| Event Name | Attribute | Description |
|------------|-----------|-------------|
| `tool_input` | `content` | Full tool input (60KB truncation) |
| `tool_input` | `content_truncated` | Whether truncated |
| `tool_input` | `content_original_length` | Length before truncation |
| `tool_result` | `content` | Full tool output (60KB truncation) |
| `tool_result` | `content_truncated` | Whether truncated |
| `tool_result` | `content_original_length` | Length before truncation |

## Typical Scenarios

### Export to a Self-Hosted Enterprise 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
```

### Local Debugging (Console Output)

```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
```

### Disable Telemetry

```bash
export OTEL_TRACES_EXPORTER=none
# Or globally disable:
export DISABLE_TELEMETRY=1
```

## Priority and Fallback

1. `DISABLE_TELEMETRY=1` has the highest priority and disables all telemetry.
2. Enable evaluation: enabled in the built-in product configuration **or** `CODEBUDDY_CODE_ENABLE_TELEMETRY` / `CLAUDE_CODE_ENABLE_TELEMETRY` is set to a truthy value (`1` / `true` / `yes` / `on`).
3. Endpoint priority: `OTEL_EXPORTER_OTLP_TRACES_ENDPOINT` > `OTEL_EXPORTER_OTLP_ENDPOINT` > `telemetry.tracing.url` in the built-in product configuration.
4. Headers: env and product configuration are merged; env keys with the same name override product configuration.

## Protocol Support

Only **`http/protobuf`** (OTLP/HTTP + Protobuf encoding) is supported, consistent with the Claude Code default.

Setting `OTEL_EXPORTER_OTLP_PROTOCOL=grpc` or `http/json` will be ignored with a warning logged, falling back to the default protobuf.

## Security and Privacy

- Spans only record tool names and call IDs by default, **excluding** user prompts, tool parameters, file content, or source code
- `user_prompt_length` is always recorded (length only); prompt text requires `OTEL_LOG_USER_PROMPTS=1` to be written
- Tool parameters (file paths, commands, etc.) require `OTEL_LOG_TOOL_DETAILS=1`; individual values exceeding 512 characters are truncated, with a total limit of ~4KB
- Full tool input/output requires `OTEL_LOG_TOOL_CONTENT=1`, recorded via span events, truncated at 60KB
- All opt-in switches are disabled by default; enterprise administrators can configure them uniformly via managed settings

## FAQ

### Does it conflict with the internal enterprise reporting channel?

No conflict. OTel custom export and the built-in standard reporting (`telemetry.report.standard`) are two independent channels and can be enabled simultaneously.

### Is metrics / logs supported?

Not yet supported, but planned. If you have a strong need, please provide feedback on the corresponding Issue.

### Is it compatible with Claude Code's OTEL format?

Yes. Span naming, attribute naming, and truncation strategies are aligned with Claude Code's conventions (`{product}.interaction` / `{product}.tool`), ensuring upstream analysis platforms can process them uniformly.
