UNPKG

mcp-adr-analysis-server

Version:

MCP server for analyzing Architectural Decision Records and project architecture

449 lines 14.5 kB
/** * Enhanced Logging System * * Provides comprehensive logging with structured error reporting, * diagnostic context, and actionable error messages. */ import { EnhancedError } from '../types/enhanced-errors.js'; /** * Enhanced Logger with comprehensive error reporting and diagnostics */ export class EnhancedLogger { config; logBuffer = []; maxBufferSize = 1000; constructor(config = {}) { this.config = { level: 'info', enableConsole: true, enableFile: false, enableStructuredLogging: true, enablePerformanceMetrics: true, maxFileSize: 10 * 1024 * 1024, // 10MB maxFiles: 5, ...config, }; } /** * Log debug information */ debug(message, component, context) { this.log('debug', message, component, context ? { context } : {}); } /** * Log informational messages */ info(message, component, context) { this.log('info', message, component, context ? { context } : {}); } /** * Log warning messages */ warn(message, component, context) { this.log('warn', message, component, context ? { context } : {}); } /** * Log error messages */ error(message, component, error, context) { const options = {}; if (error) options.error = error; if (context) options.context = context; this.log('error', message, component, options); } /** * Log critical errors */ critical(message, component, error, context) { const options = {}; if (error) options.error = error; if (context) options.context = context; this.log('critical', message, component, options); } /** * Log enhanced errors with full diagnostic information */ logEnhancedError(error) { const entry = { timestamp: new Date(), level: this.mapSeverityToLogLevel(error.severity), message: error.message, component: error.diagnostics.component, ...(error.diagnostics.operation && { operation: error.diagnostics.operation }), context: { code: error.code, severity: error.severity, recoverable: error.recoverable, retryable: error.retryable, suggestions: error.suggestions, ...error.diagnostics.context, }, error: error.toLogObject(), diagnostics: error.diagnostics, ...(error.diagnostics.performanceMetrics && { performanceMetrics: error.diagnostics.performanceMetrics, }), }; this.writeLogEntry(entry); } /** * Log operation start with performance tracking */ logOperationStart(operation, component, context) { const operationId = this.generateOperationId(); this.log('info', `Operation started: ${operation}`, component, { context: { operationId, ...context }, operation, }); return operationId; } /** * Log operation completion with performance metrics */ logOperationComplete(operationId, operation, component, duration, context) { this.log('info', `Operation completed: ${operation}`, component, { context: { operationId, duration, ...context }, operation, performanceMetrics: { duration }, }); } /** * Log operation failure with recovery suggestions */ logOperationFailure(operationId, operation, component, error, duration, context) { this.log('error', `Operation failed: ${operation}`, component, { error, context: { operationId, duration, ...context }, operation, performanceMetrics: { duration }, }); } /** * Log performance metrics */ logPerformanceMetrics(component, operation, metrics) { this.log('info', `Performance metrics for ${operation}`, component, { operation, performanceMetrics: metrics, }); } /** * Get recent log entries for debugging */ getRecentLogs(count = 100) { return this.logBuffer.slice(-count); } /** * Get logs filtered by level and component */ getFilteredLogs(filters) { return this.logBuffer.filter(entry => { if (filters.level && !this.levelMeetsFilter(filters.level, entry.level)) { return false; } if (filters.component && entry.component !== filters.component) { return false; } if (filters.operation && entry.operation !== filters.operation) { return false; } if (filters.since && entry.timestamp < filters.since) { return false; } return true; }); } /** * Clear log buffer */ clearLogs() { this.logBuffer = []; } /** * Core logging method */ log(level, message, component, options = {}) { if (!this.isLevelEnabled(level)) { return; } const entry = { timestamp: new Date(), level, message, component, ...(options.operation && { operation: options.operation }), ...(options.context && { context: options.context }), ...(options.error && { error: this.serializeError(options.error) }), ...((this.config.enablePerformanceMetrics || options.performanceMetrics) && { performanceMetrics: this.config.enablePerformanceMetrics ? { memoryUsage: this.getMemoryUsage(), ...options.performanceMetrics, } : options.performanceMetrics, }), }; this.writeLogEntry(entry); } /** * Write log entry to configured outputs */ writeLogEntry(entry) { // Add to buffer this.logBuffer.push(entry); if (this.logBuffer.length > this.maxBufferSize) { this.logBuffer.shift(); } // Console output if (this.config.enableConsole) { this.writeToConsole(entry); } // File output (if configured) if (this.config.enableFile && this.config.filePath) { this.writeToFile(entry); } } /** * Write to console with appropriate formatting */ writeToConsole(entry) { const timestamp = entry.timestamp.toISOString(); const prefix = `[${timestamp}] [${entry.level.toUpperCase()}] [${entry.component}]`; if (this.config.enableStructuredLogging) { const logData = { ...entry, timestamp: timestamp, }; switch (entry.level) { case 'critical': case 'error': console.error(prefix, entry.message, logData); break; case 'warn': console.warn(prefix, entry.message, logData); break; case 'debug': console.debug(prefix, entry.message, logData); break; default: console.log(prefix, entry.message, logData); } } else { const message = `${prefix} ${entry.message}`; switch (entry.level) { case 'critical': case 'error': console.error(message); if (entry.error) { console.error('Error details:', entry.error); } break; case 'warn': console.warn(message); break; case 'debug': console.debug(message); break; default: console.log(message); } } } /** * Write to file (placeholder - would need file system implementation) */ writeToFile(_entry) { // File logging would be implemented here // For now, this is a placeholder as file operations depend on environment } /** * Check if log level is enabled */ isLevelEnabled(level, entryLevel) { const levels = ['debug', 'info', 'warn', 'error', 'critical']; const configLevelIndex = levels.indexOf(this.config.level); const checkLevelIndex = levels.indexOf(entryLevel || level); return checkLevelIndex >= configLevelIndex; } /** * Check if a specific level meets the filter criteria */ levelMeetsFilter(filterLevel, entryLevel) { const levels = ['debug', 'info', 'warn', 'error', 'critical']; const filterLevelIndex = levels.indexOf(filterLevel); const entryLevelIndex = levels.indexOf(entryLevel); return entryLevelIndex >= filterLevelIndex; } /** * Map error severity to log level */ mapSeverityToLogLevel(severity) { switch (severity) { case 'critical': return 'critical'; case 'high': return 'error'; case 'medium': return 'warn'; case 'low': return 'info'; default: return 'info'; } } /** * Serialize error for logging */ serializeError(error) { if (error instanceof EnhancedError) { return error.toLogObject(); } return { name: error.name, message: error.message, stack: error.stack, cause: error.cause ? this.serializeError(error.cause) : undefined, }; } /** * Get current memory usage */ getMemoryUsage() { if (typeof process !== 'undefined' && process.memoryUsage) { return Math.round(process.memoryUsage().heapUsed / 1024 / 1024); // MB } return 0; } /** * Generate unique operation ID */ generateOperationId() { return `op_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`; } } /** * Global logger instance */ export const logger = new EnhancedLogger(); /** * Create component-specific logger */ export function createComponentLogger(component, config) { return new ComponentLogger(component, config); } /** * Component-specific logger wrapper */ export class ComponentLogger { logger; component; constructor(component, config) { this.component = component; this.logger = config ? new EnhancedLogger(config) : logger; // Use global logger if no config } debug(message, context) { this.logger.debug(message, this.component, context); } info(message, context) { this.logger.info(message, this.component, context); } warn(message, context) { this.logger.warn(message, this.component, context); } error(message, error, context) { this.logger.error(message, this.component, error, context); } critical(message, error, context) { this.logger.critical(message, this.component, error, context); } logEnhancedError(error) { this.logger.logEnhancedError(error); } logOperationStart(operation, context) { return this.logger.logOperationStart(operation, this.component, context); } logOperationComplete(operationId, operation, duration, context) { this.logger.logOperationComplete(operationId, operation, this.component, duration, context); } logOperationFailure(operationId, operation, error, duration, context) { this.logger.logOperationFailure(operationId, operation, this.component, error, duration, context); } logPerformanceMetrics(operation, metrics) { this.logger.logPerformanceMetrics(this.component, operation, metrics); } } /** * Error recovery utilities */ export class ErrorRecoveryManager { logger; recoveryStrategies = new Map(); constructor(logger) { this.logger = logger || new EnhancedLogger(); } /** * Register recovery strategy for specific error codes */ registerRecoveryStrategy(errorCode, strategy) { this.recoveryStrategies.set(errorCode, strategy); } /** * Attempt to recover from an enhanced error */ async attemptRecovery(error) { if (!error.recoverable) { this.logger.warn('Error is not recoverable', 'ErrorRecoveryManager', { errorCode: error.code, message: error.message, }); return false; } const strategy = this.recoveryStrategies.get(error.code); if (!strategy) { this.logger.warn('No recovery strategy found', 'ErrorRecoveryManager', { errorCode: error.code, message: error.message, }); return false; } try { this.logger.info('Attempting error recovery', 'ErrorRecoveryManager', { errorCode: error.code, message: error.message, }); const recovered = await strategy(error); if (recovered) { this.logger.info('Error recovery successful', 'ErrorRecoveryManager', { errorCode: error.code, message: error.message, }); } else { this.logger.warn('Error recovery failed', 'ErrorRecoveryManager', { errorCode: error.code, message: error.message, }); } return recovered; } catch (recoveryError) { this.logger.error('Error recovery threw exception', 'ErrorRecoveryManager', recoveryError, { originalErrorCode: error.code, originalMessage: error.message, }); return false; } } /** * Get recovery suggestions for an error */ getRecoverySuggestions(error) { return error.suggestions.map(s => `${s.action}: ${s.description}`); } } //# sourceMappingURL=enhanced-logging.js.map