π File detail
utils/telemetry/events.ts
π― Use case
This file lives under βutils/β, which covers cross-cutting helpers (shell, tempfiles, settings, messages, process input, β¦). On the API surface it exposes redactIfDisabled and logOTelEvent β mainly functions, hooks, or classes. Dependencies touch @opentelemetry and src. It composes internal code from debug, envUtils, and telemetryAttributes (relative imports).
Generated from folder role, exports, dependency roots, and inline comments β not hand-reviewed for every path.
π§ Inline summary
import type { Attributes } from '@opentelemetry/api' import { getEventLogger, getPromptId } from 'src/bootstrap/state.js' import { logForDebugging } from '../debug.js' import { isEnvTruthy } from '../envUtils.js' import { getTelemetryAttributes } from '../telemetryAttributes.js'
π€ Exports (heuristic)
redactIfDisabledlogOTelEvent
π External import roots
Package roots from from "β¦" (relative paths omitted).
@opentelemetrysrc
π₯οΈ Source preview
import type { Attributes } from '@opentelemetry/api'
import { getEventLogger, getPromptId } from 'src/bootstrap/state.js'
import { logForDebugging } from '../debug.js'
import { isEnvTruthy } from '../envUtils.js'
import { getTelemetryAttributes } from '../telemetryAttributes.js'
// Monotonically increasing counter for ordering events within a session
let eventSequence = 0
// Track whether we've already warned about a null event logger to avoid spamming
let hasWarnedNoEventLogger = false
function isUserPromptLoggingEnabled() {
return isEnvTruthy(process.env.OTEL_LOG_USER_PROMPTS)
}
export function redactIfDisabled(content: string): string {
return isUserPromptLoggingEnabled() ? content : '<REDACTED>'
}
export async function logOTelEvent(
eventName: string,
metadata: { [key: string]: string | undefined } = {},
): Promise<void> {
const eventLogger = getEventLogger()
if (!eventLogger) {
if (!hasWarnedNoEventLogger) {
hasWarnedNoEventLogger = true
logForDebugging(
`[3P telemetry] Event dropped (no event logger initialized): ${eventName}`,
{ level: 'warn' },
)
}
return
}
// Skip logging in test environment
if (process.env.NODE_ENV === 'test') {
return
}
const attributes: Attributes = {
...getTelemetryAttributes(),
'event.name': eventName,
'event.timestamp': new Date().toISOString(),
'event.sequence': eventSequence++,
}
// Add prompt ID to events (but not metrics, where it would cause unbounded cardinality)
const promptId = getPromptId()
if (promptId) {
attributes['prompt.id'] = promptId
}
// Workspace directory from the desktop app (host path). Events only β
// filesystem paths are too high-cardinality for metric dimensions, and
// the BQ metrics pipeline must never see them.
const workspaceDir = process.env.CLAUDE_CODE_WORKSPACE_HOST_PATHS
if (workspaceDir) {
attributes['workspace.host_paths'] = workspaceDir.split('|')
}
// Add metadata as attributes - all values are already strings
for (const [key, value] of Object.entries(metadata)) {
if (value !== undefined) {
attributes[key] = value
}
}
// Emit log record as an event
eventLogger.emit({
body: `claude_code.${eventName}`,
attributes,
})
}