| 213 | } |
| 214 | |
| 215 | private log(level: string, message: string, error?: Error) { |
| 216 | const timestamp = formatForDatabase(); |
| 217 | const errorInfo = error ? ` Error: ${error.message}\nStack: ${error.stack}` : ''; |
| 218 | const fullMessage = `[${timestamp}] ${level}: ${message}${errorInfo}`; |
| 219 | |
| 220 | // Try to log to console, but handle EPIPE errors gracefully |
| 221 | try { |
| 222 | // Always log to console using the original console method to avoid recursion |
| 223 | this.originalConsole.log(fullMessage); |
| 224 | } catch (consoleError: unknown) { |
| 225 | // If console logging fails (e.g., EPIPE), just write to file |
| 226 | if ((consoleError as NodeJS.ErrnoException)?.code !== 'EPIPE' && !this.isInErrorHandler) { |
| 227 | // Prevent recursion by setting flag |
| 228 | this.isInErrorHandler = true; |
| 229 | try { |
| 230 | // For non-EPIPE errors, try to at least write the error to file |
| 231 | // Use a direct write to avoid potential recursion through writeToFile |
| 232 | const errorMessage = `[${timestamp}] ERROR: Failed to write to console: ${(consoleError as Error)?.message || 'Unknown error'}\n`; |
| 233 | if (this.logStream && !this.logStream.destroyed) { |
| 234 | this.logStream.write(errorMessage); |
| 235 | } |
| 236 | } catch { |
| 237 | // Silently fail - we've done our best |
| 238 | } finally { |
| 239 | this.isInErrorHandler = false; |
| 240 | } |
| 241 | } |
| 242 | } |
| 243 | |
| 244 | // Also write to file (unless we're in error handler to prevent recursion) |
| 245 | if (!this.isInErrorHandler) { |
| 246 | this.writeToFile(fullMessage); |
| 247 | } |
| 248 | } |
| 249 | |
| 250 | verbose(message: string) { |
| 251 | if (this.configManager.isVerbose()) { |