Add telemetry to rewind (#18122)

This commit is contained in:
Adib234
2026-02-03 16:17:29 -05:00
committed by GitHub
parent 69c0585ab2
commit 53027af94c
7 changed files with 76 additions and 0 deletions
@@ -41,6 +41,8 @@ vi.mock('@google/gemini-cli-core', async (importOriginal) => {
...actual.coreEvents, ...actual.coreEvents,
emitFeedback: vi.fn(), emitFeedback: vi.fn(),
}, },
logRewind: vi.fn(),
RewindEvent: class {},
}; };
}); });
@@ -19,6 +19,8 @@ import {
checkExhaustive, checkExhaustive,
coreEvents, coreEvents,
debugLogger, debugLogger,
logRewind,
RewindEvent,
type ChatRecordingService, type ChatRecordingService,
type GeminiClient, type GeminiClient,
} from '@google/gemini-cli-core'; } from '@google/gemini-cli-core';
@@ -144,6 +146,9 @@ export const rewindCommand: SlashCommand = {
context.ui.removeComponent(); context.ui.removeComponent();
}} }}
onRewind={async (messageId, newText, outcome) => { onRewind={async (messageId, newText, outcome) => {
if (outcome !== RewindOutcome.Cancel) {
logRewind(config, new RewindEvent(outcome));
}
switch (outcome) { switch (outcome) {
case RewindOutcome.Cancel: case RewindOutcome.Cancel:
context.ui.removeComponent(); context.ui.removeComponent();
@@ -18,6 +18,7 @@ import type {
LoopDetectedEvent, LoopDetectedEvent,
NextSpeakerCheckEvent, NextSpeakerCheckEvent,
SlashCommandEvent, SlashCommandEvent,
RewindEvent,
MalformedJsonResponseEvent, MalformedJsonResponseEvent,
IdeConnectionEvent, IdeConnectionEvent,
ConversationFinishedEvent, ConversationFinishedEvent,
@@ -78,6 +79,7 @@ export enum EventNames {
LOOP_DETECTION_DISABLED = 'loop_detection_disabled', LOOP_DETECTION_DISABLED = 'loop_detection_disabled',
NEXT_SPEAKER_CHECK = 'next_speaker_check', NEXT_SPEAKER_CHECK = 'next_speaker_check',
SLASH_COMMAND = 'slash_command', SLASH_COMMAND = 'slash_command',
REWIND = 'rewind',
MALFORMED_JSON_RESPONSE = 'malformed_json_response', MALFORMED_JSON_RESPONSE = 'malformed_json_response',
IDE_CONNECTION = 'ide_connection', IDE_CONNECTION = 'ide_connection',
KITTY_SEQUENCE_OVERFLOW = 'kitty_sequence_overflow', KITTY_SEQUENCE_OVERFLOW = 'kitty_sequence_overflow',
@@ -945,6 +947,18 @@ export class ClearcutLogger {
this.flushIfNeeded(); this.flushIfNeeded();
} }
logRewindEvent(event: RewindEvent): void {
const data: EventValue[] = [
{
gemini_cli_key: EventMetadataKey.GEMINI_CLI_REWIND_OUTCOME,
value: event.outcome,
},
];
this.enqueueLogEvent(this.createLogEvent(EventNames.REWIND, data));
this.flushIfNeeded();
}
logMalformedJsonResponseEvent(event: MalformedJsonResponseEvent): void { logMalformedJsonResponseEvent(event: MalformedJsonResponseEvent): void {
const data: EventValue[] = [ const data: EventValue[] = [
{ {
@@ -544,6 +544,12 @@ export enum EventMetadataKey {
GEMINI_CLI_APPROVAL_MODE_DURATION_MS = 143, GEMINI_CLI_APPROVAL_MODE_DURATION_MS = 143,
// ========================================================================== // ==========================================================================
// Rewind Event Keys
// ==========================================================================
// Logs the outcome of a rewind operation.
GEMINI_CLI_REWIND_OUTCOME = 144,
// Model Routing Event Keys (Cont.) // Model Routing Event Keys (Cont.)
// ========================================================================== // ==========================================================================
+2
View File
@@ -46,6 +46,7 @@ export {
logExtensionUninstall, logExtensionUninstall,
logExtensionUpdateEvent, logExtensionUpdateEvent,
logWebFetchFallbackAttempt, logWebFetchFallbackAttempt,
logRewind,
} from './loggers.js'; } from './loggers.js';
export type { SlashCommandEvent, ChatCompressionEvent } from './types.js'; export type { SlashCommandEvent, ChatCompressionEvent } from './types.js';
export { export {
@@ -62,6 +63,7 @@ export {
ToolOutputTruncatedEvent, ToolOutputTruncatedEvent,
WebFetchFallbackAttemptEvent, WebFetchFallbackAttemptEvent,
ToolCallDecision, ToolCallDecision,
RewindEvent,
} from './types.js'; } from './types.js';
export { makeSlashCommandEvent, makeChatCompressionEvent } from './types.js'; export { makeSlashCommandEvent, makeChatCompressionEvent } from './types.js';
export type { TelemetryEvent } from './types.js'; export type { TelemetryEvent } from './types.js';
+20
View File
@@ -12,6 +12,7 @@ import {
EVENT_API_ERROR, EVENT_API_ERROR,
EVENT_API_RESPONSE, EVENT_API_RESPONSE,
EVENT_TOOL_CALL, EVENT_TOOL_CALL,
EVENT_REWIND,
} from './types.js'; } from './types.js';
import type { import type {
ApiErrorEvent, ApiErrorEvent,
@@ -27,6 +28,7 @@ import type {
LoopDetectedEvent, LoopDetectedEvent,
LoopDetectionDisabledEvent, LoopDetectionDisabledEvent,
SlashCommandEvent, SlashCommandEvent,
RewindEvent,
ConversationFinishedEvent, ConversationFinishedEvent,
ChatCompressionEvent, ChatCompressionEvent,
MalformedJsonResponseEvent, MalformedJsonResponseEvent,
@@ -351,6 +353,24 @@ export function logSlashCommand(
}); });
} }
export function logRewind(config: Config, event: RewindEvent): void {
const uiEvent = {
...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( export function logIdeConnection(
config: Config, config: Config,
event: IdeConnectionEvent, event: IdeConnectionEvent,
+27
View File
@@ -889,6 +889,32 @@ export enum SlashCommandStatus {
ERROR = 'error', ERROR = 'error',
} }
export const EVENT_REWIND = 'gemini_cli.rewind';
export class RewindEvent implements BaseTelemetryEvent {
'event.name': 'rewind';
'event.timestamp': string;
outcome: string;
constructor(outcome: string) {
this['event.name'] = 'rewind';
this['event.timestamp'] = new Date().toISOString();
this.outcome = outcome;
}
toOpenTelemetryAttributes(config: Config): LogAttributes {
return {
...getCommonAttributes(config),
'event.name': EVENT_REWIND,
'event.timestamp': this['event.timestamp'],
outcome: this.outcome,
};
}
toLogBody(): string {
return `Rewind performed. Outcome: ${this.outcome}.`;
}
}
export const EVENT_CHAT_COMPRESSION = 'gemini_cli.chat_compression'; export const EVENT_CHAT_COMPRESSION = 'gemini_cli.chat_compression';
export interface ChatCompressionEvent extends BaseTelemetryEvent { export interface ChatCompressionEvent extends BaseTelemetryEvent {
'event.name': 'chat_compression'; 'event.name': 'chat_compression';
@@ -1577,6 +1603,7 @@ export type TelemetryEvent =
| StartupStatsEvent | StartupStatsEvent
| WebFetchFallbackAttemptEvent | WebFetchFallbackAttemptEvent
| EditStrategyEvent | EditStrategyEvent
| RewindEvent
| EditCorrectionEvent; | EditCorrectionEvent;
export const EVENT_EXTENSION_DISABLE = 'gemini_cli.extension_disable'; export const EVENT_EXTENSION_DISABLE = 'gemini_cli.extension_disable';