248 lines
5.8 KiB
JavaScript
248 lines
5.8 KiB
JavaScript
import { writeFileSync } from 'fs';
|
|
import { join } from 'path';
|
|
import chalk from 'chalk';
|
|
|
|
export class ErrorHandler {
|
|
constructor(logger) {
|
|
this.logger = logger;
|
|
this.errors = [];
|
|
this.warnings = [];
|
|
}
|
|
|
|
/**
|
|
* Handle and categorize errors
|
|
*/
|
|
handleError(error, context = {}) {
|
|
const errorInfo = {
|
|
timestamp: new Date().toISOString(),
|
|
message: error.message || 'Unknown error',
|
|
stack: error.stack,
|
|
context,
|
|
type: this.categorizeError(error)
|
|
};
|
|
|
|
this.errors.push(errorInfo);
|
|
this.logger.error(`[${errorInfo.type}] ${errorInfo.message}`);
|
|
|
|
if (context.critical) {
|
|
throw error;
|
|
}
|
|
|
|
return errorInfo;
|
|
}
|
|
|
|
/**
|
|
* Add a warning
|
|
*/
|
|
addWarning(message, context = {}) {
|
|
const warning = {
|
|
timestamp: new Date().toISOString(),
|
|
message,
|
|
context
|
|
};
|
|
|
|
this.warnings.push(warning);
|
|
this.logger.warning(message);
|
|
}
|
|
|
|
/**
|
|
* Categorize error types
|
|
*/
|
|
categorizeError(error) {
|
|
const message = error.message.toLowerCase();
|
|
|
|
if (
|
|
message.includes('command not found') ||
|
|
message.includes('not found')
|
|
) {
|
|
return 'DEPENDENCY_ERROR';
|
|
}
|
|
if (message.includes('permission') || message.includes('access denied')) {
|
|
return 'PERMISSION_ERROR';
|
|
}
|
|
if (message.includes('timeout')) {
|
|
return 'TIMEOUT_ERROR';
|
|
}
|
|
if (message.includes('api') || message.includes('rate limit')) {
|
|
return 'API_ERROR';
|
|
}
|
|
if (message.includes('json') || message.includes('parse')) {
|
|
return 'PARSE_ERROR';
|
|
}
|
|
if (message.includes('file') || message.includes('directory')) {
|
|
return 'FILE_ERROR';
|
|
}
|
|
|
|
return 'GENERAL_ERROR';
|
|
}
|
|
|
|
/**
|
|
* Get error summary
|
|
*/
|
|
getSummary() {
|
|
const errorsByType = {};
|
|
|
|
this.errors.forEach((error) => {
|
|
if (!errorsByType[error.type]) {
|
|
errorsByType[error.type] = [];
|
|
}
|
|
errorsByType[error.type].push(error);
|
|
});
|
|
|
|
return {
|
|
totalErrors: this.errors.length,
|
|
totalWarnings: this.warnings.length,
|
|
errorsByType,
|
|
criticalErrors: this.errors.filter((e) => e.context.critical),
|
|
recentErrors: this.errors.slice(-5)
|
|
};
|
|
}
|
|
|
|
/**
|
|
* Generate error report
|
|
*/
|
|
generateReport(outputPath) {
|
|
const summary = this.getSummary();
|
|
const report = {
|
|
generatedAt: new Date().toISOString(),
|
|
summary: {
|
|
totalErrors: summary.totalErrors,
|
|
totalWarnings: summary.totalWarnings,
|
|
errorTypes: Object.keys(summary.errorsByType)
|
|
},
|
|
errors: this.errors,
|
|
warnings: this.warnings,
|
|
recommendations: this.generateRecommendations(summary)
|
|
};
|
|
|
|
writeFileSync(outputPath, JSON.stringify(report, null, 2));
|
|
return report;
|
|
}
|
|
|
|
/**
|
|
* Generate recommendations based on errors
|
|
*/
|
|
generateRecommendations(summary) {
|
|
const recommendations = [];
|
|
|
|
if (summary.errorsByType.DEPENDENCY_ERROR) {
|
|
recommendations.push({
|
|
type: 'DEPENDENCY',
|
|
message: 'Install missing dependencies using npm install or check PATH',
|
|
errors: summary.errorsByType.DEPENDENCY_ERROR.length
|
|
});
|
|
}
|
|
|
|
if (summary.errorsByType.PERMISSION_ERROR) {
|
|
recommendations.push({
|
|
type: 'PERMISSION',
|
|
message: 'Check file permissions or run with appropriate privileges',
|
|
errors: summary.errorsByType.PERMISSION_ERROR.length
|
|
});
|
|
}
|
|
|
|
if (summary.errorsByType.API_ERROR) {
|
|
recommendations.push({
|
|
type: 'API',
|
|
message: 'Check API keys, rate limits, or network connectivity',
|
|
errors: summary.errorsByType.API_ERROR.length
|
|
});
|
|
}
|
|
|
|
if (summary.errorsByType.TIMEOUT_ERROR) {
|
|
recommendations.push({
|
|
type: 'TIMEOUT',
|
|
message:
|
|
'Consider increasing timeout values or optimizing slow operations',
|
|
errors: summary.errorsByType.TIMEOUT_ERROR.length
|
|
});
|
|
}
|
|
|
|
return recommendations;
|
|
}
|
|
|
|
/**
|
|
* Display error summary in console
|
|
*/
|
|
displaySummary() {
|
|
const summary = this.getSummary();
|
|
|
|
if (summary.totalErrors === 0 && summary.totalWarnings === 0) {
|
|
console.log(chalk.green('✅ No errors or warnings detected'));
|
|
return;
|
|
}
|
|
|
|
console.log(chalk.red.bold(`\n🚨 Error Summary:`));
|
|
console.log(chalk.red(` Total Errors: ${summary.totalErrors}`));
|
|
console.log(chalk.yellow(` Total Warnings: ${summary.totalWarnings}`));
|
|
|
|
if (summary.totalErrors > 0) {
|
|
console.log(chalk.red.bold('\n Error Types:'));
|
|
Object.entries(summary.errorsByType).forEach(([type, errors]) => {
|
|
console.log(chalk.red(` - ${type}: ${errors.length}`));
|
|
});
|
|
|
|
if (summary.criticalErrors.length > 0) {
|
|
console.log(
|
|
chalk.red.bold(
|
|
`\n ⚠️ Critical Errors: ${summary.criticalErrors.length}`
|
|
)
|
|
);
|
|
summary.criticalErrors.forEach((error) => {
|
|
console.log(chalk.red(` - ${error.message}`));
|
|
});
|
|
}
|
|
}
|
|
|
|
const recommendations = this.generateRecommendations(summary);
|
|
if (recommendations.length > 0) {
|
|
console.log(chalk.yellow.bold('\n💡 Recommendations:'));
|
|
recommendations.forEach((rec) => {
|
|
console.log(chalk.yellow(` - ${rec.message}`));
|
|
});
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Clear all errors and warnings
|
|
*/
|
|
clear() {
|
|
this.errors = [];
|
|
this.warnings = [];
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Global error handler for uncaught exceptions
|
|
*/
|
|
export function setupGlobalErrorHandlers(errorHandler, logger) {
|
|
process.on('uncaughtException', (error) => {
|
|
logger.error(`Uncaught Exception: ${error.message}`);
|
|
errorHandler.handleError(error, {
|
|
critical: true,
|
|
source: 'uncaughtException'
|
|
});
|
|
process.exit(1);
|
|
});
|
|
|
|
process.on('unhandledRejection', (reason, promise) => {
|
|
logger.error(`Unhandled Rejection at: ${promise}, reason: ${reason}`);
|
|
errorHandler.handleError(new Error(String(reason)), {
|
|
critical: false,
|
|
source: 'unhandledRejection'
|
|
});
|
|
});
|
|
|
|
process.on('SIGINT', () => {
|
|
logger.info('\nReceived SIGINT, shutting down gracefully...');
|
|
errorHandler.displaySummary();
|
|
process.exit(130);
|
|
});
|
|
|
|
process.on('SIGTERM', () => {
|
|
logger.info('\nReceived SIGTERM, shutting down...');
|
|
errorHandler.displaySummary();
|
|
process.exit(143);
|
|
});
|
|
}
|