mirror of
https://github.com/QwenLM/qwen-code.git
synced 2025-12-20 08:47:44 +00:00
Clearcut logging - initial implementation (#1274)
Flag-guarded initial implementation of a clearcut logger to collect telemetry data and send it to Concord for dashboards, etc.
This commit is contained in:
@@ -11,13 +11,11 @@ import { Settings } from './settings.js';
|
||||
import { Extension } from './extension.js';
|
||||
import * as ServerConfig from '@gemini-cli/core';
|
||||
|
||||
const MOCK_HOME_DIR = '/mock/home/user';
|
||||
|
||||
vi.mock('os', async (importOriginal) => {
|
||||
const actualOs = await importOriginal<typeof os>();
|
||||
return {
|
||||
...actualOs,
|
||||
homedir: vi.fn(() => MOCK_HOME_DIR),
|
||||
homedir: vi.fn(() => '/mock/home/user'),
|
||||
};
|
||||
});
|
||||
|
||||
@@ -53,7 +51,7 @@ describe('loadCliConfig', () => {
|
||||
|
||||
beforeEach(() => {
|
||||
vi.resetAllMocks();
|
||||
vi.mocked(os.homedir).mockReturnValue(MOCK_HOME_DIR);
|
||||
vi.mocked(os.homedir).mockReturnValue('/mock/home/user');
|
||||
process.env.GEMINI_API_KEY = 'test-api-key'; // Ensure API key is set for tests
|
||||
});
|
||||
|
||||
@@ -98,7 +96,7 @@ describe('loadCliConfig telemetry', () => {
|
||||
|
||||
beforeEach(() => {
|
||||
vi.resetAllMocks();
|
||||
vi.mocked(os.homedir).mockReturnValue(MOCK_HOME_DIR);
|
||||
vi.mocked(os.homedir).mockReturnValue('/mock/home/user');
|
||||
process.env.GEMINI_API_KEY = 'test-api-key';
|
||||
});
|
||||
|
||||
@@ -250,7 +248,7 @@ describe('loadCliConfig telemetry', () => {
|
||||
describe('Hierarchical Memory Loading (config.ts) - Placeholder Suite', () => {
|
||||
beforeEach(() => {
|
||||
vi.resetAllMocks();
|
||||
vi.mocked(os.homedir).mockReturnValue(MOCK_HOME_DIR);
|
||||
vi.mocked(os.homedir).mockReturnValue('/mock/home/user');
|
||||
// Other common mocks would be reset here.
|
||||
});
|
||||
|
||||
@@ -310,7 +308,7 @@ describe('Hierarchical Memory Loading (config.ts) - Placeholder Suite', () => {
|
||||
// Example of a previously failing test structure:
|
||||
/*
|
||||
it('should correctly use mocked homedir for global path', async () => {
|
||||
const MOCK_GEMINI_DIR_LOCAL = path.join(MOCK_HOME_DIR, '.gemini');
|
||||
const MOCK_GEMINI_DIR_LOCAL = path.join('/mock/home/user', '.gemini');
|
||||
const MOCK_GLOBAL_PATH_LOCAL = path.join(MOCK_GEMINI_DIR_LOCAL, 'GEMINI.md');
|
||||
mockFs({
|
||||
[MOCK_GLOBAL_PATH_LOCAL]: { type: 'file', content: 'GlobalContentOnly' }
|
||||
|
||||
@@ -226,6 +226,7 @@ export async function loadCliConfig(
|
||||
process.env.OTEL_EXPORTER_OTLP_ENDPOINT ??
|
||||
settings.telemetry?.otlpEndpoint,
|
||||
logPrompts: argv.telemetryLogPrompts ?? settings.telemetry?.logPrompts,
|
||||
disableDataCollection: settings.telemetry?.disableDataCollection ?? true,
|
||||
},
|
||||
// Git-aware file filtering settings
|
||||
fileFiltering: {
|
||||
|
||||
@@ -6,15 +6,13 @@
|
||||
|
||||
/// <reference types="vitest/globals" />
|
||||
|
||||
const MOCK_HOME_DIR = '/mock/home/user'; // MUST BE FIRST
|
||||
|
||||
// Mock 'os' first. Its factory uses MOCK_HOME_DIR.
|
||||
// Mock 'os' first.
|
||||
import * as osActual from 'os'; // Import for type info for the mock factory
|
||||
vi.mock('os', async (importOriginal) => {
|
||||
const actualOs = await importOriginal<typeof osActual>();
|
||||
return {
|
||||
...actualOs,
|
||||
homedir: vi.fn(() => MOCK_HOME_DIR),
|
||||
homedir: vi.fn(() => '/mock/home/user'),
|
||||
};
|
||||
});
|
||||
|
||||
@@ -77,7 +75,7 @@ describe('Settings Loading and Merging', () => {
|
||||
mockFsMkdirSync = vi.mocked(fs.mkdirSync);
|
||||
mockStripJsonComments = vi.mocked(stripJsonComments);
|
||||
|
||||
vi.mocked(osActual.homedir).mockReturnValue(MOCK_HOME_DIR);
|
||||
vi.mocked(osActual.homedir).mockReturnValue('/mock/home/user');
|
||||
(mockStripJsonComments as unknown as Mock).mockImplementation(
|
||||
(jsonString: string) => jsonString,
|
||||
);
|
||||
|
||||
@@ -131,6 +131,8 @@ export async function main() {
|
||||
}
|
||||
|
||||
logUserPrompt(config, {
|
||||
'event.name': 'user_prompt',
|
||||
'event.timestamp': new Date().toISOString(),
|
||||
prompt: input,
|
||||
prompt_length: input.length,
|
||||
});
|
||||
|
||||
@@ -38,12 +38,17 @@ const MockedGeminiClientClass = vi.hoisted(() =>
|
||||
}),
|
||||
);
|
||||
|
||||
const MockedUserPromptEvent = vi.hoisted(() =>
|
||||
vi.fn().mockImplementation(() => {}),
|
||||
);
|
||||
|
||||
vi.mock('@gemini-cli/core', async (importOriginal) => {
|
||||
const actualCoreModule = (await importOriginal()) as any;
|
||||
return {
|
||||
...actualCoreModule,
|
||||
GitService: vi.fn(),
|
||||
GeminiClient: MockedGeminiClientClass,
|
||||
UserPromptEvent: MockedUserPromptEvent,
|
||||
};
|
||||
});
|
||||
|
||||
@@ -283,6 +288,7 @@ describe('useGeminiStream', () => {
|
||||
getProjectRoot: vi.fn(() => '/test/dir'),
|
||||
getCheckpointingEnabled: vi.fn(() => false),
|
||||
getGeminiClient: mockGetGeminiClient,
|
||||
getDisableDataCollection: () => false,
|
||||
addHistory: vi.fn(),
|
||||
} as unknown as Config;
|
||||
mockOnDebugMessage = vi.fn();
|
||||
|
||||
@@ -23,6 +23,7 @@ import {
|
||||
EditorType,
|
||||
ThoughtSummary,
|
||||
isAuthError,
|
||||
UserPromptEvent,
|
||||
} from '@gemini-cli/core';
|
||||
import { type Part, type PartListUnion } from '@google/genai';
|
||||
import {
|
||||
@@ -213,10 +214,10 @@ export const useGeminiStream = (
|
||||
|
||||
if (typeof query === 'string') {
|
||||
const trimmedQuery = query.trim();
|
||||
logUserPrompt(config, {
|
||||
prompt: trimmedQuery,
|
||||
prompt_length: trimmedQuery.length,
|
||||
});
|
||||
logUserPrompt(
|
||||
config,
|
||||
new UserPromptEvent(trimmedQuery.length, trimmedQuery),
|
||||
);
|
||||
onDebugMessage(`User query: '${trimmedQuery}'`);
|
||||
await logger?.logMessage(MessageSenderType.USER, trimmedQuery);
|
||||
|
||||
|
||||
@@ -48,6 +48,7 @@ const mockToolRegistry = {
|
||||
const mockConfig = {
|
||||
getToolRegistry: vi.fn(() => mockToolRegistry as unknown as ToolRegistry),
|
||||
getApprovalMode: vi.fn(() => ApprovalMode.DEFAULT),
|
||||
getDisableDataCollection: () => false,
|
||||
};
|
||||
|
||||
const mockTool: Tool = {
|
||||
|
||||
Reference in New Issue
Block a user