@dharshansr/gitgenius
Version:
AI-powered commit message generator with enhanced features
198 lines • 6.5 kB
JavaScript
/**
* Error tracking system with comprehensive error monitoring
*/
import { logger } from './Logger.js';
import { ConfigManager } from '../core/ConfigManager.js';
import { writeFileSync, existsSync, mkdirSync, readFileSync } from 'fs';
import { join } from 'path';
import { homedir } from 'os';
export class ErrorTracker {
constructor() {
this.errors = new Map();
this.configManager = new ConfigManager();
const errorDir = join(homedir(), '.gitgenius', 'errors');
if (!existsSync(errorDir)) {
mkdirSync(errorDir, { recursive: true });
}
this.errorLogPath = join(errorDir, 'errors.json');
this.loadErrors();
}
static getInstance() {
if (!ErrorTracker.instance) {
ErrorTracker.instance = new ErrorTracker();
}
return ErrorTracker.instance;
}
/**
* Load errors from persistent storage
*/
loadErrors() {
try {
if (existsSync(this.errorLogPath)) {
const content = readFileSync(this.errorLogPath, 'utf-8');
const errorArray = JSON.parse(content);
errorArray.forEach(error => {
this.errors.set(error.id, error);
});
}
}
catch (error) {
logger.warn('ErrorTracker', 'Failed to load error history', { error });
}
}
/**
* Save errors to persistent storage
*/
saveErrors() {
try {
const errorArray = Array.from(this.errors.values());
writeFileSync(this.errorLogPath, JSON.stringify(errorArray, null, 2));
}
catch (error) {
logger.warn('ErrorTracker', 'Failed to save error history', { error });
}
}
/**
* Generate error ID from message and category
*/
generateErrorId(category, message) {
const hash = Buffer.from(`${category}:${message}`).toString('base64').substring(0, 16);
return hash;
}
/**
* Track an error
*/
trackError(category, message, error, context) {
const id = this.generateErrorId(category, message);
logger.error(category, message, error, context);
const existingError = this.errors.get(id);
if (existingError) {
existingError.occurrences++;
existingError.timestamp = new Date().toISOString();
existingError.resolved = false;
if (context) {
existingError.context = context;
}
}
else {
const errorRecord = {
id,
timestamp: new Date().toISOString(),
category,
message,
stack: error?.stack,
context,
resolved: false,
occurrences: 1
};
this.errors.set(id, errorRecord);
}
this.saveErrors();
}
/**
* Mark error as resolved
*/
resolveError(errorId) {
const error = this.errors.get(errorId);
if (error) {
error.resolved = true;
this.saveErrors();
logger.info('ErrorTracker', `Error resolved: ${errorId}`);
return true;
}
return false;
}
/**
* Get all errors
*/
getAllErrors(includeResolved = false) {
const errors = Array.from(this.errors.values());
return includeResolved ? errors : errors.filter(e => !e.resolved);
}
/**
* Get errors by category
*/
getErrorsByCategory(category, includeResolved = false) {
return this.getAllErrors(includeResolved).filter(e => e.category === category);
}
/**
* Get recent errors
*/
getRecentErrors(count = 10, includeResolved = false) {
return this.getAllErrors(includeResolved)
.sort((a, b) => new Date(b.timestamp).getTime() - new Date(a.timestamp).getTime())
.slice(0, count);
}
/**
* Get error statistics
*/
getErrorStats() {
const allErrors = this.getAllErrors(true);
const unresolvedErrors = allErrors.filter(e => !e.resolved);
const errorsByCategory = {};
const errorsByDay = {};
const errorCounts = new Map();
allErrors.forEach(error => {
// By category
errorsByCategory[error.category] = (errorsByCategory[error.category] || 0) + 1;
// By day
const day = error.timestamp.split('T')[0];
errorsByDay[day] = (errorsByDay[day] || 0) + 1;
// Count occurrences
const current = errorCounts.get(error.message) || 0;
errorCounts.set(error.message, current + error.occurrences);
});
// Get most common errors
const mostCommonErrors = Array.from(errorCounts.entries())
.map(([message, count]) => ({ message, count }))
.sort((a, b) => b.count - a.count)
.slice(0, 10);
return {
totalErrors: allErrors.length,
unresolvedErrors: unresolvedErrors.length,
errorsByCategory,
errorsByDay,
mostCommonErrors
};
}
/**
* Clear resolved errors
*/
clearResolvedErrors() {
const beforeCount = this.errors.size;
const unresolvedErrors = Array.from(this.errors.values()).filter(e => !e.resolved);
this.errors.clear();
unresolvedErrors.forEach(error => {
this.errors.set(error.id, error);
});
this.saveErrors();
const clearedCount = beforeCount - this.errors.size;
logger.info('ErrorTracker', `Cleared ${clearedCount} resolved errors`);
return clearedCount;
}
/**
* Clear all errors
*/
clearAllErrors() {
this.errors.clear();
this.saveErrors();
logger.info('ErrorTracker', 'All errors cleared');
}
/**
* Export errors to file
*/
exportErrors(filePath) {
try {
const errors = this.getAllErrors(true);
writeFileSync(filePath, JSON.stringify(errors, null, 2));
logger.info('ErrorTracker', `Errors exported to ${filePath}`);
}
catch (error) {
logger.error('ErrorTracker', `Failed to export errors: ${error}`);
throw error;
}
}
}
// Export singleton instance
export const errorTracker = ErrorTracker.getInstance();
//# sourceMappingURL=ErrorTracker.js.map