Merge pull request #1610 from QwenLM/feat/debug-logging-refactor
Some checks are pending
Qwen Code CI / CodeQL (push) Waiting to run
Qwen Code CI / Test-3 (push) Blocked by required conditions
Qwen Code CI / Lint (push) Waiting to run
Qwen Code CI / Test (push) Blocked by required conditions
Qwen Code CI / Test-1 (push) Blocked by required conditions
Qwen Code CI / Test-2 (push) Blocked by required conditions
Qwen Code CI / Post Coverage Comment (push) Blocked by required conditions
Qwen Code CI / Test-4 (push) Blocked by required conditions
Qwen Code CI / Test-5 (push) Blocked by required conditions
Qwen Code CI / Test-6 (push) Blocked by required conditions
Qwen Code CI / Test-7 (push) Blocked by required conditions
Qwen Code CI / Test-8 (push) Blocked by required conditions
E2E Tests / E2E Test (Linux) - sandbox:docker (push) Waiting to run
E2E Tests / E2E Test (Linux) - sandbox:none (push) Waiting to run
E2E Tests / E2E Test - macOS (push) Waiting to run

feat: debug mode output refactor — route console calls to logfile-first debugLogger
This commit is contained in:
tanzhenxin 2026-02-05 20:42:50 +08:00 committed by GitHub
commit 83fd2bc7f9
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
250 changed files with 3423 additions and 3734 deletions

View file

@ -34,6 +34,7 @@ import {
type IdeContext,
IdeClient,
ideContextStore,
createDebugLogger,
getErrorMessage,
getAllGeminiMdFilenames,
ShellExecutionService,
@ -55,7 +56,6 @@ import { useApprovalModeCommand } from './hooks/useApprovalModeCommand.js';
import { useResumeCommand } from './hooks/useResumeCommand.js';
import { useSlashCommandProcessor } from './hooks/slashCommandProcessor.js';
import { useVimMode } from './contexts/VimModeContext.js';
import { useConsoleMessages } from './hooks/useConsoleMessages.js';
import { useTerminalSize } from './hooks/useTerminalSize.js';
import { calculatePromptWidths } from './components/InputPrompt.js';
import { useStdin, useStdout } from 'ink';
@ -63,6 +63,7 @@ import ansiEscapes from 'ansi-escapes';
import * as fs from 'node:fs';
import { basename } from 'node:path';
import { computeWindowTitle } from '../utils/windowTitle.js';
import { clearScreen } from '../utils/stdioHelpers.js';
import { useTextBuffer } from './components/shared/text-buffer.js';
import { useLogger } from './hooks/useLogger.js';
import { useGeminiStream } from './hooks/useGeminiStream.js';
@ -80,10 +81,8 @@ import { type IdeIntegrationNudgeResult } from './IdeIntegrationNudge.js';
import { type CommandMigrationNudgeResult } from './CommandFormatMigrationNudge.js';
import { useCommandMigration } from './hooks/useCommandMigration.js';
import { migrateTomlCommands } from '../services/command-migration-tool.js';
import { appEvents, AppEvent } from '../utils/events.js';
import { type UpdateObject } from './utils/updateCheck.js';
import { setUpdateHandler } from '../utils/handleAutoUpdate.js';
import { ConsolePatcher } from './utils/ConsolePatcher.js';
import { registerCleanup, runExitCleanup } from '../utils/cleanup.js';
import { useMessageQueue } from './hooks/useMessageQueue.js';
import { useAutoAcceptIndicator } from './hooks/useAutoAcceptIndicator.js';
@ -111,6 +110,7 @@ import {
} from '../commands/extensions/consent.js';
const CTRL_EXIT_PROMPT_DURATION_MS = 1000;
const debugLogger = createDebugLogger('APP_CONTAINER');
function isToolExecuting(pendingHistoryItems: HistoryItemWithoutId[]) {
return pendingHistoryItems.some((item) => {
@ -313,21 +313,6 @@ export const AppContainer = (props: AppContainerProps) => {
return () => clearInterval(interval);
}, [config, currentModel, getCurrentModel]);
const {
consoleMessages,
handleNewMessage,
clearConsoleMessages: clearConsoleMessagesState,
} = useConsoleMessages();
useEffect(() => {
const consolePatcher = new ConsolePatcher({
onNewMessage: handleNewMessage,
debugMode: config.getDebugMode(),
});
consolePatcher.patch();
registerCleanup(consolePatcher.cleanup);
}, [handleNewMessage, config]);
// Derive widths for InputPrompt using shared helper
const { inputWidth, suggestionsWidth } = useMemo(() => {
const { inputWidth, suggestionsWidth } =
@ -607,10 +592,13 @@ export const AppContainer = (props: AppContainerProps) => {
[visionSwitchResolver],
);
// onDebugMessage should log to console, not update footer debugMessage
const onDebugMessage = useCallback((message: string) => {
console.debug(message);
}, []);
// onDebugMessage should log to debug logfile, not update footer debugMessage
const onDebugMessage = useCallback(
(message: string) => {
config.getDebugLogger().debug(message);
},
[config],
);
const performMemoryRefresh = useCallback(async () => {
historyManager.addItem(
@ -626,7 +614,6 @@ export const AppContainer = (props: AppContainerProps) => {
settings.merged.context?.loadFromIncludeDirectories
? config.getWorkspaceContext().getDirectories()
: [],
config.getDebugMode(),
config.getFileService(),
config.getExtensionContextFilePaths(),
config.isTrustedFolder(),
@ -648,14 +635,12 @@ export const AppContainer = (props: AppContainerProps) => {
},
Date.now(),
);
if (config.getDebugMode()) {
console.log(
`[DEBUG] Refreshed memory content in config: ${memoryContent.substring(
0,
200,
)}...`,
);
}
debugLogger.debug(
`[DEBUG] Refreshed memory content in config: ${memoryContent.substring(
0,
200,
)}...`,
);
} catch (error) {
const errorMessage = getErrorMessage(error);
historyManager.addItem(
@ -665,7 +650,7 @@ export const AppContainer = (props: AppContainerProps) => {
},
Date.now(),
);
console.error('Error refreshing memory:', error);
debugLogger.error('Error refreshing memory:', error);
}
}, [config, historyManager, settings.merged]);
@ -769,10 +754,9 @@ export const AppContainer = (props: AppContainerProps) => {
const handleClearScreen = useCallback(() => {
historyManager.clearItems();
clearConsoleMessagesState();
console.clear();
clearScreen();
refreshStatic();
}, [historyManager, clearConsoleMessagesState, refreshStatic]);
}, [historyManager, refreshStatic]);
const { handleInput: vimHandleInput } = useVim(buffer, handleFinalSubmit);
@ -900,7 +884,6 @@ export const AppContainer = (props: AppContainerProps) => {
setShowMigrationNudge: setShowCommandMigrationNudge,
} = useCommandMigration(settings, config.storage);
const [showErrorDetails, setShowErrorDetails] = useState<boolean>(false);
const [showToolDescriptions, setShowToolDescriptions] =
useState<boolean>(false);
@ -951,28 +934,6 @@ export const AppContainer = (props: AppContainerProps) => {
return unsubscribe;
}, []);
useEffect(() => {
const openDebugConsole = () => {
setShowErrorDetails(true);
setConstrainHeight(false);
};
appEvents.on(AppEvent.OpenDebugConsole, openDebugConsole);
const logErrorHandler = (errorMessage: unknown) => {
handleNewMessage({
type: 'error',
content: String(errorMessage),
count: 1,
});
};
appEvents.on(AppEvent.LogError, logErrorHandler);
return () => {
appEvents.off(AppEvent.OpenDebugConsole, openDebugConsole);
appEvents.off(AppEvent.LogError, logErrorHandler);
};
}, [handleNewMessage]);
const handleEscapePromptChange = useCallback((showPrompt: boolean) => {
setShowEscapePrompt(showPrompt);
}, []);
@ -1180,7 +1141,7 @@ export const AppContainer = (props: AppContainerProps) => {
(key: Key) => {
// Debug log keystrokes if enabled
if (settings.merged.general?.debugKeystrokeLogging) {
console.log('[DEBUG] Keystroke:', JSON.stringify(key));
debugLogger.debug('[DEBUG] Keystroke:', JSON.stringify(key));
}
if (keyMatchers[Command.QUIT](key)) {
@ -1214,9 +1175,7 @@ export const AppContainer = (props: AppContainerProps) => {
setConstrainHeight(true);
}
if (keyMatchers[Command.SHOW_ERROR_DETAILS](key)) {
setShowErrorDetails((prev) => !prev);
} else if (keyMatchers[Command.TOGGLE_TOOL_DESCRIPTIONS](key)) {
if (keyMatchers[Command.TOGGLE_TOOL_DESCRIPTIONS](key)) {
const newValue = !showToolDescriptions;
setShowToolDescriptions(newValue);
@ -1244,7 +1203,6 @@ export const AppContainer = (props: AppContainerProps) => {
[
constrainHeight,
setConstrainHeight,
setShowErrorDetails,
showToolDescriptions,
setShowToolDescriptions,
config,
@ -1303,22 +1261,6 @@ export const AppContainer = (props: AppContainerProps) => {
stdout,
]);
const filteredConsoleMessages = useMemo(() => {
if (config.getDebugMode()) {
return consoleMessages;
}
return consoleMessages.filter((msg) => msg.type !== 'debug');
}, [consoleMessages, config]);
// Computed values
const errorCount = useMemo(
() =>
filteredConsoleMessages
.filter((msg) => msg.type === 'error')
.reduce((total, msg) => total + msg.count, 0),
[filteredConsoleMessages],
);
const nightly = props.version.includes('nightly');
const dialogsVisible =
@ -1413,8 +1355,6 @@ export const AppContainer = (props: AppContainerProps) => {
isFolderTrustDialogOpen: isFolderTrustDialogOpen ?? false,
isTrustedFolder,
constrainHeight,
showErrorDetails,
filteredConsoleMessages,
ideContextState,
showToolDescriptions,
ctrlCPressedOnce,
@ -1428,7 +1368,6 @@ export const AppContainer = (props: AppContainerProps) => {
showAutoAcceptIndicator,
currentModel,
contextFileNames,
errorCount,
availableTerminalHeight,
mainAreaWidth,
staticAreaMaxItemHeight,
@ -1506,8 +1445,6 @@ export const AppContainer = (props: AppContainerProps) => {
isFolderTrustDialogOpen,
isTrustedFolder,
constrainHeight,
showErrorDetails,
filteredConsoleMessages,
ideContextState,
showToolDescriptions,
ctrlCPressedOnce,
@ -1520,7 +1457,6 @@ export const AppContainer = (props: AppContainerProps) => {
messageQueue,
showAutoAcceptIndicator,
contextFileNames,
errorCount,
availableTerminalHeight,
mainAreaWidth,
staticAreaMaxItemHeight,