/** * Logging utility with structured output */ export enum LogLevel { DEBUG = 0, INFO = 1, WARN = 2, ERROR = 3, } class Logger { private level: LogLevel = LogLevel.INFO; private logFile: string | null = null; setLevel(level: LogLevel): void { this.level = level; } setLogFile(path: string): void { this.logFile = path; } debug(message: string, ...args: any[]): void { this.log(LogLevel.DEBUG, message, ...args); } info(message: string, ...args: any[]): void { this.log(LogLevel.INFO, message, ...args); } warn(message: string, ...args: any[]): void { this.log(LogLevel.WARN, message, ...args); } error(message: string, ...args: any[]): void { this.log(LogLevel.ERROR, message, ...args); } private log(level: LogLevel, message: string, ...args: any[]): void { if (level < this.level) return; const timestamp = new Date().toISOString(); const levelName = LogLevel[level]; const formattedMessage = `[${timestamp}] [${levelName}] ${message}`; // Console output with colors const coloredMessage = this.colorize(level, formattedMessage); console.log(coloredMessage, ...args); // File output (if configured) if (this.logFile) { const fileMessage = `${formattedMessage} ${args.length > 0 ? JSON.stringify(args) : ''}\n`; Bun.write(this.logFile, fileMessage, { createPath: true }); } } private colorize(level: LogLevel, message: string): string { const colors = { [LogLevel.DEBUG]: '\x1b[36m', // Cyan [LogLevel.INFO]: '\x1b[32m', // Green [LogLevel.WARN]: '\x1b[33m', // Yellow [LogLevel.ERROR]: '\x1b[31m', // Red }; const reset = '\x1b[0m'; return `${colors[level]}${message}${reset}`; } } export const logger = new Logger();