MCP GitHub Issue Server

import { Logger } from './index.js'; import { LoggerHealthStatus } from '../types/logging.js'; /** * Monitors logger health and handles recovery */ export class LoggerHealthMonitor { private lastHealthCheck = 0; private consecutiveFailures = 0; private readonly MAX_CONSECUTIVE_FAILURES = 3; private readonly HEALTH_CHECK_INTERVAL = 5000; // 5 seconds constructor( private readonly logger: Logger, private readonly onUnhealthy: (status: LoggerHealthStatus) => void ) {} /** * Performs a comprehensive health check of the logger */ async checkHealth(): Promise<LoggerHealthStatus> { const now = Date.now(); // Only check every 5 seconds to reduce overhead if (now - this.lastHealthCheck < this.HEALTH_CHECK_INTERVAL) { return { healthy: true }; } try { // Test file descriptors (if using file transport) await this.checkFileDescriptors(); // Test write capability await this.testLogWrite(); // Test error handling await this.testErrorLogging(); // Reset failure count on success this.consecutiveFailures = 0; this.lastHealthCheck = now; return { healthy: true }; } catch (error) { this.consecutiveFailures++; const status: LoggerHealthStatus = { healthy: false, error: error instanceof Error ? error.message : String(error), consecutiveFailures: this.consecutiveFailures, lastCheckTime: now, }; // Notify if max failures exceeded if (this.consecutiveFailures >= this.MAX_CONSECUTIVE_FAILURES) { this.onUnhealthy(status); } return status; } } /** * Checks if file descriptors are valid and writable */ private async checkFileDescriptors(): Promise<void> { // Implementation depends on logger transport type // For now, we'll just check if the logger instance exists if (!this.logger) { throw new Error('Logger instance is null or undefined'); } } /** * Tests basic log writing capability */ private async testLogWrite(): Promise<void> { return new Promise<void>((resolve, reject) => { try { this.logger.debug('Logger health check - write test'); resolve(); } catch (error) { reject(error); } }); } /** * Tests error logging capability */ private async testErrorLogging(): Promise<void> { return new Promise<void>((resolve, reject) => { try { const testError = new Error('Logger health check - error test'); this.logger.error('Test error logging', testError); resolve(); } catch (error) { reject(error); } }); } /** * Attempts to recover logger functionality */ async attemptRecovery(): Promise<boolean> { try { // Basic recovery attempts: // 1. Flush any pending writes await this.flushLogs(); // 2. Check file permissions and attempt to fix await this.checkAndFixPermissions(); // 3. Attempt to recreate transports await this.recreateTransports(); // Verify recovery was successful const status = await this.checkHealth(); return status.healthy; } catch (error) { this.logger.error('Logger recovery failed', error); return false; } } /** * Flushes any pending log writes */ private async flushLogs(): Promise<void> { // Implementation depends on logger transport type // For now, just a placeholder return Promise.resolve(); } /** * Checks and attempts to fix log file permissions */ private async checkAndFixPermissions(): Promise<void> { // Implementation depends on logger transport type // For now, just a placeholder return Promise.resolve(); } /** * Recreates logger transports */ private async recreateTransports(): Promise<void> { // Implementation depends on logger transport type // For now, just a placeholder return Promise.resolve(); } }