get-console-logs
Retrieve console logs from the Vite Dev server to monitor real-time updates. Specify checkpoints or limit the number of logs to focus on relevant debugging information.
Instructions
Retrieves console logs from the development server
Input Schema
| Name | Required | Description | Default |
|---|---|---|---|
| checkpoint | No | If specified, returns only logs recorded at this checkpoint | |
| limit | No | Number of logs to return, starting from the most recent log |
Input Schema (JSON Schema)
{
"$schema": "http://json-schema.org/draft-07/schema#",
"additionalProperties": false,
"properties": {
"checkpoint": {
"description": "If specified, returns only logs recorded at this checkpoint",
"type": "string"
},
"limit": {
"description": "Number of logs to return, starting from the most recent log",
"type": "number"
}
},
"type": "object"
}
Implementation Reference
- src/tools/browser-tools.ts:708-754 (registration)Registration of the 'get-console-logs' tool including input schema, description, and inline handler function that reads and parses logs using LogManagerserver.tool( 'get-console-logs', 'Retrieves console logs from the development server', { checkpoint: z.string().optional().describe('If specified, returns only logs recorded at this checkpoint'), limit: z.number().optional().describe('Number of logs to return, starting from the most recent log') }, async ({ checkpoint, limit = 100 }) => { try { // Read logs (always provide limit value) const result = await logManager.readLogs(limit, checkpoint); // Parse logs const parsedLogs = result.logs.map((log: string) => { try { return JSON.parse(log); } catch (error) { return { type: 'unknown', text: log, timestamp: new Date().toISOString() }; } }); return { content: [ { type: 'text', text: JSON.stringify({ logs: parsedLogs, writePosition: result.writePosition, totalLogs: result.totalLogs }, null, 2) } ] }; } catch (error) { Logger.error(`Failed to read console logs: ${error}`); return { content: [ { type: 'text', text: `Failed to read console logs: ${error}` } ], isError: true }; } } );
- src/tools/browser-tools.ts:708-754 (handler)Primary handler logic for executing the get-console-logs tool: reads recent logs via LogManager.readLogs, parses JSON entries, handles errors, and formats responseserver.tool( 'get-console-logs', 'Retrieves console logs from the development server', { checkpoint: z.string().optional().describe('If specified, returns only logs recorded at this checkpoint'), limit: z.number().optional().describe('Number of logs to return, starting from the most recent log') }, async ({ checkpoint, limit = 100 }) => { try { // Read logs (always provide limit value) const result = await logManager.readLogs(limit, checkpoint); // Parse logs const parsedLogs = result.logs.map((log: string) => { try { return JSON.parse(log); } catch (error) { return { type: 'unknown', text: log, timestamp: new Date().toISOString() }; } }); return { content: [ { type: 'text', text: JSON.stringify({ logs: parsedLogs, writePosition: result.writePosition, totalLogs: result.totalLogs }, null, 2) } ] }; } catch (error) { Logger.error(`Failed to read console logs: ${error}`); return { content: [ { type: 'text', text: `Failed to read console logs: ${error}` } ], isError: true }; } } );
- src/tools/browser-tools.ts:712-714 (schema)Input schema validation for get-console-logs tool using Zod: optional checkpoint ID and log limit (default 100)checkpoint: z.string().optional().describe('If specified, returns only logs recorded at this checkpoint'), limit: z.number().optional().describe('Number of logs to return, starting from the most recent log') },
- src/tools/log-manager.ts:199-300 (helper)Core LogManager.readLogs implementation: scans log directories for rotated files (per checkpoint or default), calculates positions, streams and skips to recent logs, returns last N raw log lines with metadatapublic async readLogs(limit: number, checkpointId?: string): Promise<{ logs: string[], writePosition: number, totalLogs: number }> { try { // 1. Calculate necessary information const logDir = path.dirname(this.getLogFilePath(0, checkpointId)); const filePattern = checkpointId ? new RegExp(`^chk-${checkpointId}-(\\d+)\\.log$`) : /^default-log-(\d+)\.log$/; // 2. Find log files in directory const files = fs.existsSync(logDir) ? fs.readdirSync(logDir) : []; const logFiles = files .filter(file => filePattern.test(file)) .map(file => { const match = file.match(filePattern); return { file, path: path.join(logDir, file), number: match ? parseInt(match[1], 10) : -1 }; }) .filter(item => item.number >= 0) .sort((a, b) => a.number - b.number); // Sort in order (oldest first) if (logFiles.length === 0) { return { logs: [], writePosition: 0, totalLogs: 0 }; } // 3. Calculate total number of logs (completed files + current file log count) const lastFileIndex = logFiles.length - 1; const completedFilesLogs = lastFileIndex * this.MAX_LOGS_PER_FILE; // Get log count of the last file let currentFileLogCount = 0; if (checkpointId) { const checkpointData = this.checkpointStreams.get(checkpointId); currentFileLogCount = checkpointData ? checkpointData.currentLogCount : 0; } else { currentFileLogCount = this.currentLogCount; } const totalLogs = completedFilesLogs + currentFileLogCount; // 4. Return empty result if no logs needed if (totalLogs === 0) { return { logs: [], writePosition: currentFileLogCount, totalLogs: 0 }; } // 5. Calculate start position and number of logs to read const startPosition = Math.max(0, totalLogs - limit); const startFileIndex = Math.floor(startPosition / this.MAX_LOGS_PER_FILE); const startLogInFile = startPosition % this.MAX_LOGS_PER_FILE; // 6. Read log files (using stream) const logs: string[] = []; let logsNeeded = Math.min(limit, totalLogs); for (let i = startFileIndex; i < logFiles.length && logsNeeded > 0; i++) { const filePath = logFiles[i].path; if (!fs.existsSync(filePath)) continue; // Read line by line using readline interface const rl = readline.createInterface({ input: fs.createReadStream(filePath, { encoding: 'utf-8' }), crlfDelay: Infinity }); let skippedLines = 0; // Skip lines if this is the first file and has a start position const shouldSkipLines = (i === startFileIndex && startLogInFile > 0); const linesToSkip = shouldSkipLines ? startLogInFile : 0; for await (const line of rl) { if (!line.trim()) continue; // Skip necessary lines if (shouldSkipLines && skippedLines < linesToSkip) { skippedLines++; continue; } logs.push(line); logsNeeded--; if (logsNeeded <= 0) { rl.close(); break; } } } // 7. Return result return { logs, writePosition: currentFileLogCount, totalLogs }; } catch (error) { Logger.error(`Failed to read logs: ${error}`); return { logs: [], writePosition: 0, totalLogs: 0 }; } }