feat(telemetry): expand cli configuration event

Adds the following attributes to the  event:
- embedding_model
- api_key_enabled
- code_assist_enabled
- debug_mode
- mcp_servers

This additional data will provide more insight into user configurations.
This commit is contained in:
jerop 2025-06-11 20:15:44 +00:00 committed by Jerop Kipruto
parent 5586ad5f8a
commit c0580eaf4b
3 changed files with 153 additions and 75 deletions

View File

@ -262,13 +262,18 @@ These are timestamped records of specific events.
- **Attributes**:
- `model` (string)
- `embedding_model` (string)
- `sandbox_enabled` (boolean)
- `core_tools_enabled` (string)
- `approval_mode` (string)
- `api_key_enabled` (boolean)
- `vertex_ai_enabled` (boolean)
- `code_assist_enabled` (boolean)
- `log_user_prompts_enabled` (boolean)
- `file_filtering_respect_git_ignore` (boolean)
- `file_filtering_allow_build_artifacts` (boolean)
- `debug_mode` (boolean)
- `mcp_servers` (string)
- `gemini_cli.user_prompt`: Fired when a user submits a prompt.

View File

@ -8,36 +8,101 @@ import { logs } from '@opentelemetry/api-logs';
import { SemanticAttributes } from '@opentelemetry/semantic-conventions';
import { Config } from '../config/config.js';
import { EVENT_API_RESPONSE } from './constants.js';
import { logApiResponse } from './loggers.js';
import { logApiResponse, logCliConfiguration } from './loggers.js';
import * as metrics from './metrics.js';
import * as sdk from './sdk.js';
import { vi, describe, beforeEach, it, expect } from 'vitest';
vi.mock('@gemini-cli/cli/dist/src/utils/version', () => ({
getCliVersion: () => 'test-version',
}));
vi.mock('@gemini-cli/cli/dist/src/config/settings', () => ({
getTheme: () => 'test-theme',
}));
describe('loggers', () => {
const mockLogger = {
emit: vi.fn(),
};
beforeEach(() => {
vi.spyOn(sdk, 'isTelemetrySdkInitialized').mockReturnValue(true);
vi.spyOn(logs, 'getLogger').mockReturnValue(mockLogger);
vi.useFakeTimers();
vi.setSystemTime(new Date('2025-01-01T00:00:00.000Z'));
});
describe('logCliConfiguration', () => {
it('should log the cli configuration', () => {
const mockConfig = {
getSessionId: () => 'test-session-id',
getModel: () => 'test-model',
getEmbeddingModel: () => 'test-embedding-model',
getSandbox: () => true,
getCoreTools: () => ['ls', 'read-file'],
getApprovalMode: () => 'default',
getContentGeneratorConfig: () => ({
model: 'test-model',
apiKey: 'test-api-key',
vertexai: true,
codeAssist: false,
}),
getTelemetryLogUserPromptsEnabled: () => true,
getFileFilteringRespectGitIgnore: () => true,
getFileFilteringAllowBuildArtifacts: () => false,
getDebugMode: () => true,
getMcpServers: () => ({
'test-server': {
command: 'test-command',
},
}),
getQuestion: () => 'test-question',
} as unknown as Config;
logCliConfiguration(mockConfig);
expect(mockLogger.emit).toHaveBeenCalledWith({
body: 'CLI configuration loaded.',
attributes: {
'session.id': 'test-session-id',
'event.name': 'gemini_cli.config',
'event.timestamp': '2025-01-01T00:00:00.000Z',
model: 'test-model',
embedding_model: 'test-embedding-model',
sandbox_enabled: true,
core_tools_enabled: 'ls,read-file',
approval_mode: 'default',
api_key_enabled: true,
vertex_ai_enabled: true,
code_assist_enabled: false,
log_user_prompts_enabled: true,
file_filtering_respect_git_ignore: true,
file_filtering_allow_build_artifacts: false,
debug_mode: true,
mcp_servers: 'test-server',
},
});
});
});
describe('logApiResponse', () => {
const mockConfig = {
getSessionId: () => 'test-session-id',
} as Config;
const mockLogger = {
emit: vi.fn(),
};
const mockMetrics = {
recordApiResponseMetrics: vi.fn(),
recordTokenUsageMetrics: vi.fn(),
};
beforeEach(() => {
vi.spyOn(sdk, 'isTelemetrySdkInitialized').mockReturnValue(true);
vi.spyOn(logs, 'getLogger').mockReturnValue(mockLogger);
vi.spyOn(metrics, 'recordApiResponseMetrics').mockImplementation(
mockMetrics.recordApiResponseMetrics,
);
vi.spyOn(metrics, 'recordTokenUsageMetrics').mockImplementation(
mockMetrics.recordTokenUsageMetrics,
);
vi.useFakeTimers();
vi.setSystemTime(new Date('2025-01-01T00:00:00.000Z'));
});
it('should log an API response with all fields', () => {
@ -117,3 +182,4 @@ describe('logApiResponse', () => {
});
});
});
});

View File

@ -43,21 +43,28 @@ function getCommonAttributes(config: Config): LogAttributes {
export function logCliConfiguration(config: Config): void {
if (!isTelemetrySdkInitialized()) return;
const generatorConfig = config.getContentGeneratorConfig();
const mcpServers = config.getMcpServers();
const attributes: LogAttributes = {
...getCommonAttributes(config),
'event.name': EVENT_CLI_CONFIG,
'event.timestamp': new Date().toISOString(),
model: config.getModel(),
embedding_model: config.getEmbeddingModel(),
sandbox_enabled:
typeof config.getSandbox() === 'string' ? true : config.getSandbox(),
core_tools_enabled: (config.getCoreTools() ?? []).join(','),
approval_mode: config.getApprovalMode(),
vertex_ai_enabled: !!config.getContentGeneratorConfig().vertexai,
api_key_enabled: !!generatorConfig.apiKey,
vertex_ai_enabled: !!generatorConfig.vertexai,
code_assist_enabled: !!generatorConfig.codeAssist,
log_user_prompts_enabled: config.getTelemetryLogUserPromptsEnabled(),
file_filtering_respect_git_ignore:
config.getFileFilteringRespectGitIgnore(),
file_filtering_allow_build_artifacts:
config.getFileFilteringAllowBuildArtifacts(),
debug_mode: config.getDebugMode(),
mcp_servers: mcpServers ? Object.keys(mcpServers).join(',') : '',
};
const logger = logs.getLogger(SERVICE_NAME);
const logRecord: LogRecord = {