UNPKG

@mrtkrcm/acp-claude-code

Version:

ACP (Agent Client Protocol) bridge for Claude Code

139 lines 5.16 kB
import { createWriteStream } from 'node:fs'; import { resolve } from 'node:path'; export class Logger { component; debugMode; fileLogger = null; logBuffer = []; flushTimer; BUFFER_SIZE = 50; MAX_BUFFER_SIZE = 200; // Prevent memory leaks FLUSH_INTERVAL = 5000; // 5 seconds constructor(component, debugMode = false) { this.component = component; this.debugMode = debugMode; this.initializeFileLogging(); } initializeFileLogging() { const logFile = process.env.ACP_LOG_FILE; if (!logFile) return; try { const logPath = resolve(logFile); this.fileLogger = createWriteStream(logPath, { flags: 'a' }); this.fileLogger.on('error', (error) => { console.error(`[${this.component}] Log file error: ${error.message}`); this.fileLogger = null; }); } catch (error) { console.error(`[${this.component}] Failed to create log file: ${error}`); } } log(message, level = 'DEBUG', contextOrArgs, ...args) { // Handle flexible parameter types for backwards compatibility let context; let allArgs = args; if (typeof contextOrArgs === 'object' && contextOrArgs !== null && !Array.isArray(contextOrArgs)) { try { context = contextOrArgs; } catch { allArgs = [contextOrArgs, ...args]; } } else if (contextOrArgs !== undefined) { allArgs = [contextOrArgs, ...args]; } const entry = { timestamp: new Date().toISOString(), level, component: this.component, message, context, args: allArgs.length > 0 ? allArgs.map(arg => typeof arg === 'object' ? JSON.stringify(arg) : String(arg)) : undefined }; const formattedMessage = `[${entry.timestamp}] [${level}] [${this.component}] ${message}`; const argsStr = entry.args?.length ? ` ${entry.args.join(' ')}` : ''; // Console output based on level and debug setting if (this.debugMode || level !== 'DEBUG') { const consoleMethod = this.getConsoleMethod(level); consoleMethod(formattedMessage + argsStr); } // File logging with buffering and overflow protection if (this.fileLogger) { // Prevent buffer overflow by removing old entries if (this.logBuffer.length >= this.MAX_BUFFER_SIZE) { this.logBuffer.shift(); // Remove oldest entry } this.logBuffer.push(entry); // Immediate flush for errors or if buffer is full if (level === 'ERROR' || this.logBuffer.length >= this.BUFFER_SIZE) { this.flushLogBuffer(); } else if (!this.flushTimer) { // Schedule flush this.flushTimer = setTimeout(() => this.flushLogBuffer(), this.FLUSH_INTERVAL); } } } getConsoleMethod(level) { switch (level) { case 'ERROR': return console.error; case 'WARN': return console.warn; default: return console.log; } } debug(message, contextOrArgs, ...args) { this.log(message, 'DEBUG', contextOrArgs, ...args); } info(message, contextOrArgs, ...args) { this.log(message, 'INFO', contextOrArgs, ...args); } warn(message, contextOrArgs, ...args) { this.log(message, 'WARN', contextOrArgs, ...args); } error(message, contextOrArgs, ...args) { this.log(message, 'ERROR', contextOrArgs, ...args); } writeStartupMessage() { if (this.fileLogger) { this.fileLogger.write(`\n=== ${this.component} Started at ${new Date().toISOString()} ===\n`); } } writeShutdownMessage() { if (this.fileLogger) { this.fileLogger.write(`=== ${this.component} Stopped at ${new Date().toISOString()} ===\n`); this.fileLogger.end(); } } flushLogBuffer() { if (this.logBuffer.length === 0) return; if (this.fileLogger) { const entries = this.logBuffer.splice(0); // Clear buffer const logText = entries.map(entry => JSON.stringify(entry)).join('\n') + '\n'; try { this.fileLogger.write(logText); } catch (error) { // If write fails, clear buffer to prevent memory leak console.error(`[${this.component}] Failed to write log buffer: ${error}`); } } if (this.flushTimer) { clearTimeout(this.flushTimer); this.flushTimer = undefined; } } destroy() { // Flush any remaining logs this.flushLogBuffer(); this.writeShutdownMessage(); } } // Factory function for consistent logger creation export function createLogger(component) { return new Logger(component, process.env.ACP_DEBUG === 'true'); } //# sourceMappingURL=logger.js.map