遥测与用户画像
Claude Code 的多管道遥测架构 — 664 种 tengu_ 事件、Datadog 实时监控、1P BigQuery 数据仓库、GrowthBook A/B 实验平台、用户画像收集、PII 分层保护的完整实现
职责概述
解决的问题:Anthropic 需要知道 CC 用得怎么样——哪些工具最受欢迎、什么操作最容易出错、A/B 测试的新功能有没有效果。但不能无脑收集数据,要在"收集产品洞察"和"保护用户隐私"之间找平衡。
应用场景:① 运维团队通过 Datadog 实时监控 API 错误率,发现问题秒级告警 ② 产品团队通过 BigQuery 分析"哪些工具组合最高效",指导产品迭代 ③ A/B 测试新功能(如自动压缩策略)的效果量化 ④ 组织管理员可以关闭指标上报,满足合规要求。
一句话理解:就像手机 App 的"使用数据分析"——开发者知道"20% 的用户在第三步流失了",但不知道"张三在第三步流失了"。
架构设计
数据流全景
logEvent() / logEventAsync()
│
┌───────┴───────┐
│ Event Queue │ ← Sink 未附加时缓存
└───────┬───────┘
│ Sink 附加后一次性排空
┌───────┴───────┐
│ Sink Router │ ← metadata.ts 注入上下文
└───┬───────┬───┘
┌───────────┘ └───────────┐
▼ ▼
┌─────────────────┐ ┌─────────────────────┐
│ Datadog Sink │ │ 1P Event Logger │
│ (白名单 64 种) │ │ (OTel LoggerProv.) │
└────────┬────────┘ └──────────┬──────────┘
│ │
▼ ▼
Datadog HTTP API FirstPartyEventLoggingExporter
(us5.datadoghq.com) (protobuf 序列化 + 重试)
│
▼
api.anthropic.com/event_logging/batch
│
▼
BigQuery 仓库
GrowthBook SDK (remoteEval)
│
├──→ Feature Gates (控制 Datadog 开关等)
├──→ Dynamic Configs (采样率、批次配置)
└──→ Experiment Exposures → 1P Event Logger
◉ 事件总线与队列
logEvent() 是整个遥测系统的统一入口。它实现了延迟绑定模式:在 Sink 附加前,所有事件缓存在内存队列中;Sink 附加后,队列一次性排空到真实管道。这确保了启动早期的事件(如初始化错误)不会丢失。
// services/analytics/index.ts
// 公共 API — 所有模块通过此函数上报事件
export function logEvent(
eventName: string,
eventProperties?: Record<string, unknown>,
analyticsMetadata?: AnalyticsMetadata_I_VERIFIED_THIS_IS_NOT_CODE_OR_FILEPATHS,
): void
// 异步版本 — 支持需要 await 的元数据收集
export async function logEventAsync(
eventName: string,
eventProperties?: Record<string, unknown>,
analyticsMetadata?: AnalyticsMetadata_I_VERIFIED_THIS_IS_NOT_CODE_OR_FILEPATHS,
): Promise<void>
// 类型标记:强制开发者显式验证字符串不含代码/文件路径
type AnalyticsMetadata_I_VERIFIED_THIS_IS_NOT_CODE_OR_FILEPATHS = {
[key: string]: string | boolean | number | null
}
// PII 标记:标记字段发送至特权 BigQuery 列
type AnalyticsMetadata_I_VERIFIED_THIS_IS_PII_TAGGED = {
_PROTO_EMAIL?: string
_PROTO_SKILL_NAME?: string
_PROTO_PLUGIN_NAME?: string
_PROTO_MARKETPLACE_NAME?: string
}
// Sink 未附加时 → 缓存到 eventQueue
// Sink 附加后 → 排空队列 + 后续事件直接分发
const eventQueue: QueuedEvent[] = []
I_VERIFIED_THIS_IS_NOT_CODE_OR_FILEPATHS 不是一个接口而是一个类型别名,开发者每次调用 logEvent 时必须显式声明变量类型,强制其确认数据合规。这是一种编译期的"勾选确认"机制。📊 Datadog 实时监控管道
Datadog 管道负责实时告警和运营监控。采用白名单机制(仅 64 种事件),用户 ID 哈希到 30 个桶(不可逆),仅限第一方 API 提供商。
// services/analytics/datadog.ts
const DATADOG_ENDPOINT = 'https://http-intake.logs.us5.datadoghq.com/api/v2/logs'
const DATADOG_CLIENT_TOKEN = 'pubbbf48e6d78dae54bceaa4acf463299bf' // 硬编码
// 批量配置
const FLUSH_INTERVAL_MS = 15_000 // 15 秒刷新
const MAX_BATCH_SIZE = 100 // 最大批次 100 条
// 白名单机制 — 仅发送以下事件
const DATADOG_ALLOWED_EVENTS = new Set([
'chrome_bridge_*', // Chrome 桥接
'tengu_api_error', // API 错误
'tengu_init', // 初始化
'tengu_tool_use_success', // 工具成功
'tengu_tool_use_error', // 工具失败
'tengu_started', // 启动
// ... 共约 64 种
])
// 用户隐私桶 — SHA-256 哈希后取模
function getUserBucket(userId: string): number {
const hash = createHash('sha256').update(userId).digest('hex')
return parseInt(hash.slice(0, 8), 16) % 30
}
// 仅第一方提供商(排除 Bedrock/Vertex/Foundry)
if (!isFirstPartyProvider()) return // 跳过第三方
🗄 1P 事件日志 — BigQuery 数据仓库
1P(First Party)管道是数据分析的核心,基于 OpenTelemetry 构建。全量收集 664 种事件,序列化为 Protobuf 格式,批量发送到 Anthropic API 后进入 BigQuery。支持失败重试、磁盘缓存和动态采样率配置。
// services/analytics/firstPartyEventLogger.ts
// 基于 OpenTelemetry LoggerProvider 构建
const provider = new LoggerProvider({
resource: new Resource({
'service.name': 'claude-code',
'service.version': VERSION,
}),
})
provider.addLogRecordProcessor(
new BatchLogRecordProcessor(exporter, {
scheduledDelayMillis: 5000, // 5 秒刷新
maxExportBatchSize: 512, // 最大批次 512
maxQueueSize: 2048, // 队列上限 2048
})
)
// 每个事件的结构
interface ClaudeCodeInternalEvent {
event_id: string // UUID
core_metadata: {
model: string // 模型名称
session_id: string // 会话 ID
user_type: string // ant | external
beta_features: string[] // 启用的 beta 特性
entrypoint: string // cli | sdk | unknown
interaction_mode: string // 交互模式
client_type: string // 客户端类型
agent_id?: string // Agent 标识
agent_type?: string // teammate | subagent | standalone
team_name?: string // 团队名
subscription_type?: string // max | pro | enterprise | team
}
user_metadata: {
device_id: string // 设备 ID
session_id: string // 会话 ID
email?: string // 用户邮箱(PII)
app_version: string // 应用版本
platform: string // 平台
organization_uuid?: string
account_uuid?: string
}
event_metadata: Record<string, unknown> // 事件特有属性
}
失败处理:磁盘缓存 + 指数退避
// services/analytics/firstPartyEventLoggingExporter.ts
// 失败事件写入磁盘缓存
const FAILED_EVENTS_DIR = '~/.claude/telemetry/'
const FAILED_EVENTS_FILE = '1p_failed_events.*.json'
// 指数退避重试
const MAX_RETRIES = 8
const BASE_DELAY_MS = 1000 // 1s, 2s, 4s, 8s, 16s, 32s, 64s, 128s
async function exportWithRetry(events: LogRecord[]): Promise<void> {
for (let attempt = 0; attempt < MAX_RETRIES; attempt++) {
try {
await this.sendBatch(events)
return
} catch (error) {
if (attempt === MAX_RETRIES - 1) {
// 最终失败 → 写入磁盘缓存
await this.persistFailedEvents(events)
return
}
await this.delay(BASE_DELAY_MS * Math.pow(2, attempt))
}
}
}
// 支持动态配置(通过 GrowthBook)
// - 批次大小、延迟、端点 URL、采样率均可远程调整
⚗ GrowthBook A/B 实验平台
GrowthBook 是 CC 的特性开关和 A/B 测试平台。通过远程评估模式获取实验配置,控制 Datadog 开关、采样率、反蒸馏策略等。用户属性用于实验分组,实验曝光记录写入 1P 事件系统。
// services/analytics/growthbook.ts
const gb = new GrowthBook({
apiHost: 'https://api.anthropic.com/',
remoteEval: true, // 远程评估模式
attributes: { // 用户属性 — 实验分组依据
id: userId,
sessionId: sessionId,
deviceID: deviceId,
platform: platform,
apiBaseUrlHost: apiHost,
organizationUUID: orgUuid,
accountUUID: accountUuid,
userType: userType, // ant | external
subscriptionType: subscription, // max | pro | enterprise | team
rateLimitTier: tier,
firstTokenTime: firstTokenTime,
email: email,
appVersion: version,
github: { // CI 环境上下文
eventName: ghEventName,
repository: ghRepo,
runnerEnvironment: ghRunner,
},
},
})
// 特性缓存到磁盘(~/.claude.json → cachedGrowthBookFeatures)
// 外部用户: 6 小时刷新
// Anth 内部: 20 分钟刷新
// 关键 Feature Gates
// tengu_log_datadog_events — Datadog 管道总开关
// tengu_frond_boric — 管道级熔断(datadog | firstParty)
// tengu_anti_distill_fake_tool_injection — 假工具注入开关
// tengu_thinking_redaction — 思维链脱敏开关
// tengu_event_sampling_config — 事件采样率动态配置
⚙ 元数据收集引擎
每个遥测事件都通过 metadata.ts 注入标准化的上下文信息,包括环境、进程、工具名称清洗和文件扩展名提取。
// services/analytics/metadata.ts
interface EventMetadata {
// 环境上下文 (EnvContext)
env: {
platform: string // darwin | linux | win32
arch: string // x64 | arm64
nodeVersion: string // Node.js 版本
terminal: string // 终端类型
packageManagers: string[] // 检测到的包管理器
runtimes: string[] // Bun | Node
isCi: boolean // 是否 CI 环境
version: string // CC 版本
buildTime: string // 构建时间
deploymentEnvironment: string
wslVersion?: string // WSL 版本
linuxDistro?: string // Linux 发行版
vcs?: string // git | none
githubActions?: { // GitHub Actions 元数据
eventName: string
repository: string
actor: string
ref: string
runnerOS: string
}
remoteEnvironmentType?: string // 远程环境类型
containerId?: string // 容器 ID
}
// 进程指标 (ProcessMetrics)
process: {
uptime: number // 进程运行时间
rss: number // 常驻内存集
heapTotal: number // 堆总量
heapUsed: number // 堆使用量
external: number // 外部内存
arrayBuffers: number // ArrayBuffer 内存
constrainedMemory?: number // 内存限制
cpuUsage: number // CPU 使用率(%)
}
// Agent 标识
agentId?: string // 当前 Agent ID
parentSessionId?: string // 父会话 ID
agentType?: string // teammate | subagent | standalone
teamName?: string // 团队名称
}
// 工具名称清洗 — MCP 工具名统一归一化
// 原始: "mcp__plugin_ecc_playwright__browser_click"
// 清洗后: "mcp_tool"(防止泄漏自定义插件名)
// 但存在白名单豁免:特定已知 MCP 工具保留原始名称
// 文件扩展名提取 — 从 Bash 命令中提取
// "sed -i 's/foo/bar/' config.yaml" → ".yaml"
// "python3 train.py && python3 eval.py" → ".py,.py"
mcp_tool 是为了保护用户隐私(防止泄漏自定义工具名),但白名单豁免又暴露了部分已知 MCP 工具。这说明完全匿名化会影响数据分析的实用性,需要在隐私和可观测性之间取舍。👤 用户画像维度
CC 收集的用户画像数据覆盖 5 个维度,用于产品分析、计费追踪和实验分组。所有 PII 数据通过 _PROTO_ 前缀标记,仅在特权管道中传输。
维度 1:身份标识
// utils/user.ts — CoreUserData
{
deviceId: string // 持久化设备 ID(~/.claude.json)
sessionId: string // 会话 ID(每次启动生成)
email: string // OAuth 邮箱
organizationUuid: string // 组织 UUID
accountUuid: string // 账户 UUID
userType: 'ant' | 'external'
subscriptionType: 'max' | 'pro' | 'enterprise' | 'team' | null
rateLimitTier: string // 速率限制层级
firstTokenTime: string // 首次使用时间
}
维度 2:运行环境
// 从 process, os, env 自动采集
{
platform: 'darwin' | 'linux' | 'win32'
arch: 'x64' | 'arm64'
nodeVersion: 'v22.x.x'
terminal: 'iTerm.app' | 'vscode' | 'jetbrains'
packageManagers: ['npm', 'yarn', 'pnpm']
runtimes: ['bun', 'node']
isCi: boolean // CI 环境检测
containerId?: string // Docker 容器 ID
wslVersion?: string // WSL 版本
linuxDistro?: string // Ubuntu 22.04 等
vcs: 'git' | 'none'
}
维度 3:行为模式
// 664 种 tengu_ 事件覆盖的行为
{
toolUsage: { // 工具使用统计
toolName: string // 具体工具名
success: boolean
duration: number
fileExtensions: string[] // 操作的文件类型
}
gitOperations: { // Git 操作追踪
operation: 'commit' | 'push' | 'pr_create' | 'merge' | 'rebase'
success: boolean
}
modelUsage: { // 模型使用情况
model: string
tokenUsage: { input, output, cacheRead, cacheWrite, webSearch }
cost: number
}
sessionPattern: { // 会话模式
interactionMode: string
autoModeEnabled: boolean
compactTriggered: boolean
resumeCount: number
}
}
维度 4:系统资源
// 每事件注入的进程指标(base64 编码)
{
rss: number // 常驻内存集
heapTotal: number // 堆总量
heapUsed: number // 堆使用量
cpuUsage: number // CPU 使用率
uptime: number // 进程运行时间
}
维度 5:CI/CD 上下文
// GitHub Actions 环境自动采集
{
githubActions: {
eventName: 'push' | 'pull_request' | 'workflow_dispatch'
repository: 'owner/repo'
actor: 'username'
ref: 'refs/heads/main'
runnerOS: 'ubuntu-latest'
runnerEnvironment: 'github-hosted' | 'self-hosted'
}
}
🛡 隐私保护机制
CC 构建了多层隐私保护:类型级 PII 标记、管道级剥离、用户级 opt-out、组织级 metrics 控制。
1. PII 分层标记与管道剥离
// services/analytics/index.ts
// PII 字段用 _PROTO_ 前缀标记
interface PIIFields {
_PROTO_EMAIL?: string // 用户邮箱
_PROTO_SKILL_NAME?: string // Skill 名称
_PROTO_PLUGIN_NAME?: string // 插件名称
_PROTO_MARKETPLACE_NAME?: string // 市场名称
}
// Datadog 管道发送前:stripProtoFields() 剥离所有 _PROTO_* 字段
// 1P 管道发送前:保留 _PROTO_* 字段,写入 BigQuery 特权列
// 这确保 PII 数据只在内部数据仓库中可见,不会泄漏到 Datadog
2. 三级隐私控制
// utils/privacyLevel.ts
type PrivacyLevel = 'default' | 'no-telemetry' | 'essential-traffic'
// default: 正常收集所有遥测数据
// no-telemetry: 禁用分析事件,保留必要 API 调用
// essential-traffic: 仅保留认证和 API 请求
// 控制方式:
// DISABLE_TELEMETRY=1 → no-telemetry
// CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC=1 → essential-traffic
// 配置入口:
// commands/privacy-settings/privacy-settings.tsx
// → "Help improve Claude" (Grove) 开关
// → 记录 tengu_grove_policy_toggled 事件
3. 组织级 Metrics Opt-Out
// services/api/metricsOptOut.ts
// 查询组织是否启用了指标记录
// GET https://api.anthropic.com/api/claude_code/organizations/metrics_enabled
// 响应: { enabled: boolean }
// 缓存策略:
// - 磁盘缓存: 24 小时
// - 内存缓存: 1 小时
// → 避免每次启动都查询 API
4. 第三方提供商排除
Datadog 管道对 Bedrock/Vertex/Foundry 用户完全跳过 — 第三方 API 提供商的用户数据不会发送到 Anthropic 的 Datadog 实例。1P 事件日志仍然收集,但标记了提供商类型。
📋 事件分类体系
664 种 tengu_ 前缀事件按功能域分为以下类别:
| 类别 | 事件前缀 | 典型事件 | 路由 |
|---|---|---|---|
| API 层 | tengu_api_* | query, error, success, retry, timeout | Datadog + 1P |
| 工具使用 | tengu_tool_use_* | success, error, granted_in_prompt_* | Datadog + 1P |
| 会话管理 | tengu_started/exit/resumed/continue | 启动、退出、恢复、继续 | 1P |
| Git 操作 | tengu_git_operation | commit, push, pr_create, merge, rebase | 1P |
| 模型管理 | tengu_model_* | fallback_triggered, manual_config | 1P |
| 自动模式 | tengu_auto_* | mode_*, compact_* | 1P |
| MCP | tengu_mcp_* | channel_flags, tool_use | 1P |
| 认证 | tengu_oauth_*/tengu_api_key_* | login, refresh, token_exchange | 1P |
| Agent | tengu_agent_* | spawn, complete, tool_* | 1P |
| 成本 | tengu_advisor_* | tool_token_usage | 1P |
| 隐私 | tengu_grove_* | policy_toggled | 1P |
| 初始化 | tengu_init | 启动初始化 | Datadog + 1P |
设计模式与亮点
1. 延迟绑定队列 — 启动早期事件不丢失
事件总线在 Sink 附加前将所有事件缓存在内存队列中。这解决了经典的"鸡和蛋"问题:遥测系统本身初始化时可能出错,这些错误事件也需要被记录。Sink 附加后一次性排空,确保无丢失。
2. 类型级 PII 强制验证
I_VERIFIED_THIS_IS_NOT_CODE_OR_FILEPATHS 不是运行时检查,而是编译期类型标记。开发者必须显式声明才能调用 logEvent,这是一种低成本高效率的代码审查提示机制。
3. 管道级熔断与动态配置
GrowthBook 的 tengu_frond_boric 配置可以独立关闭 Datadog 或 1P 管道,tengu_event_sampling_config 可以动态调整采样率。这意味着 Anthropic 可以在不发版的情况下应对数据管道故障或成本压力。
4. 用户桶代替用户 ID
Datadog 管道将用户 ID 哈希到 30 个桶,实现了"知道多少人受影响,不知道是谁受影响"的隐私目标。这是差分隐私思想在实际工程中的轻量应用。
5. 磁盘缓存保障数据不丢
1P Exporter 的失败事件写入 ~/.claude/telemetry/,配合指数退避重试(最多 8 次,总延迟约 4 分钟),确保网络抖动不会导致数据丢失。GrowthBook 配置也缓存到磁盘,离线启动时使用缓存值。
6. 工具名清洗的取舍
MCP 工具名统一替换为 mcp_tool,但已知安全工具保留原名。这种"默认匿名 + 白名单豁免"的模式是隐私保护与数据实用性之间的工程折衷。
◈ Agent 实践借鉴 — 垂直 Agent 的遥测体系
场景映射:客服 Agent 的遥测需求
客服 Agent 需要追踪:对话质量(解决率/满意度)、工具调用效率(API 成功率/延迟)、用户画像(使用频率/付费层级)、系统健康(内存/CPU/错误率)。CC 的遥测架构提供了完整的参考实现。
借鉴 CC:三管道遥测架构
// 客服 Agent 遥测架构 — 借鉴 CC 的多管道设计
class AgentTelemetry {
// 管道 1:实时告警(对应 CC 的 Datadog)
// 用 Prometheus + Grafana 替代 Datadog
async pushAlert(event: AlertEvent): Promise<void> {
// 白名单机制:仅告警类事件进此管道
if (!this.ALERT_EVENTS.has(event.name)) return
await this.prometheus.push(event)
}
// 管道 2:数据仓库(对应 CC 的 1P BigQuery)
// 用 ClickHouse 替代 BigQuery
async logToWarehouse(event: AgentEvent): Promise<void> {
// 全量事件 + 元数据丰富
const enriched = this.enrichMetadata(event)
await this.clickhouse.insert('agent_events', enriched)
}
// 管道 3:实验平台(对应 CC 的 GrowthBook)
// 用自建 AB Platform 或 LaunchDarkly
async trackExperiment(userId: string, experimentId: string): Promise<void> {
const variant = this.abPlatform.getVariant(userId, experimentId)
await this.logToWarehouse({
name: 'experiment_exposure',
properties: { experimentId, variant },
})
}
// 元数据丰富(对应 CC 的 metadata.ts)
private enrichMetadata(event: AgentEvent): EnrichedEvent {
return {
...event,
env: this.collectEnvContext(), // 平台、版本、运行时
process: this.collectProcessMetrics(), // 内存、CPU
user: this.collectUserContext(), // 用户类型、订阅级别
session: this.collectSessionContext(), // 会话 ID、对话轮数
}
}
// 隐私控制(对应 CC 的 stripProtoFields)
private stripPII(event: EnrichedEvent): SafeEvent {
const { _PII_EMAIL, _PII_PHONE, ...safe } = event as any
return safe
}
}
落地清单
- 延迟绑定队列:确保启动早期事件不丢失。Agent 初始化过程中的错误最关键。
- PII 分层标记:敏感字段用前缀标记,告警管道自动剥离,数据仓库管道保留。
- 管道级熔断:任一管道故障不影响其他管道。动态配置可以远程关闭。
- 工具名清洗:第三方集成工具名统一归一化,防止泄漏客户自定义工具。
- Datadog 硬编码 Token:这是 CC 特有的,自建系统用环境变量注入。
- 用户桶哈希:客服场景用户数有限,直接用匿名 ID 即可,不需要桶。
- GrowthBook 远程评估:初期用本地配置文件就够了,规模上来后再引入远程配置。
代码索引
| 文件 | 行数 | 说明 |
|---|---|---|
services/analytics/index.ts | ~200 | 事件总线入口:logEvent/logEventAsync、事件队列、PII 标记类型 |
services/analytics/datadog.ts | ~250 | Datadog 管道:批量发送、白名单、用户桶、第三方排除 |
services/analytics/firstPartyEventLogger.ts | ~300 | 1P 事件日志:OTel LoggerProvider、事件结构、GrowthBook 集成 |
services/analytics/firstPartyEventLoggingExporter.ts | ~350 | 1P 导出器:Protobuf 序列化、失败缓存、指数退避重试 |
services/analytics/growthbook.ts | ~300 | GrowthBook SDK:远程评估、用户属性、特性缓存、实验曝光 |
services/analytics/metadata.ts | ~400 | 元数据收集:环境上下文、进程指标、工具名清洗、文件扩展名 |
services/analytics/sink.ts | ~120 | 路由 Sink:Datadog + 1P 双管道分发、PII 剥离 |
services/analytics/sinkKillswitch.ts | ~50 | 管道熔断:GrowthBook 动态配置控制 |
services/analytics/config.ts | ~60 | 分析配置:禁用条件(测试/第三方/用户 opt-out) |
utils/user.ts | ~200 | 用户核心数据:设备 ID、会话 ID、邮箱、组织、订阅类型 |
utils/telemetryAttributes.ts | ~50 | OTel 遥测属性定义 |
utils/telemetry/bigqueryExporter.ts | ~150 | BigQuery 指标导出器:OTel → Anthropic API |
utils/privacyLevel.ts | ~60 | 隐私三级控制:default / no-telemetry / essential-traffic |
services/diagnosticTracking.ts | ~100 | 诊断追踪:IDE 文件编辑前后的错误/警告 |
tools/shared/gitOperationTracking.ts | ~80 | Git 操作追踪:commit/push/pr/merge/rebase |
cost-tracker.ts | ~200 | 费用追踪:token 用量 + 成本统计 |
services/api/metricsOptOut.ts | ~80 | 组织级指标 opt-out:API 查询 + 双层缓存 |
services/api/usage.ts | ~100 | 使用量查询:速率限制利用率 |
commands/privacy-settings/privacy-settings.tsx | ~150 | 隐私设置 UI:Grove 开关 |