migrate console.error to coreEvents/debugger for sandbox, logger, chatRecordingService (#12253)

This commit is contained in:
Sehoon Shon
2025-11-04 16:02:31 -05:00
committed by GitHub
parent 75c2769b32
commit b6524e410a
3 changed files with 52 additions and 35 deletions
+18 -18
View File
@@ -15,6 +15,7 @@ import { USER_SETTINGS_DIR } from '../config/settings.js';
import { promisify } from 'node:util'; import { promisify } from 'node:util';
import type { Config, SandboxConfig } from '@google/gemini-cli-core'; import type { Config, SandboxConfig } from '@google/gemini-cli-core';
import { import {
coreEvents,
debugLogger, debugLogger,
FatalSandboxError, FatalSandboxError,
GEMINI_DIR, GEMINI_DIR,
@@ -87,9 +88,8 @@ async function shouldUseCurrentUserInSandbox(): Promise<boolean> {
osReleaseContent.match(/^ID_LIKE=.*debian.*/m) || // Covers derivatives osReleaseContent.match(/^ID_LIKE=.*debian.*/m) || // Covers derivatives
osReleaseContent.match(/^ID_LIKE=.*ubuntu.*/m) // Covers derivatives osReleaseContent.match(/^ID_LIKE=.*ubuntu.*/m) // Covers derivatives
) { ) {
// note here and below we use console.error for informational messages on stderr debugLogger.log(
console.error( 'Defaulting to use current user UID/GID for Debian/Ubuntu-based Linux.',
'INFO: Defaulting to use current user UID/GID for Debian/Ubuntu-based Linux.',
); );
return true; return true;
} }
@@ -216,8 +216,7 @@ export async function start_sandbox(
`Missing macos seatbelt profile file '${profileFile}'`, `Missing macos seatbelt profile file '${profileFile}'`,
); );
} }
// Log on STDERR so it doesn't clutter the output on STDOUT debugLogger.log(`using macos seatbelt (profile: ${profile}) ...`);
console.error(`using macos seatbelt (profile: ${profile}) ...`);
// if DEBUG is set, convert to --inspect-brk in NODE_OPTIONS // if DEBUG is set, convert to --inspect-brk in NODE_OPTIONS
const nodeOptions = [ const nodeOptions = [
...(process.env['DEBUG'] ? ['--inspect-brk'] : []), ...(process.env['DEBUG'] ? ['--inspect-brk'] : []),
@@ -319,7 +318,7 @@ export async function start_sandbox(
// console.info(data.toString()); // console.info(data.toString());
// }); // });
proxyProcess.stderr?.on('data', (data) => { proxyProcess.stderr?.on('data', (data) => {
console.error(data.toString()); debugLogger.debug(`[PROXY STDERR]: ${data.toString().trim()}`);
}); });
proxyProcess.on('close', (code, signal) => { proxyProcess.on('close', (code, signal) => {
if (sandboxProcess?.pid) { if (sandboxProcess?.pid) {
@@ -348,7 +347,7 @@ export async function start_sandbox(
}); });
} }
console.error(`hopping into sandbox (command: ${config.command}) ...`); debugLogger.log(`hopping into sandbox (command: ${config.command}) ...`);
// determine full path for gemini-cli to distinguish linked vs installed setting // determine full path for gemini-cli to distinguish linked vs installed setting
const gcPath = fs.realpathSync(process.argv[1]); const gcPath = fs.realpathSync(process.argv[1]);
@@ -373,7 +372,7 @@ export async function start_sandbox(
'run `npm link ./packages/cli` under gemini-cli repo to switch to linked binary.', 'run `npm link ./packages/cli` under gemini-cli repo to switch to linked binary.',
); );
} else { } else {
console.error('building sandbox ...'); debugLogger.log('building sandbox ...');
const gcRoot = gcPath.split('/packages/')[0]; const gcRoot = gcPath.split('/packages/')[0];
// if project folder has sandbox.Dockerfile under project settings folder, use that // if project folder has sandbox.Dockerfile under project settings folder, use that
let buildArgs = ''; let buildArgs = '';
@@ -382,7 +381,7 @@ export async function start_sandbox(
'sandbox.Dockerfile', 'sandbox.Dockerfile',
); );
if (isCustomProjectSandbox) { if (isCustomProjectSandbox) {
console.error(`using ${projectSandboxDockerfile} for sandbox`); debugLogger.log(`using ${projectSandboxDockerfile} for sandbox`);
buildArgs += `-f ${path.resolve(projectSandboxDockerfile)} -i ${image}`; buildArgs += `-f ${path.resolve(projectSandboxDockerfile)} -i ${image}`;
} }
execSync( execSync(
@@ -497,7 +496,7 @@ export async function start_sandbox(
`Missing mount path '${from}' listed in SANDBOX_MOUNTS`, `Missing mount path '${from}' listed in SANDBOX_MOUNTS`,
); );
} }
console.error(`SANDBOX_MOUNTS: ${from} -> ${to} (${opts})`); debugLogger.log(`SANDBOX_MOUNTS: ${from} -> ${to} (${opts})`);
args.push('--volume', mount); args.push('--volume', mount);
} }
} }
@@ -679,7 +678,7 @@ export async function start_sandbox(
for (let env of process.env['SANDBOX_ENV'].split(',')) { for (let env of process.env['SANDBOX_ENV'].split(',')) {
if ((env = env.trim())) { if ((env = env.trim())) {
if (env.includes('=')) { if (env.includes('=')) {
console.error(`SANDBOX_ENV: ${env}`); debugLogger.log(`SANDBOX_ENV: ${env}`);
args.push('--env', env); args.push('--env', env);
} else { } else {
throw new FatalSandboxError( throw new FatalSandboxError(
@@ -789,7 +788,7 @@ export async function start_sandbox(
// console.info(data.toString()); // console.info(data.toString());
// }); // });
proxyProcess.stderr?.on('data', (data) => { proxyProcess.stderr?.on('data', (data) => {
console.error(data.toString().trim()); debugLogger.debug(`[PROXY STDERR]: ${data.toString().trim()}`);
}); });
proxyProcess.on('close', (code, signal) => { proxyProcess.on('close', (code, signal) => {
if (sandboxProcess?.pid) { if (sandboxProcess?.pid) {
@@ -818,7 +817,7 @@ export async function start_sandbox(
return new Promise<number>((resolve, reject) => { return new Promise<number>((resolve, reject) => {
sandboxProcess.on('error', (err) => { sandboxProcess.on('error', (err) => {
console.error('Sandbox process error:', err); coreEvents.emitFeedback('error', 'Sandbox process error', err);
reject(err); reject(err);
}); });
@@ -939,13 +938,13 @@ async function ensureSandboxImageIsPresent(
sandbox: string, sandbox: string,
image: string, image: string,
): Promise<boolean> { ): Promise<boolean> {
console.info(`Checking for sandbox image: ${image}`); debugLogger.log(`Checking for sandbox image: ${image}`);
if (await imageExists(sandbox, image)) { if (await imageExists(sandbox, image)) {
console.info(`Sandbox image ${image} found locally.`); debugLogger.log(`Sandbox image ${image} found locally.`);
return true; return true;
} }
console.info(`Sandbox image ${image} not found locally.`); debugLogger.log(`Sandbox image ${image} not found locally.`);
if (image === LOCAL_DEV_SANDBOX_IMAGE_NAME) { if (image === LOCAL_DEV_SANDBOX_IMAGE_NAME) {
// user needs to build the image themselves // user needs to build the image themselves
return false; return false;
@@ -954,7 +953,7 @@ async function ensureSandboxImageIsPresent(
if (await pullImage(sandbox, image)) { if (await pullImage(sandbox, image)) {
// After attempting to pull, check again to be certain // After attempting to pull, check again to be certain
if (await imageExists(sandbox, image)) { if (await imageExists(sandbox, image)) {
console.info(`Sandbox image ${image} is now available after pulling.`); debugLogger.log(`Sandbox image ${image} is now available after pulling.`);
return true; return true;
} else { } else {
debugLogger.warn( debugLogger.warn(
@@ -964,7 +963,8 @@ async function ensureSandboxImageIsPresent(
} }
} }
console.error( coreEvents.emitFeedback(
'error',
`Failed to obtain sandbox image ${image} after check and pull attempt.`, `Failed to obtain sandbox image ${image} after check and pull attempt.`,
); );
return false; // Pull command failed or image still not present return false; // Pull command failed or image still not present
+19 -9
View File
@@ -9,6 +9,7 @@ import { promises as fs } from 'node:fs';
import type { Content } from '@google/genai'; import type { Content } from '@google/genai';
import type { Storage } from '../config/storage.js'; import type { Storage } from '../config/storage.js';
import { debugLogger } from '../utils/debugLogger.js'; import { debugLogger } from '../utils/debugLogger.js';
import { coreEvents } from '../utils/events.js';
const LOG_FILE_NAME = 'logs.json'; const LOG_FILE_NAME = 'logs.json';
@@ -158,7 +159,7 @@ export class Logger {
: 0; : 0;
this.initialized = true; this.initialized = true;
} catch (err) { } catch (err) {
console.error('Failed to initialize logger:', err); coreEvents.emitFeedback('error', 'Failed to initialize logger:', err);
this.initialized = false; this.initialized = false;
} }
} }
@@ -315,7 +316,7 @@ export class Logger {
async saveCheckpoint(conversation: Content[], tag: string): Promise<void> { async saveCheckpoint(conversation: Content[], tag: string): Promise<void> {
if (!this.initialized) { if (!this.initialized) {
console.error( debugLogger.error(
'Logger not initialized or checkpoint file path not set. Cannot save a checkpoint.', 'Logger not initialized or checkpoint file path not set. Cannot save a checkpoint.',
); );
return; return;
@@ -325,13 +326,13 @@ export class Logger {
try { try {
await fs.writeFile(path, JSON.stringify(conversation, null, 2), 'utf-8'); await fs.writeFile(path, JSON.stringify(conversation, null, 2), 'utf-8');
} catch (error) { } catch (error) {
console.error('Error writing to checkpoint file:', error); debugLogger.error('Error writing to checkpoint file:', error);
} }
} }
async loadCheckpoint(tag: string): Promise<Content[]> { async loadCheckpoint(tag: string): Promise<Content[]> {
if (!this.initialized) { if (!this.initialized) {
console.error( debugLogger.error(
'Logger not initialized or checkpoint file path not set. Cannot load checkpoint.', 'Logger not initialized or checkpoint file path not set. Cannot load checkpoint.',
); );
return []; return [];
@@ -354,14 +355,17 @@ export class Logger {
// This is okay, it just means the checkpoint doesn't exist in either format. // This is okay, it just means the checkpoint doesn't exist in either format.
return []; return [];
} }
console.error(`Failed to read or parse checkpoint file ${path}:`, error); debugLogger.error(
`Failed to read or parse checkpoint file ${path}:`,
error,
);
return []; return [];
} }
} }
async deleteCheckpoint(tag: string): Promise<boolean> { async deleteCheckpoint(tag: string): Promise<boolean> {
if (!this.initialized || !this.geminiDir) { if (!this.initialized || !this.geminiDir) {
console.error( debugLogger.error(
'Logger not initialized or checkpoint file path not set. Cannot delete checkpoint.', 'Logger not initialized or checkpoint file path not set. Cannot delete checkpoint.',
); );
return false; return false;
@@ -377,7 +381,10 @@ export class Logger {
} catch (error) { } catch (error) {
const nodeError = error as NodeJS.ErrnoException; const nodeError = error as NodeJS.ErrnoException;
if (nodeError.code !== 'ENOENT') { if (nodeError.code !== 'ENOENT') {
console.error(`Failed to delete checkpoint file ${newPath}:`, error); debugLogger.error(
`Failed to delete checkpoint file ${newPath}:`,
error,
);
throw error; // Rethrow unexpected errors throw error; // Rethrow unexpected errors
} }
// It's okay if it doesn't exist. // It's okay if it doesn't exist.
@@ -392,7 +399,10 @@ export class Logger {
} catch (error) { } catch (error) {
const nodeError = error as NodeJS.ErrnoException; const nodeError = error as NodeJS.ErrnoException;
if (nodeError.code !== 'ENOENT') { if (nodeError.code !== 'ENOENT') {
console.error(`Failed to delete checkpoint file ${oldPath}:`, error); debugLogger.error(
`Failed to delete checkpoint file ${oldPath}:`,
error,
);
throw error; // Rethrow unexpected errors throw error; // Rethrow unexpected errors
} }
// It's okay if it doesn't exist. // It's okay if it doesn't exist.
@@ -421,7 +431,7 @@ export class Logger {
return false; // It truly doesn't exist in either format. return false; // It truly doesn't exist in either format.
} }
// A different error occurred. // A different error occurred.
console.error( debugLogger.error(
`Failed to check checkpoint existence for ${ `Failed to check checkpoint existence for ${
filePath ?? `path for tag "${tag}"` filePath ?? `path for tag "${tag}"`
}:`, }:`,
@@ -15,6 +15,7 @@ import type {
PartListUnion, PartListUnion,
GenerateContentResponseUsageMetadata, GenerateContentResponseUsageMetadata,
} from '@google/genai'; } from '@google/genai';
import { debugLogger } from '../utils/debugLogger.js';
export const SESSION_FILE_PREFIX = 'session-'; export const SESSION_FILE_PREFIX = 'session-';
@@ -170,7 +171,7 @@ export class ChatRecordingService {
this.queuedThoughts = []; this.queuedThoughts = [];
this.queuedTokens = null; this.queuedTokens = null;
} catch (error) { } catch (error) {
console.error('Error initializing chat recording service:', error); debugLogger.error('Error initializing chat recording service:', error);
throw error; throw error;
} }
} }
@@ -222,7 +223,7 @@ export class ChatRecordingService {
} }
}); });
} catch (error) { } catch (error) {
console.error('Error saving message:', error); debugLogger.error('Error saving message to chat history.', error);
throw error; throw error;
} }
} }
@@ -239,7 +240,7 @@ export class ChatRecordingService {
timestamp: new Date().toISOString(), timestamp: new Date().toISOString(),
}); });
} catch (error) { } catch (error) {
console.error('Error saving thought:', error); debugLogger.error('Error saving thought to chat history.', error);
throw error; throw error;
} }
} }
@@ -273,7 +274,10 @@ export class ChatRecordingService {
} }
}); });
} catch (error) { } catch (error) {
console.error('Error updating message tokens:', error); debugLogger.error(
'Error updating message tokens in chat history.',
error,
);
throw error; throw error;
} }
} }
@@ -367,7 +371,10 @@ export class ChatRecordingService {
} }
}); });
} catch (error) { } catch (error) {
console.error('Error adding tool call to message:', error); debugLogger.error(
'Error adding tool call to message in chat history.',
error,
);
throw error; throw error;
} }
} }
@@ -381,7 +388,7 @@ export class ChatRecordingService {
return JSON.parse(this.cachedLastConvData); return JSON.parse(this.cachedLastConvData);
} catch (error) { } catch (error) {
if ((error as NodeJS.ErrnoException).code !== 'ENOENT') { if ((error as NodeJS.ErrnoException).code !== 'ENOENT') {
console.error('Error reading conversation file:', error); debugLogger.error('Error reading conversation file.', error);
throw error; throw error;
} }
@@ -413,7 +420,7 @@ export class ChatRecordingService {
fs.writeFileSync(this.conversationFile, newContent); fs.writeFileSync(this.conversationFile, newContent);
} }
} catch (error) { } catch (error) {
console.error('Error writing conversation file:', error); debugLogger.error('Error writing conversation file.', error);
throw error; throw error;
} }
} }
@@ -442,7 +449,7 @@ export class ChatRecordingService {
const sessionPath = path.join(chatsDir, `${sessionId}.json`); const sessionPath = path.join(chatsDir, `${sessionId}.json`);
fs.unlinkSync(sessionPath); fs.unlinkSync(sessionPath);
} catch (error) { } catch (error) {
console.error('Error deleting session:', error); debugLogger.error('Error deleting session file.', error);
throw error; throw error;
} }
} }