Download packages/core/src/telemetry/loggers.ts from SaylorTwift/gemini-cli: direct link, hf CLI and curl.
- Browser
- Download file 30.3 kB
-
https://huggingface.co/SaylorTwift/gemini-cli/resolve/main/packages/core/src/telemetry/loggers.ts
- Command line
-
hf download hf://SaylorTwift/gemini-cli/packages/core/src/telemetry/loggers.ts
-
curl -L -o loggers.ts https://huggingface.co/SaylorTwift/gemini-cli/resolve/main/packages/core/src/telemetry/loggers.ts
30.3 kB
| /** | |
| * @license | |
| * Copyright 2025 Google LLC | |
| * SPDX-License-Identifier: Apache-2.0 | |
| */ | |
| import { logs, type LogRecord } from '@opentelemetry/api-logs'; | |
| import type { Config } from '../config/config.js'; | |
| import { SERVICE_NAME } from './constants.js'; | |
| import { | |
| EVENT_API_ERROR, | |
| EVENT_API_RESPONSE, | |
| EVENT_TOOL_CALL, | |
| EVENT_REWIND, | |
| type ApiErrorEvent, | |
| type ApiRequestEvent, | |
| type ApiResponseEvent, | |
| type FileOperationEvent, | |
| type IdeConnectionEvent, | |
| type StartSessionEvent, | |
| type ToolCallEvent, | |
| type UserPromptEvent, | |
| type FlashFallbackEvent, | |
| type NextSpeakerCheckEvent, | |
| type LoopDetectedEvent, | |
| type LoopDetectionDisabledEvent, | |
| type SlashCommandEvent, | |
| type RewindEvent, | |
| type ConversationFinishedEvent, | |
| type ChatCompressionEvent, | |
| type MalformedJsonResponseEvent, | |
| type InvalidChunkEvent, | |
| type ContentRetryEvent, | |
| type ContentRetryFailureEvent, | |
| type NetworkRetryAttemptEvent, | |
| type RipgrepFallbackEvent, | |
| type ToolOutputTruncatedEvent, | |
| type ModelRoutingEvent, | |
| type ExtensionDisableEvent, | |
| type ExtensionEnableEvent, | |
| type ExtensionUninstallEvent, | |
| type ExtensionInstallEvent, | |
| type ModelSlashCommandEvent, | |
| type EditStrategyEvent, | |
| type EditCorrectionEvent, | |
| type AgentStartEvent, | |
| type AgentFinishEvent, | |
| type RecoveryAttemptEvent, | |
| type WebFetchFallbackAttemptEvent, | |
| type ExtensionUpdateEvent, | |
| type ApprovalModeSwitchEvent, | |
| type ApprovalModeDurationEvent, | |
| type HookCallEvent, | |
| type StartupStatsEvent, | |
| type LlmLoopCheckEvent, | |
| type PlanExecutionEvent, | |
| type ToolOutputMaskingEvent, | |
| type KeychainAvailabilityEvent, | |
| type TokenStorageInitializationEvent, | |
| type OnboardingStartEvent, | |
| type OnboardingSuccessEvent, | |
| } from './types.js'; | |
| import { | |
| recordApiErrorMetrics, | |
| recordToolCallMetrics, | |
| recordChatCompressionMetrics, | |
| recordFileOperationMetric, | |
| recordRetryAttemptMetrics, | |
| recordContentRetry, | |
| recordContentRetryFailure, | |
| recordModelRoutingMetrics, | |
| recordModelSlashCommand, | |
| getConventionAttributes, | |
| recordTokenUsageMetrics, | |
| recordApiResponseMetrics, | |
| recordAgentRunMetrics, | |
| recordRecoveryAttemptMetrics, | |
| recordLinesChanged, | |
| recordHookCallMetrics, | |
| recordPlanExecution, | |
| recordKeychainAvailability, | |
| recordTokenStorageInitialization, | |
| recordInvalidChunk, | |
| recordOnboardingStart, | |
| recordOnboardingSuccess, | |
| recordBrowserAgentConnection, | |
| recordBrowserAgentVisionStatus, | |
| recordBrowserAgentTaskOutcome, | |
| recordBrowserAgentCleanup, | |
| } from './metrics.js'; | |
| import { bufferTelemetryEvent } from './sdk.js'; | |
| import { uiTelemetryService, type UiEvent } from './uiTelemetry.js'; | |
| import { ClearcutLogger } from './clearcut-logger/clearcut-logger.js'; | |
| import { debugLogger } from '../utils/debugLogger.js'; | |
| import type { BillingTelemetryEvent } from './billingEvents.js'; | |
| import { | |
| CreditsUsedEvent, | |
| OverageOptionSelectedEvent, | |
| EmptyWalletMenuShownEvent, | |
| CreditPurchaseClickEvent, | |
| } from './billingEvents.js'; | |
| export function logCliConfiguration( | |
| config: Config, | |
| event: StartSessionEvent, | |
| ): void { | |
| void ClearcutLogger.getInstance(config)?.logStartSessionEvent(event); | |
| bufferTelemetryEvent(() => { | |
| // Wait for experiments to load before emitting so we capture experimentIds | |
| void config | |
| .getExperimentsAsync() | |
| .then(() => { | |
| const logger = logs.getLogger(SERVICE_NAME); | |
| const logRecord: LogRecord = { | |
| body: event.toLogBody(), | |
| attributes: event.toOpenTelemetryAttributes(config), | |
| }; | |
| logger.emit(logRecord); | |
| }) | |
| .catch((e: unknown) => { | |
| debugLogger.error('Failed to log telemetry event', e); | |
| }); | |
| }); | |
| } | |
| export function logUserPrompt(config: Config, event: UserPromptEvent): void { | |
| ClearcutLogger.getInstance(config)?.logNewPromptEvent(event); | |
| bufferTelemetryEvent(() => { | |
| const logger = logs.getLogger(SERVICE_NAME); | |
| const logRecord: LogRecord = { | |
| body: event.toLogBody(), | |
| attributes: event.toOpenTelemetryAttributes(config), | |
| }; | |
| logger.emit(logRecord); | |
| }); | |
| } | |
| export function logToolCall(config: Config, event: ToolCallEvent): void { | |
| // eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion | |
| const uiEvent = { | |
| // eslint-disable-next-line @typescript-eslint/no-misused-spread | |
| ...event, | |
| 'event.name': EVENT_TOOL_CALL, | |
| 'event.timestamp': new Date().toISOString(), | |
| } as UiEvent; | |
| uiTelemetryService.addEvent(uiEvent); | |
| ClearcutLogger.getInstance(config)?.logToolCallEvent(event); | |
| bufferTelemetryEvent(() => { | |
| const logger = logs.getLogger(SERVICE_NAME); | |
| const logRecord: LogRecord = { | |
| body: event.toLogBody(), | |
| attributes: event.toOpenTelemetryAttributes(config), | |
| }; | |
| logger.emit(logRecord); | |
| recordToolCallMetrics(config, event.duration_ms, { | |
| function_name: event.function_name, | |
| success: event.success, | |
| decision: event.decision, | |
| tool_type: event.tool_type, | |
| }); | |
| if (event.metadata) { | |
| // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment | |
| const added = event.metadata['model_added_lines']; | |
| if (typeof added === 'number' && added > 0) { | |
| recordLinesChanged(config, added, 'added', { | |
| function_name: event.function_name, | |
| }); | |
| } | |
| // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment | |
| const removed = event.metadata['model_removed_lines']; | |
| if (typeof removed === 'number' && removed > 0) { | |
| recordLinesChanged(config, removed, 'removed', { | |
| function_name: event.function_name, | |
| }); | |
| } | |
| } | |
| }); | |
| } | |
| export function logToolOutputTruncated( | |
| config: Config, | |
| event: ToolOutputTruncatedEvent, | |
| ): void { | |
| ClearcutLogger.getInstance(config)?.logToolOutputTruncatedEvent(event); | |
| bufferTelemetryEvent(() => { | |
| const logger = logs.getLogger(SERVICE_NAME); | |
| const logRecord: LogRecord = { | |
| body: event.toLogBody(), | |
| attributes: event.toOpenTelemetryAttributes(config), | |
| }; | |
| logger.emit(logRecord); | |
| }); | |
| } | |
| export function logToolOutputMasking( | |
| config: Config, | |
| event: ToolOutputMaskingEvent, | |
| ): void { | |
| ClearcutLogger.getInstance(config)?.logToolOutputMaskingEvent(event); | |
| bufferTelemetryEvent(() => { | |
| const logger = logs.getLogger(SERVICE_NAME); | |
| const logRecord: LogRecord = { | |
| body: event.toLogBody(), | |
| attributes: event.toOpenTelemetryAttributes(config), | |
| }; | |
| logger.emit(logRecord); | |
| }); | |
| } | |
| export function logFileOperation( | |
| config: Config, | |
| event: FileOperationEvent, | |
| ): void { | |
| ClearcutLogger.getInstance(config)?.logFileOperationEvent(event); | |
| bufferTelemetryEvent(() => { | |
| const logger = logs.getLogger(SERVICE_NAME); | |
| const logRecord: LogRecord = { | |
| body: event.toLogBody(), | |
| attributes: event.toOpenTelemetryAttributes(config), | |
| }; | |
| logger.emit(logRecord); | |
| recordFileOperationMetric(config, { | |
| operation: event.operation, | |
| lines: event.lines, | |
| mimetype: event.mimetype, | |
| extension: event.extension, | |
| programming_language: event.programming_language, | |
| }); | |
| }); | |
| } | |
| export function logApiRequest(config: Config, event: ApiRequestEvent): void { | |
| ClearcutLogger.getInstance(config)?.logApiRequestEvent(event); | |
| bufferTelemetryEvent(() => { | |
| const logger = logs.getLogger(SERVICE_NAME); | |
| logger.emit(event.toLogRecord(config)); | |
| logger.emit(event.toSemanticLogRecord(config)); | |
| }); | |
| } | |
| export function logFlashFallback( | |
| config: Config, | |
| event: FlashFallbackEvent, | |
| ): void { | |
| ClearcutLogger.getInstance(config)?.logFlashFallbackEvent(); | |
| bufferTelemetryEvent(() => { | |
| const logger = logs.getLogger(SERVICE_NAME); | |
| const logRecord: LogRecord = { | |
| body: event.toLogBody(), | |
| attributes: event.toOpenTelemetryAttributes(config), | |
| }; | |
| logger.emit(logRecord); | |
| }); | |
| } | |
| export function logRipgrepFallback( | |
| config: Config, | |
| event: RipgrepFallbackEvent, | |
| ): void { | |
| ClearcutLogger.getInstance(config)?.logRipgrepFallbackEvent(); | |
| bufferTelemetryEvent(() => { | |
| const logger = logs.getLogger(SERVICE_NAME); | |
| const logRecord: LogRecord = { | |
| body: event.toLogBody(), | |
| attributes: event.toOpenTelemetryAttributes(config), | |
| }; | |
| logger.emit(logRecord); | |
| }); | |
| } | |
| export function logApiError(config: Config, event: ApiErrorEvent): void { | |
| // eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion | |
| const uiEvent = { | |
| // eslint-disable-next-line @typescript-eslint/no-misused-spread | |
| ...event, | |
| 'event.name': EVENT_API_ERROR, | |
| 'event.timestamp': new Date().toISOString(), | |
| } as UiEvent; | |
| uiTelemetryService.addEvent(uiEvent); | |
| ClearcutLogger.getInstance(config)?.logApiErrorEvent(event); | |
| bufferTelemetryEvent(() => { | |
| const logger = logs.getLogger(SERVICE_NAME); | |
| logger.emit(event.toLogRecord(config)); | |
| logger.emit(event.toSemanticLogRecord(config)); | |
| recordApiErrorMetrics(config, event.duration_ms, { | |
| model: event.model, | |
| status_code: event.status_code, | |
| error_type: event.error_type, | |
| }); | |
| // Record GenAI operation duration for errors | |
| recordApiResponseMetrics(config, event.duration_ms, { | |
| model: event.model, | |
| status_code: event.status_code, | |
| genAiAttributes: { | |
| ...getConventionAttributes(event), | |
| 'error.type': event.error_type || 'unknown', | |
| }, | |
| }); | |
| }); | |
| } | |
| export function logApiResponse(config: Config, event: ApiResponseEvent): void { | |
| // eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion | |
| const uiEvent = { | |
| // eslint-disable-next-line @typescript-eslint/no-misused-spread | |
| ...event, | |
| 'event.name': EVENT_API_RESPONSE, | |
| 'event.timestamp': new Date().toISOString(), | |
| } as UiEvent; | |
| uiTelemetryService.addEvent(uiEvent); | |
| ClearcutLogger.getInstance(config)?.logApiResponseEvent(event); | |
| bufferTelemetryEvent(() => { | |
| const logger = logs.getLogger(SERVICE_NAME); | |
| logger.emit(event.toLogRecord(config)); | |
| logger.emit(event.toSemanticLogRecord(config)); | |
| const conventionAttributes = getConventionAttributes(event); | |
| recordApiResponseMetrics(config, event.duration_ms, { | |
| model: event.model, | |
| status_code: event.status_code, | |
| genAiAttributes: conventionAttributes, | |
| }); | |
| const tokenUsageData = [ | |
| { count: event.usage.input_token_count, type: 'input' as const }, | |
| { count: event.usage.output_token_count, type: 'output' as const }, | |
| { count: event.usage.cached_content_token_count, type: 'cache' as const }, | |
| { count: event.usage.thoughts_token_count, type: 'thought' as const }, | |
| { count: event.usage.tool_token_count, type: 'tool' as const }, | |
| ]; | |
| for (const { count, type } of tokenUsageData) { | |
| recordTokenUsageMetrics(config, count, { | |
| model: event.model, | |
| type, | |
| genAiAttributes: conventionAttributes, | |
| }); | |
| } | |
| }); | |
| } | |
| export function logLoopDetected( | |
| config: Config, | |
| event: LoopDetectedEvent, | |
| ): void { | |
| ClearcutLogger.getInstance(config)?.logLoopDetectedEvent(event); | |
| bufferTelemetryEvent(() => { | |
| const logger = logs.getLogger(SERVICE_NAME); | |
| const logRecord: LogRecord = { | |
| body: event.toLogBody(), | |
| attributes: event.toOpenTelemetryAttributes(config), | |
| }; | |
| logger.emit(logRecord); | |
| }); | |
| } | |
| export function logLoopDetectionDisabled( | |
| config: Config, | |
| event: LoopDetectionDisabledEvent, | |
| ): void { | |
| ClearcutLogger.getInstance(config)?.logLoopDetectionDisabledEvent(); | |
| bufferTelemetryEvent(() => { | |
| const logger = logs.getLogger(SERVICE_NAME); | |
| const logRecord: LogRecord = { | |
| body: event.toLogBody(), | |
| attributes: event.toOpenTelemetryAttributes(config), | |
| }; | |
| logger.emit(logRecord); | |
| }); | |
| } | |
| export function logNextSpeakerCheck( | |
| config: Config, | |
| event: NextSpeakerCheckEvent, | |
| ): void { | |
| ClearcutLogger.getInstance(config)?.logNextSpeakerCheck(event); | |
| bufferTelemetryEvent(() => { | |
| const logger = logs.getLogger(SERVICE_NAME); | |
| const logRecord: LogRecord = { | |
| body: event.toLogBody(), | |
| attributes: event.toOpenTelemetryAttributes(config), | |
| }; | |
| logger.emit(logRecord); | |
| }); | |
| } | |
| export function logSlashCommand( | |
| config: Config, | |
| event: SlashCommandEvent, | |
| ): void { | |
| ClearcutLogger.getInstance(config)?.logSlashCommandEvent(event); | |
| bufferTelemetryEvent(() => { | |
| const logger = logs.getLogger(SERVICE_NAME); | |
| const logRecord: LogRecord = { | |
| body: event.toLogBody(), | |
| attributes: event.toOpenTelemetryAttributes(config), | |
| }; | |
| logger.emit(logRecord); | |
| }); | |
| } | |
| export function logRewind(config: Config, event: RewindEvent): void { | |
| // eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion | |
| const uiEvent = { | |
| // eslint-disable-next-line @typescript-eslint/no-misused-spread | |
| ...event, | |
| 'event.name': EVENT_REWIND, | |
| 'event.timestamp': new Date().toISOString(), | |
| } as UiEvent; | |
| uiTelemetryService.addEvent(uiEvent); | |
| ClearcutLogger.getInstance(config)?.logRewindEvent(event); | |
| bufferTelemetryEvent(() => { | |
| const logger = logs.getLogger(SERVICE_NAME); | |
| const logRecord: LogRecord = { | |
| body: event.toLogBody(), | |
| attributes: event.toOpenTelemetryAttributes(config), | |
| }; | |
| logger.emit(logRecord); | |
| }); | |
| } | |
| export function logIdeConnection( | |
| config: Config, | |
| event: IdeConnectionEvent, | |
| ): void { | |
| ClearcutLogger.getInstance(config)?.logIdeConnectionEvent(event); | |
| bufferTelemetryEvent(() => { | |
| const logger = logs.getLogger(SERVICE_NAME); | |
| const logRecord: LogRecord = { | |
| body: event.toLogBody(), | |
| attributes: event.toOpenTelemetryAttributes(config), | |
| }; | |
| logger.emit(logRecord); | |
| }); | |
| } | |
| export function logConversationFinishedEvent( | |
| config: Config, | |
| event: ConversationFinishedEvent, | |
| ): void { | |
| ClearcutLogger.getInstance(config)?.logConversationFinishedEvent(event); | |
| bufferTelemetryEvent(() => { | |
| const logger = logs.getLogger(SERVICE_NAME); | |
| const logRecord: LogRecord = { | |
| body: event.toLogBody(), | |
| attributes: event.toOpenTelemetryAttributes(config), | |
| }; | |
| logger.emit(logRecord); | |
| }); | |
| } | |
| export function logChatCompression( | |
| config: Config, | |
| event: ChatCompressionEvent, | |
| ): void { | |
| ClearcutLogger.getInstance(config)?.logChatCompressionEvent(event); | |
| const logger = logs.getLogger(SERVICE_NAME); | |
| const logRecord: LogRecord = { | |
| body: event.toLogBody(), | |
| attributes: event.toOpenTelemetryAttributes(config), | |
| }; | |
| logger.emit(logRecord); | |
| recordChatCompressionMetrics(config, { | |
| tokens_before: event.tokens_before, | |
| tokens_after: event.tokens_after, | |
| }); | |
| } | |
| export function logMalformedJsonResponse( | |
| config: Config, | |
| event: MalformedJsonResponseEvent, | |
| ): void { | |
| ClearcutLogger.getInstance(config)?.logMalformedJsonResponseEvent(event); | |
| bufferTelemetryEvent(() => { | |
| const logger = logs.getLogger(SERVICE_NAME); | |
| const logRecord: LogRecord = { | |
| body: event.toLogBody(), | |
| attributes: event.toOpenTelemetryAttributes(config), | |
| }; | |
| logger.emit(logRecord); | |
| }); | |
| } | |
| export function logInvalidChunk( | |
| config: Config, | |
| event: InvalidChunkEvent, | |
| ): void { | |
| ClearcutLogger.getInstance(config)?.logInvalidChunkEvent(event); | |
| bufferTelemetryEvent(() => { | |
| const logger = logs.getLogger(SERVICE_NAME); | |
| const logRecord: LogRecord = { | |
| body: event.toLogBody(), | |
| attributes: event.toOpenTelemetryAttributes(config), | |
| }; | |
| logger.emit(logRecord); | |
| recordInvalidChunk(config); | |
| }); | |
| } | |
| export function logNetworkRetryAttempt( | |
| config: Config, | |
| event: NetworkRetryAttemptEvent, | |
| ): void { | |
| ClearcutLogger.getInstance(config)?.logNetworkRetryAttemptEvent(event); | |
| bufferTelemetryEvent(() => { | |
| const logger = logs.getLogger(SERVICE_NAME); | |
| const logRecord: LogRecord = { | |
| body: event.toLogBody(), | |
| attributes: event.toOpenTelemetryAttributes(config), | |
| }; | |
| logger.emit(logRecord); | |
| recordRetryAttemptMetrics(config, { | |
| model: event.model, | |
| attempt: event.attempt, | |
| }); | |
| }); | |
| } | |
| export function logContentRetry( | |
| config: Config, | |
| event: ContentRetryEvent, | |
| ): void { | |
| ClearcutLogger.getInstance(config)?.logContentRetryEvent(event); | |
| bufferTelemetryEvent(() => { | |
| const logger = logs.getLogger(SERVICE_NAME); | |
| const logRecord: LogRecord = { | |
| body: event.toLogBody(), | |
| attributes: event.toOpenTelemetryAttributes(config), | |
| }; | |
| logger.emit(logRecord); | |
| recordContentRetry(config); | |
| }); | |
| } | |
| export function logContentRetryFailure( | |
| config: Config, | |
| event: ContentRetryFailureEvent, | |
| ): void { | |
| ClearcutLogger.getInstance(config)?.logContentRetryFailureEvent(event); | |
| bufferTelemetryEvent(() => { | |
| const logger = logs.getLogger(SERVICE_NAME); | |
| const logRecord: LogRecord = { | |
| body: event.toLogBody(), | |
| attributes: event.toOpenTelemetryAttributes(config), | |
| }; | |
| logger.emit(logRecord); | |
| recordContentRetryFailure(config); | |
| }); | |
| } | |
| export function logModelRouting( | |
| config: Config, | |
| event: ModelRoutingEvent, | |
| ): void { | |
| ClearcutLogger.getInstance(config)?.logModelRoutingEvent(event); | |
| bufferTelemetryEvent(() => { | |
| const logger = logs.getLogger(SERVICE_NAME); | |
| const logRecord: LogRecord = { | |
| body: event.toLogBody(), | |
| attributes: event.toOpenTelemetryAttributes(config), | |
| }; | |
| logger.emit(logRecord); | |
| recordModelRoutingMetrics(config, event); | |
| }); | |
| } | |
| export function logModelSlashCommand( | |
| config: Config, | |
| event: ModelSlashCommandEvent, | |
| ): void { | |
| ClearcutLogger.getInstance(config)?.logModelSlashCommandEvent(event); | |
| bufferTelemetryEvent(() => { | |
| const logger = logs.getLogger(SERVICE_NAME); | |
| const logRecord: LogRecord = { | |
| body: event.toLogBody(), | |
| attributes: event.toOpenTelemetryAttributes(config), | |
| }; | |
| logger.emit(logRecord); | |
| recordModelSlashCommand(config, event); | |
| }); | |
| } | |
| export async function logExtensionInstallEvent( | |
| config: Config, | |
| event: ExtensionInstallEvent, | |
| ): Promise<void> { | |
| await ClearcutLogger.getInstance(config)?.logExtensionInstallEvent(event); | |
| bufferTelemetryEvent(() => { | |
| const logger = logs.getLogger(SERVICE_NAME); | |
| const logRecord: LogRecord = { | |
| body: event.toLogBody(), | |
| attributes: event.toOpenTelemetryAttributes(config), | |
| }; | |
| logger.emit(logRecord); | |
| }); | |
| } | |
| export async function logExtensionUninstall( | |
| config: Config, | |
| event: ExtensionUninstallEvent, | |
| ): Promise<void> { | |
| await ClearcutLogger.getInstance(config)?.logExtensionUninstallEvent(event); | |
| bufferTelemetryEvent(() => { | |
| const logger = logs.getLogger(SERVICE_NAME); | |
| const logRecord: LogRecord = { | |
| body: event.toLogBody(), | |
| attributes: event.toOpenTelemetryAttributes(config), | |
| }; | |
| logger.emit(logRecord); | |
| }); | |
| } | |
| export async function logExtensionUpdateEvent( | |
| config: Config, | |
| event: ExtensionUpdateEvent, | |
| ): Promise<void> { | |
| await ClearcutLogger.getInstance(config)?.logExtensionUpdateEvent(event); | |
| bufferTelemetryEvent(() => { | |
| const logger = logs.getLogger(SERVICE_NAME); | |
| const logRecord: LogRecord = { | |
| body: event.toLogBody(), | |
| attributes: event.toOpenTelemetryAttributes(config), | |
| }; | |
| logger.emit(logRecord); | |
| }); | |
| } | |
| export async function logExtensionEnable( | |
| config: Config, | |
| event: ExtensionEnableEvent, | |
| ): Promise<void> { | |
| await ClearcutLogger.getInstance(config)?.logExtensionEnableEvent(event); | |
| bufferTelemetryEvent(() => { | |
| const logger = logs.getLogger(SERVICE_NAME); | |
| const logRecord: LogRecord = { | |
| body: event.toLogBody(), | |
| attributes: event.toOpenTelemetryAttributes(config), | |
| }; | |
| logger.emit(logRecord); | |
| }); | |
| } | |
| export async function logExtensionDisable( | |
| config: Config, | |
| event: ExtensionDisableEvent, | |
| ): Promise<void> { | |
| await ClearcutLogger.getInstance(config)?.logExtensionDisableEvent(event); | |
| bufferTelemetryEvent(() => { | |
| const logger = logs.getLogger(SERVICE_NAME); | |
| const logRecord: LogRecord = { | |
| body: event.toLogBody(), | |
| attributes: event.toOpenTelemetryAttributes(config), | |
| }; | |
| logger.emit(logRecord); | |
| }); | |
| } | |
| export function logEditStrategy( | |
| config: Config, | |
| event: EditStrategyEvent, | |
| ): void { | |
| ClearcutLogger.getInstance(config)?.logEditStrategyEvent(event); | |
| bufferTelemetryEvent(() => { | |
| const logger = logs.getLogger(SERVICE_NAME); | |
| const logRecord: LogRecord = { | |
| body: event.toLogBody(), | |
| attributes: event.toOpenTelemetryAttributes(config), | |
| }; | |
| logger.emit(logRecord); | |
| }); | |
| } | |
| export function logEditCorrectionEvent( | |
| config: Config, | |
| event: EditCorrectionEvent, | |
| ): void { | |
| ClearcutLogger.getInstance(config)?.logEditCorrectionEvent(event); | |
| bufferTelemetryEvent(() => { | |
| const logger = logs.getLogger(SERVICE_NAME); | |
| const logRecord: LogRecord = { | |
| body: event.toLogBody(), | |
| attributes: event.toOpenTelemetryAttributes(config), | |
| }; | |
| logger.emit(logRecord); | |
| }); | |
| } | |
| export function logAgentStart(config: Config, event: AgentStartEvent): void { | |
| ClearcutLogger.getInstance(config)?.logAgentStartEvent(event); | |
| bufferTelemetryEvent(() => { | |
| const logger = logs.getLogger(SERVICE_NAME); | |
| const logRecord: LogRecord = { | |
| body: event.toLogBody(), | |
| attributes: event.toOpenTelemetryAttributes(config), | |
| }; | |
| logger.emit(logRecord); | |
| }); | |
| } | |
| export function logAgentFinish(config: Config, event: AgentFinishEvent): void { | |
| ClearcutLogger.getInstance(config)?.logAgentFinishEvent(event); | |
| bufferTelemetryEvent(() => { | |
| const logger = logs.getLogger(SERVICE_NAME); | |
| const logRecord: LogRecord = { | |
| body: event.toLogBody(), | |
| attributes: event.toOpenTelemetryAttributes(config), | |
| }; | |
| logger.emit(logRecord); | |
| recordAgentRunMetrics(config, event); | |
| }); | |
| } | |
| export function logRecoveryAttempt( | |
| config: Config, | |
| event: RecoveryAttemptEvent, | |
| ): void { | |
| ClearcutLogger.getInstance(config)?.logRecoveryAttemptEvent(event); | |
| bufferTelemetryEvent(() => { | |
| const logger = logs.getLogger(SERVICE_NAME); | |
| const logRecord: LogRecord = { | |
| body: event.toLogBody(), | |
| attributes: event.toOpenTelemetryAttributes(config), | |
| }; | |
| logger.emit(logRecord); | |
| recordRecoveryAttemptMetrics(config, event); | |
| }); | |
| } | |
| export function logWebFetchFallbackAttempt( | |
| config: Config, | |
| event: WebFetchFallbackAttemptEvent, | |
| ): void { | |
| ClearcutLogger.getInstance(config)?.logWebFetchFallbackAttemptEvent(event); | |
| bufferTelemetryEvent(() => { | |
| const logger = logs.getLogger(SERVICE_NAME); | |
| const logRecord: LogRecord = { | |
| body: event.toLogBody(), | |
| attributes: event.toOpenTelemetryAttributes(config), | |
| }; | |
| logger.emit(logRecord); | |
| }); | |
| } | |
| export function logLlmLoopCheck( | |
| config: Config, | |
| event: LlmLoopCheckEvent, | |
| ): void { | |
| ClearcutLogger.getInstance(config)?.logLlmLoopCheckEvent(event); | |
| bufferTelemetryEvent(() => { | |
| const logger = logs.getLogger(SERVICE_NAME); | |
| const logRecord: LogRecord = { | |
| body: event.toLogBody(), | |
| attributes: event.toOpenTelemetryAttributes(config), | |
| }; | |
| logger.emit(logRecord); | |
| }); | |
| } | |
| export function logApprovalModeSwitch( | |
| config: Config, | |
| event: ApprovalModeSwitchEvent, | |
| ) { | |
| ClearcutLogger.getInstance(config)?.logApprovalModeSwitchEvent(event); | |
| bufferTelemetryEvent(() => { | |
| logs.getLogger(SERVICE_NAME).emit({ | |
| body: event.toLogBody(), | |
| attributes: event.toOpenTelemetryAttributes(config), | |
| }); | |
| }); | |
| } | |
| export function logApprovalModeDuration( | |
| config: Config, | |
| event: ApprovalModeDurationEvent, | |
| ) { | |
| ClearcutLogger.getInstance(config)?.logApprovalModeDurationEvent(event); | |
| bufferTelemetryEvent(() => { | |
| logs.getLogger(SERVICE_NAME).emit({ | |
| body: event.toLogBody(), | |
| attributes: event.toOpenTelemetryAttributes(config), | |
| }); | |
| }); | |
| } | |
| export function logPlanExecution(config: Config, event: PlanExecutionEvent) { | |
| ClearcutLogger.getInstance(config)?.logPlanExecutionEvent(event); | |
| bufferTelemetryEvent(() => { | |
| logs.getLogger(SERVICE_NAME).emit({ | |
| body: event.toLogBody(), | |
| attributes: event.toOpenTelemetryAttributes(config), | |
| }); | |
| recordPlanExecution(config, { | |
| approval_mode: event.approval_mode, | |
| }); | |
| }); | |
| } | |
| export function logHookCall(config: Config, event: HookCallEvent): void { | |
| ClearcutLogger.getInstance(config)?.logHookCallEvent(event); | |
| bufferTelemetryEvent(() => { | |
| const logger = logs.getLogger(SERVICE_NAME); | |
| const logRecord: LogRecord = { | |
| body: event.toLogBody(), | |
| attributes: event.toOpenTelemetryAttributes(config), | |
| }; | |
| logger.emit(logRecord); | |
| recordHookCallMetrics( | |
| config, | |
| event.hook_event_name, | |
| event.hook_name, | |
| event.duration_ms, | |
| event.success, | |
| ); | |
| }); | |
| } | |
| export function logStartupStats( | |
| config: Config, | |
| event: StartupStatsEvent, | |
| ): void { | |
| ClearcutLogger.getInstance(config)?.logStartupStatsEvent(event); | |
| bufferTelemetryEvent(() => { | |
| // Wait for experiments to load before emitting so we capture experimentIds | |
| void config | |
| .getExperimentsAsync() | |
| .then(() => { | |
| const logger = logs.getLogger(SERVICE_NAME); | |
| const logRecord: LogRecord = { | |
| body: event.toLogBody(), | |
| attributes: event.toOpenTelemetryAttributes(config), | |
| }; | |
| logger.emit(logRecord); | |
| }) | |
| .catch((e: unknown) => { | |
| debugLogger.error('Failed to log telemetry event', e); | |
| }); | |
| }); | |
| } | |
| export function logKeychainAvailability( | |
| config: Config, | |
| event: KeychainAvailabilityEvent, | |
| ): void { | |
| ClearcutLogger.getInstance(config)?.logKeychainAvailabilityEvent(event); | |
| bufferTelemetryEvent(() => { | |
| const logger = logs.getLogger(SERVICE_NAME); | |
| const logRecord: LogRecord = { | |
| body: event.toLogBody(), | |
| attributes: event.toOpenTelemetryAttributes(config), | |
| }; | |
| logger.emit(logRecord); | |
| recordKeychainAvailability(config, event); | |
| }); | |
| } | |
| export function logTokenStorageInitialization( | |
| config: Config, | |
| event: TokenStorageInitializationEvent, | |
| ): void { | |
| ClearcutLogger.getInstance(config)?.logTokenStorageInitializationEvent(event); | |
| bufferTelemetryEvent(() => { | |
| const logger = logs.getLogger(SERVICE_NAME); | |
| const logRecord: LogRecord = { | |
| body: event.toLogBody(), | |
| attributes: event.toOpenTelemetryAttributes(config), | |
| }; | |
| logger.emit(logRecord); | |
| recordTokenStorageInitialization(config, event); | |
| }); | |
| } | |
| export function logOnboardingStart( | |
| config: Config, | |
| event: OnboardingStartEvent, | |
| ): void { | |
| ClearcutLogger.getInstance(config)?.logOnboardingStartEvent(event); | |
| bufferTelemetryEvent(() => { | |
| const logger = logs.getLogger(SERVICE_NAME); | |
| const logRecord: LogRecord = { | |
| body: event.toLogBody(), | |
| attributes: event.toOpenTelemetryAttributes(config), | |
| }; | |
| logger.emit(logRecord); | |
| recordOnboardingStart(config); | |
| }); | |
| } | |
| export function logOnboardingSuccess( | |
| config: Config, | |
| event: OnboardingSuccessEvent, | |
| ): void { | |
| ClearcutLogger.getInstance(config)?.logOnboardingSuccessEvent(event); | |
| bufferTelemetryEvent(() => { | |
| const logger = logs.getLogger(SERVICE_NAME); | |
| const logRecord: LogRecord = { | |
| body: event.toLogBody(), | |
| attributes: event.toOpenTelemetryAttributes(config), | |
| }; | |
| logger.emit(logRecord); | |
| recordOnboardingSuccess(config, event.userTier, event.duration_ms); | |
| }); | |
| } | |
| export function logBillingEvent( | |
| config: Config, | |
| event: BillingTelemetryEvent, | |
| ): void { | |
| bufferTelemetryEvent(() => { | |
| const logger = logs.getLogger(SERVICE_NAME); | |
| const logRecord: LogRecord = { | |
| body: event.toLogBody(), | |
| attributes: event.toOpenTelemetryAttributes(config), | |
| }; | |
| logger.emit(logRecord); | |
| }); | |
| const cc = ClearcutLogger.getInstance(config); | |
| if (cc) { | |
| if (event instanceof CreditsUsedEvent) { | |
| cc.logCreditsUsedEvent(event); | |
| } else if (event instanceof OverageOptionSelectedEvent) { | |
| cc.logOverageOptionSelectedEvent(event); | |
| } else if (event instanceof EmptyWalletMenuShownEvent) { | |
| cc.logEmptyWalletMenuShownEvent(event); | |
| } else if (event instanceof CreditPurchaseClickEvent) { | |
| cc.logCreditPurchaseClickEvent(event); | |
| } | |
| } | |
| } | |
| // ========================================================================== | |
| // Browser Agent Events | |
| // ========================================================================== | |
| export function logBrowserAgentConnection( | |
| config: Config, | |
| durationMs: number, | |
| attributes: { | |
| session_mode: 'persistent' | 'isolated' | 'existing'; | |
| headless: boolean; | |
| success: boolean; | |
| error_type?: | |
| | 'profile_locked' | |
| | 'timeout' | |
| | 'connection_refused' | |
| | 'unknown'; | |
| tool_count?: number; | |
| }, | |
| ): void { | |
| ClearcutLogger.getInstance(config)?.logBrowserAgentConnectionEvent({ | |
| session_mode: attributes.session_mode, | |
| headless: attributes.headless, | |
| success: attributes.success, | |
| duration_ms: durationMs, | |
| error_type: attributes.error_type, | |
| tool_count: attributes.tool_count, | |
| }); | |
| recordBrowserAgentConnection(config, durationMs, attributes); | |
| } | |
| export function logBrowserAgentVisionStatus( | |
| config: Config, | |
| attributes: { | |
| enabled: boolean; | |
| disabled_reason?: | |
| | 'no_visual_model' | |
| | 'missing_visual_tools' | |
| | 'blocked_auth_type'; | |
| }, | |
| ): void { | |
| ClearcutLogger.getInstance(config)?.logBrowserAgentVisionStatusEvent({ | |
| enabled: attributes.enabled, | |
| disabled_reason: attributes.disabled_reason, | |
| }); | |
| recordBrowserAgentVisionStatus(config, attributes); | |
| } | |
| export function logBrowserAgentTaskOutcome( | |
| config: Config, | |
| attributes: { | |
| success: boolean; | |
| session_mode: 'persistent' | 'isolated' | 'existing'; | |
| vision_enabled: boolean; | |
| headless: boolean; | |
| duration_ms: number; | |
| }, | |
| ): void { | |
| ClearcutLogger.getInstance(config)?.logBrowserAgentTaskOutcomeEvent({ | |
| success: attributes.success, | |
| session_mode: attributes.session_mode, | |
| vision_enabled: attributes.vision_enabled, | |
| headless: attributes.headless, | |
| duration_ms: attributes.duration_ms, | |
| }); | |
| recordBrowserAgentTaskOutcome(config, attributes); | |
| } | |
| export function logBrowserAgentCleanup( | |
| config: Config, | |
| durationMs: number, | |
| attributes: { | |
| session_mode: 'persistent' | 'isolated' | 'existing'; | |
| success: boolean; | |
| }, | |
| ): void { | |
| ClearcutLogger.getInstance(config)?.logBrowserAgentCleanupEvent({ | |
| session_mode: attributes.session_mode, | |
| success: attributes.success, | |
| duration_ms: durationMs, | |
| }); | |
| recordBrowserAgentCleanup(config, durationMs, attributes); | |
| } | |