telemetry: track interactive session state (#12856)

Co-authored-by: owenofbrien <86964623+owenofbrien@users.noreply.github.com>
This commit is contained in:
N. Taylor Mullen
2025-11-11 02:03:32 -08:00
committed by GitHub
parent e79f62694a
commit 7bb13d1c41
24 changed files with 132 additions and 25 deletions
@@ -887,8 +887,7 @@ describe('ClearcutLogger', () => {
status: 'success',
} as SuccessfulToolCall;
// eslint-disable-next-line @typescript-eslint/no-explicit-any
logger?.logToolCallEvent(new ToolCallEvent(completedToolCall as any));
logger?.logToolCallEvent(new ToolCallEvent(completedToolCall));
const events = getEvents(logger!);
expect(events.length).toBe(1);
@@ -933,8 +932,7 @@ describe('ClearcutLogger', () => {
status: 'success',
} as SuccessfulToolCall;
// eslint-disable-next-line @typescript-eslint/no-explicit-any
logger?.logToolCallEvent(new ToolCallEvent(completedToolCall as any));
logger?.logToolCallEvent(new ToolCallEvent(completedToolCall));
const events = getEvents(logger!);
expect(events.length).toBe(1);
@@ -1301,6 +1301,10 @@ export class ClearcutLogger {
gemini_cli_key: EventMetadataKey.GEMINI_CLI_USER_SETTINGS,
value: this.getConfigJson(),
},
{
gemini_cli_key: EventMetadataKey.GEMINI_CLI_INTERACTIVE,
value: this.config?.isInteractive().toString() ?? 'false',
},
];
return [...data, ...defaultLogMetadata];
}
@@ -473,4 +473,7 @@ export enum EventMetadataKey {
// Logs whether the agent recovery attempt was successful.
GEMINI_CLI_AGENT_RECOVERY_SUCCESS = 124,
// Logs whether the session is interactive.
GEMINI_CLI_INTERACTIVE = 125,
}
@@ -69,7 +69,6 @@ describe('Circular Reference Handling', () => {
durationMs: 100,
};
// Create a tool call event with circular references in function_args
const event = new ToolCallEvent(mockCompletedToolCall);
// This should not throw an error
+54 -2
View File
@@ -211,6 +211,7 @@ describe('loggers', () => {
},
}),
}),
isInteractive: () => false,
} as unknown as Config;
const startSessionEvent = new StartSessionEvent(mockConfig);
@@ -224,6 +225,7 @@ describe('loggers', () => {
'installation.id': 'test-installation-id',
'event.name': EVENT_CLI_CONFIG,
'event.timestamp': '2025-01-01T00:00:00.000Z',
interactive: false,
model: 'test-model',
embedding_model: 'test-embedding-model',
sandbox_enabled: true,
@@ -254,6 +256,7 @@ describe('loggers', () => {
getTelemetryEnabled: () => true,
getTelemetryLogPromptsEnabled: () => true,
getUsageStatisticsEnabled: () => true,
isInteractive: () => false,
} as unknown as Config;
it('should log a user prompt', () => {
@@ -274,6 +277,7 @@ describe('loggers', () => {
'installation.id': 'test-installation-id',
'event.name': EVENT_USER_PROMPT,
'event.timestamp': '2025-01-01T00:00:00.000Z',
interactive: false,
prompt_length: 11,
prompt: 'test-prompt',
prompt_id: 'prompt-id-8',
@@ -289,6 +293,7 @@ describe('loggers', () => {
getTelemetryLogPromptsEnabled: () => false,
getTargetDir: () => 'target-dir',
getUsageStatisticsEnabled: () => true,
isInteractive: () => false,
} as unknown as Config;
const event = new UserPromptEvent(
11,
@@ -307,6 +312,7 @@ describe('loggers', () => {
'installation.id': 'test-installation-id',
'event.name': EVENT_USER_PROMPT,
'event.timestamp': '2025-01-01T00:00:00.000Z',
interactive: false,
prompt_length: 11,
prompt_id: 'prompt-id-9',
auth_type: 'cloud-shell',
@@ -322,6 +328,7 @@ describe('loggers', () => {
getUsageStatisticsEnabled: () => true,
getTelemetryEnabled: () => true,
getTelemetryLogPromptsEnabled: () => true,
isInteractive: () => false,
} as Config;
const mockMetrics = {
@@ -496,6 +503,7 @@ describe('loggers', () => {
getUsageStatisticsEnabled: () => true,
getTelemetryEnabled: () => true,
getTelemetryLogPromptsEnabled: () => true,
isInteractive: () => false,
} as Config;
const mockMetrics = {
@@ -627,6 +635,7 @@ describe('loggers', () => {
getUsageStatisticsEnabled: () => true,
getTelemetryEnabled: () => true,
getTelemetryLogPromptsEnabled: () => true,
isInteractive: () => false,
} as Config;
it('should log an API request with request_text', () => {
@@ -646,6 +655,7 @@ describe('loggers', () => {
'installation.id': 'test-installation-id',
'event.name': EVENT_API_REQUEST,
'event.timestamp': '2025-01-01T00:00:00.000Z',
interactive: false,
model: 'test-model',
request_text: 'This is a test request',
prompt_id: 'prompt-id-7',
@@ -666,6 +676,7 @@ describe('loggers', () => {
'installation.id': 'test-installation-id',
'event.name': EVENT_API_REQUEST,
'event.timestamp': '2025-01-01T00:00:00.000Z',
interactive: false,
model: 'test-model',
prompt_id: 'prompt-id-6',
},
@@ -677,6 +688,7 @@ describe('loggers', () => {
const mockConfig = {
getSessionId: () => 'test-session-id',
getUsageStatisticsEnabled: () => true,
isInteractive: () => false,
} as unknown as Config;
it('should log flash fallback event', () => {
@@ -692,6 +704,7 @@ describe('loggers', () => {
'installation.id': 'test-installation-id',
'event.name': EVENT_FLASH_FALLBACK,
'event.timestamp': '2025-01-01T00:00:00.000Z',
interactive: false,
auth_type: 'vertex-ai',
},
});
@@ -702,6 +715,7 @@ describe('loggers', () => {
const mockConfig = {
getSessionId: () => 'test-session-id',
getUsageStatisticsEnabled: () => true,
isInteractive: () => false,
} as unknown as Config;
beforeEach(() => {
@@ -794,6 +808,7 @@ describe('loggers', () => {
getUsageStatisticsEnabled: () => true,
getTelemetryEnabled: () => true,
getTelemetryLogPromptsEnabled: () => true,
isInteractive: () => false,
} as Config;
const mockMetrics = {
@@ -865,6 +880,7 @@ describe('loggers', () => {
'installation.id': 'test-installation-id',
'event.name': EVENT_TOOL_CALL,
'event.timestamp': '2025-01-01T00:00:00.000Z',
interactive: false,
function_name: 'test-function',
function_args: JSON.stringify(
{
@@ -881,7 +897,8 @@ describe('loggers', () => {
tool_type: 'native',
error: undefined,
error_type: undefined,
mcp_server_name: undefined,
extension_id: undefined,
metadata: {
model_added_lines: 1,
model_removed_lines: 2,
@@ -962,6 +979,7 @@ describe('loggers', () => {
'installation.id': 'test-installation-id',
'event.name': EVENT_TOOL_CALL,
'event.timestamp': '2025-01-01T00:00:00.000Z',
interactive: false,
function_name: 'test-function',
function_args: JSON.stringify(
{
@@ -978,6 +996,8 @@ describe('loggers', () => {
tool_type: 'native',
error: undefined,
error_type: undefined,
mcp_server_name: undefined,
extension_id: undefined,
metadata: undefined,
content_length: undefined,
},
@@ -1039,6 +1059,7 @@ describe('loggers', () => {
'installation.id': 'test-installation-id',
'event.name': EVENT_TOOL_CALL,
'event.timestamp': '2025-01-01T00:00:00.000Z',
interactive: false,
function_name: 'test-function',
function_args: JSON.stringify(
{
@@ -1055,6 +1076,8 @@ describe('loggers', () => {
tool_type: 'native',
error: undefined,
error_type: undefined,
mcp_server_name: undefined,
extension_id: undefined,
metadata: undefined,
content_length: 13,
},
@@ -1115,6 +1138,7 @@ describe('loggers', () => {
'installation.id': 'test-installation-id',
'event.name': EVENT_TOOL_CALL,
'event.timestamp': '2025-01-01T00:00:00.000Z',
interactive: false,
function_name: 'test-function',
function_args: JSON.stringify(
{
@@ -1131,6 +1155,8 @@ describe('loggers', () => {
decision: undefined,
error: undefined,
error_type: undefined,
mcp_server_name: undefined,
extension_id: undefined,
metadata: undefined,
content_length: 13,
},
@@ -1190,6 +1216,7 @@ describe('loggers', () => {
'installation.id': 'test-installation-id',
'event.name': EVENT_TOOL_CALL,
'event.timestamp': '2025-01-01T00:00:00.000Z',
interactive: false,
function_name: 'test-function',
function_args: JSON.stringify(
{
@@ -1208,6 +1235,8 @@ describe('loggers', () => {
prompt_id: 'prompt-id-5',
tool_type: 'native',
decision: undefined,
mcp_server_name: undefined,
extension_id: undefined,
metadata: undefined,
content_length: errorMessage.length,
},
@@ -1273,7 +1302,6 @@ describe('loggers', () => {
durationMs: 100,
};
const event = new ToolCallEvent(call);
logToolCall(mockConfig, event);
expect(mockLogger.emit).toHaveBeenCalledWith({
@@ -1286,6 +1314,7 @@ describe('loggers', () => {
'event.timestamp': '2025-01-01T00:00:00.000Z',
extension_name: 'test-extension',
extension_id: 'test-extension-id',
interactive: false,
function_name: 'mock_mcp_tool',
function_args: JSON.stringify(
{
@@ -1333,6 +1362,7 @@ describe('loggers', () => {
'installation.id': 'test-installation-id',
'event.name': EVENT_MALFORMED_JSON_RESPONSE,
'event.timestamp': '2025-01-01T00:00:00.000Z',
interactive: false,
model: 'test-model',
},
});
@@ -1346,6 +1376,7 @@ describe('loggers', () => {
getUsageStatisticsEnabled: () => true,
getTelemetryEnabled: () => true,
getTelemetryLogPromptsEnabled: () => true,
isInteractive: () => false,
} as Config;
const mockMetrics = {
@@ -1378,6 +1409,7 @@ describe('loggers', () => {
'installation.id': 'test-installation-id',
'event.name': EVENT_FILE_OPERATION,
'event.timestamp': '2025-01-01T00:00:00.000Z',
interactive: false,
tool_name: 'test-tool',
operation: 'read',
lines: 10,
@@ -1404,6 +1436,7 @@ describe('loggers', () => {
const mockConfig = {
getSessionId: () => 'test-session-id',
getUsageStatisticsEnabled: () => true,
isInteractive: () => false,
} as unknown as Config;
it('should log a tool output truncated event', () => {
@@ -1426,6 +1459,7 @@ describe('loggers', () => {
'event.name': EVENT_TOOL_OUTPUT_TRUNCATED,
'event.timestamp': '2025-01-01T00:00:00.000Z',
eventName: 'tool_output_truncated',
interactive: false,
prompt_id: 'prompt-id-1',
tool_name: 'test-tool',
original_content_length: 1000,
@@ -1441,6 +1475,7 @@ describe('loggers', () => {
const mockConfig = {
getSessionId: () => 'test-session-id',
getUsageStatisticsEnabled: () => true,
isInteractive: () => false,
} as unknown as Config;
beforeEach(() => {
@@ -1472,6 +1507,7 @@ describe('loggers', () => {
'installation.id': 'test-installation-id',
...event,
'event.name': EVENT_MODEL_ROUTING,
interactive: false,
},
});
@@ -1509,6 +1545,7 @@ describe('loggers', () => {
getContentGeneratorConfig: () => null,
getUseSmartEdit: () => null,
getUseModelRouter: () => null,
isInteractive: () => false,
} as unknown as Config;
beforeEach(() => {
@@ -1542,6 +1579,7 @@ describe('loggers', () => {
'installation.id': 'test-installation-id',
'event.name': EVENT_EXTENSION_INSTALL,
'event.timestamp': '2025-01-01T00:00:00.000Z',
interactive: false,
extension_name: 'testing',
extension_version: '0.1.0',
extension_source: 'git',
@@ -1558,6 +1596,7 @@ describe('loggers', () => {
getContentGeneratorConfig: () => null,
getUseSmartEdit: () => null,
getUseModelRouter: () => null,
isInteractive: () => false,
} as unknown as Config;
beforeEach(() => {
@@ -1592,6 +1631,7 @@ describe('loggers', () => {
'installation.id': 'test-installation-id',
'event.name': EVENT_EXTENSION_UPDATE,
'event.timestamp': '2025-01-01T00:00:00.000Z',
interactive: false,
extension_name: 'testing',
extension_version: '0.1.0',
extension_previous_version: '0.1.1',
@@ -1609,6 +1649,7 @@ describe('loggers', () => {
getContentGeneratorConfig: () => null,
getUseSmartEdit: () => null,
getUseModelRouter: () => null,
isInteractive: () => false,
} as unknown as Config;
beforeEach(() => {
@@ -1639,6 +1680,7 @@ describe('loggers', () => {
'installation.id': 'test-installation-id',
'event.name': EVENT_EXTENSION_UNINSTALL,
'event.timestamp': '2025-01-01T00:00:00.000Z',
interactive: false,
extension_name: 'testing',
status: 'success',
},
@@ -1650,6 +1692,7 @@ describe('loggers', () => {
const mockConfig = {
getSessionId: () => 'test-session-id',
getUsageStatisticsEnabled: () => true,
isInteractive: () => false,
} as unknown as Config;
beforeEach(() => {
@@ -1677,6 +1720,7 @@ describe('loggers', () => {
'installation.id': 'test-installation-id',
'event.name': EVENT_EXTENSION_ENABLE,
'event.timestamp': '2025-01-01T00:00:00.000Z',
interactive: false,
extension_name: 'testing',
setting_scope: 'user',
},
@@ -1688,6 +1732,7 @@ describe('loggers', () => {
const mockConfig = {
getSessionId: () => 'test-session-id',
getUsageStatisticsEnabled: () => true,
isInteractive: () => false,
} as unknown as Config;
beforeEach(() => {
@@ -1715,6 +1760,7 @@ describe('loggers', () => {
'installation.id': 'test-installation-id',
'event.name': EVENT_EXTENSION_DISABLE,
'event.timestamp': '2025-01-01T00:00:00.000Z',
interactive: false,
extension_name: 'testing',
setting_scope: 'user',
},
@@ -1726,6 +1772,7 @@ describe('loggers', () => {
const mockConfig = {
getSessionId: () => 'test-session-id',
getUsageStatisticsEnabled: () => true,
isInteractive: () => false,
} as unknown as Config;
beforeEach(() => {
@@ -1749,6 +1796,7 @@ describe('loggers', () => {
'installation.id': 'test-installation-id',
'event.name': EVENT_AGENT_START,
'event.timestamp': '2025-01-01T00:00:00.000Z',
interactive: false,
agent_id: 'agent-123',
agent_name: 'TestAgent',
},
@@ -1760,6 +1808,7 @@ describe('loggers', () => {
const mockConfig = {
getSessionId: () => 'test-session-id',
getUsageStatisticsEnabled: () => true,
isInteractive: () => false,
} as unknown as Config;
beforeEach(() => {
@@ -1790,6 +1839,7 @@ describe('loggers', () => {
'installation.id': 'test-installation-id',
'event.name': EVENT_AGENT_FINISH,
'event.timestamp': '2025-01-01T00:00:00.000Z',
interactive: false,
agent_id: 'agent-123',
agent_name: 'TestAgent',
duration_ms: 1000,
@@ -1809,6 +1859,7 @@ describe('loggers', () => {
const mockConfig = {
getSessionId: () => 'test-session-id',
getUsageStatisticsEnabled: () => true,
isInteractive: () => false,
} as unknown as Config;
beforeEach(() => {
@@ -1832,6 +1883,7 @@ describe('loggers', () => {
'installation.id': 'test-installation-id',
'event.name': EVENT_WEB_FETCH_FALLBACK_ATTEMPT,
'event.timestamp': '2025-01-01T00:00:00.000Z',
interactive: false,
reason: 'private_ip',
},
});
@@ -17,6 +17,7 @@ export function getCommonAttributes(config: Config): Attributes {
return {
'session.id': config.getSessionId(),
'installation.id': installationManager.getInstallationId(),
interactive: config.isInteractive(),
...(email && { 'user.email': email }),
};
}
+14 -1
View File
@@ -161,6 +161,19 @@ export class EndSessionEvent implements BaseTelemetryEvent {
this['event.timestamp'] = new Date().toISOString();
this.session_id = config?.getSessionId();
}
toOpenTelemetryAttributes(config: Config): LogAttributes {
return {
...getCommonAttributes(config),
'event.name': this['event.name'],
'event.timestamp': this['event.timestamp'],
session_id: this.session_id,
};
}
toLogBody(): string {
return 'Session ended.';
}
}
export const EVENT_USER_PROMPT = 'gemini_cli.user_prompt';
@@ -299,7 +312,7 @@ export class ToolCallEvent implements BaseTelemetryEvent {
}
}
} else {
this.function_name = function_name!;
this.function_name = function_name as string;
this.function_args = function_args!;
this.duration_ms = duration_ms!;
this.success = success!;