/ utils / telemetryAttributes.ts
telemetryAttributes.ts
 1  import type { Attributes } from '@opentelemetry/api'
 2  import { getSessionId } from 'src/bootstrap/state.js'
 3  import { getOauthAccountInfo } from './auth.js'
 4  import { getOrCreateUserID } from './config.js'
 5  import { envDynamic } from './envDynamic.js'
 6  import { isEnvTruthy } from './envUtils.js'
 7  import { toTaggedId } from './taggedId.js'
 8  
 9  // Default configuration for metrics cardinality
10  const METRICS_CARDINALITY_DEFAULTS = {
11    OTEL_METRICS_INCLUDE_SESSION_ID: true,
12    OTEL_METRICS_INCLUDE_VERSION: false,
13    OTEL_METRICS_INCLUDE_ACCOUNT_UUID: true,
14  }
15  
16  function shouldIncludeAttribute(
17    envVar: keyof typeof METRICS_CARDINALITY_DEFAULTS,
18  ): boolean {
19    const defaultValue = METRICS_CARDINALITY_DEFAULTS[envVar]
20    const envValue = process.env[envVar]
21  
22    if (envValue === undefined) {
23      return defaultValue
24    }
25  
26    return isEnvTruthy(envValue)
27  }
28  
29  export function getTelemetryAttributes(): Attributes {
30    const userId = getOrCreateUserID()
31    const sessionId = getSessionId()
32  
33    const attributes: Attributes = {
34      'user.id': userId,
35    }
36  
37    if (shouldIncludeAttribute('OTEL_METRICS_INCLUDE_SESSION_ID')) {
38      attributes['session.id'] = sessionId
39    }
40    if (shouldIncludeAttribute('OTEL_METRICS_INCLUDE_VERSION')) {
41      attributes['app.version'] = MACRO.VERSION
42    }
43  
44    // Only include OAuth account data when actively using OAuth authentication
45    const oauthAccount = getOauthAccountInfo()
46    if (oauthAccount) {
47      const orgId = oauthAccount.organizationUuid
48      const email = oauthAccount.emailAddress
49      const accountUuid = oauthAccount.accountUuid
50  
51      if (orgId) attributes['organization.id'] = orgId
52      if (email) attributes['user.email'] = email
53  
54      if (
55        accountUuid &&
56        shouldIncludeAttribute('OTEL_METRICS_INCLUDE_ACCOUNT_UUID')
57      ) {
58        attributes['user.account_uuid'] = accountUuid
59        attributes['user.account_id'] =
60          process.env.CLAUDE_CODE_ACCOUNT_TAGGED_ID ||
61          toTaggedId('user', accountUuid)
62      }
63    }
64  
65    // Add terminal type if available
66    if (envDynamic.terminal) {
67      attributes['terminal.type'] = envDynamic.terminal
68    }
69  
70    return attributes
71  }