Files
Comfyui-LayerForge/js/ErrorHandler.js
Dariusz L 98d5b18422 Remove redundant comments and clean up logging code
This commit removes unnecessary and redundant comments from multiple JavaScript modules, streamlining the code and improving readability. No functional changes were made; only comment cleanup and minor formatting adjustments.
2025-06-26 05:03:17 +02:00

351 lines
11 KiB
JavaScript

/**
* ErrorHandler - Centralna obsługa błędów
* Eliminuje powtarzalne wzorce obsługi błędów w całym projekcie
*/
import {createModuleLogger} from "./utils/LoggerUtils.js";
const log = createModuleLogger('ErrorHandler');
/**
* Typy błędów w aplikacji
*/
export const ErrorTypes = {
VALIDATION: 'VALIDATION_ERROR',
NETWORK: 'NETWORK_ERROR',
FILE_IO: 'FILE_IO_ERROR',
CANVAS: 'CANVAS_ERROR',
IMAGE_PROCESSING: 'IMAGE_PROCESSING_ERROR',
STATE_MANAGEMENT: 'STATE_MANAGEMENT_ERROR',
USER_INPUT: 'USER_INPUT_ERROR',
SYSTEM: 'SYSTEM_ERROR'
};
/**
* Klasa błędu aplikacji z dodatkowymi informacjami
*/
export class AppError extends Error {
constructor(message, type = ErrorTypes.SYSTEM, details = null, originalError = null) {
super(message);
this.name = 'AppError';
this.type = type;
this.details = details;
this.originalError = originalError;
this.timestamp = new Date().toISOString();
if (Error.captureStackTrace) {
Error.captureStackTrace(this, AppError);
}
}
}
/**
* Handler błędów z automatycznym logowaniem i kategoryzacją
*/
export class ErrorHandler {
constructor() {
this.errorCounts = new Map();
this.errorHistory = [];
this.maxHistorySize = 100;
}
/**
* Obsługuje błąd z automatycznym logowaniem
* @param {Error|AppError} error - Błąd do obsłużenia
* @param {string} context - Kontekst wystąpienia błędu
* @param {Object} additionalInfo - Dodatkowe informacje
* @returns {AppError} Znormalizowany błąd
*/
handle(error, context = 'Unknown', additionalInfo = {}) {
const normalizedError = this.normalizeError(error, context, additionalInfo);
this.logError(normalizedError, context);
this.recordError(normalizedError);
this.incrementErrorCount(normalizedError.type);
return normalizedError;
}
/**
* Normalizuje błąd do standardowego formatu
* @param {Error|AppError|string} error - Błąd do znormalizowania
* @param {string} context - Kontekst
* @param {Object} additionalInfo - Dodatkowe informacje
* @returns {AppError} Znormalizowany błąd
*/
normalizeError(error, context, additionalInfo) {
if (error instanceof AppError) {
return error;
}
if (error instanceof Error) {
const type = this.categorizeError(error, context);
return new AppError(
error.message,
type,
{ context, ...additionalInfo },
error
);
}
if (typeof error === 'string') {
return new AppError(
error,
ErrorTypes.SYSTEM,
{ context, ...additionalInfo }
);
}
return new AppError(
'Unknown error occurred',
ErrorTypes.SYSTEM,
{ context, originalError: error, ...additionalInfo }
);
}
/**
* Kategoryzuje błąd na podstawie wiadomości i kontekstu
* @param {Error} error - Błąd do skategoryzowania
* @param {string} context - Kontekst
* @returns {string} Typ błędu
*/
categorizeError(error, context) {
const message = error.message.toLowerCase();
if (message.includes('fetch') || message.includes('network') ||
message.includes('connection') || message.includes('timeout')) {
return ErrorTypes.NETWORK;
}
if (message.includes('file') || message.includes('read') ||
message.includes('write') || message.includes('path')) {
return ErrorTypes.FILE_IO;
}
if (message.includes('invalid') || message.includes('required') ||
message.includes('validation') || message.includes('format')) {
return ErrorTypes.VALIDATION;
}
if (message.includes('image') || message.includes('canvas') ||
message.includes('blob') || message.includes('tensor')) {
return ErrorTypes.IMAGE_PROCESSING;
}
if (message.includes('state') || message.includes('cache') ||
message.includes('storage')) {
return ErrorTypes.STATE_MANAGEMENT;
}
if (context.toLowerCase().includes('canvas')) {
return ErrorTypes.CANVAS;
}
return ErrorTypes.SYSTEM;
}
/**
* Loguje błąd z odpowiednim poziomem
* @param {AppError} error - Błąd do zalogowania
* @param {string} context - Kontekst
*/
logError(error, context) {
const logMessage = `[${error.type}] ${error.message}`;
const logDetails = {
context,
timestamp: error.timestamp,
details: error.details,
stack: error.stack
};
switch (error.type) {
case ErrorTypes.VALIDATION:
case ErrorTypes.USER_INPUT:
log.warn(logMessage, logDetails);
break;
case ErrorTypes.NETWORK:
log.error(logMessage, logDetails);
break;
default:
log.error(logMessage, logDetails);
}
}
/**
* Zapisuje błąd w historii
* @param {AppError} error - Błąd do zapisania
*/
recordError(error) {
this.errorHistory.push({
timestamp: error.timestamp,
type: error.type,
message: error.message,
context: error.details?.context
});
if (this.errorHistory.length > this.maxHistorySize) {
this.errorHistory.shift();
}
}
/**
* Zwiększa licznik błędów dla danego typu
* @param {string} errorType - Typ błędu
*/
incrementErrorCount(errorType) {
const current = this.errorCounts.get(errorType) || 0;
this.errorCounts.set(errorType, current + 1);
}
/**
* Zwraca statystyki błędów
* @returns {Object} Statystyki błędów
*/
getErrorStats() {
return {
totalErrors: this.errorHistory.length,
errorCounts: Object.fromEntries(this.errorCounts),
recentErrors: this.errorHistory.slice(-10),
errorsByType: this.groupErrorsByType()
};
}
/**
* Grupuje błędy według typu
* @returns {Object} Błędy pogrupowane według typu
*/
groupErrorsByType() {
const grouped = {};
this.errorHistory.forEach(error => {
if (!grouped[error.type]) {
grouped[error.type] = [];
}
grouped[error.type].push(error);
});
return grouped;
}
/**
* Czyści historię błędów
*/
clearHistory() {
this.errorHistory = [];
this.errorCounts.clear();
log.info('Error history cleared');
}
}
const errorHandler = new ErrorHandler();
/**
* Wrapper funkcji z automatyczną obsługą błędów
* @param {Function} fn - Funkcja do opakowania
* @param {string} context - Kontekst wykonania
* @returns {Function} Opakowana funkcja
*/
export function withErrorHandling(fn, context) {
return async function(...args) {
try {
return await fn.apply(this, args);
} catch (error) {
const handledError = errorHandler.handle(error, context, {
functionName: fn.name,
arguments: args.length
});
throw handledError;
}
};
}
/**
* Decorator dla metod klasy z automatyczną obsługą błędów
* @param {string} context - Kontekst wykonania
*/
export function handleErrors(context) {
return function(target, propertyKey, descriptor) {
const originalMethod = descriptor.value;
descriptor.value = async function(...args) {
try {
return await originalMethod.apply(this, args);
} catch (error) {
const handledError = errorHandler.handle(error, `${context}.${propertyKey}`, {
className: target.constructor.name,
methodName: propertyKey,
arguments: args.length
});
throw handledError;
}
};
return descriptor;
};
}
/**
* Funkcja pomocnicza do tworzenia błędów walidacji
* @param {string} message - Wiadomość błędu
* @param {Object} details - Szczegóły walidacji
* @returns {AppError} Błąd walidacji
*/
export function createValidationError(message, details = {}) {
return new AppError(message, ErrorTypes.VALIDATION, details);
}
/**
* Funkcja pomocnicza do tworzenia błędów sieciowych
* @param {string} message - Wiadomość błędu
* @param {Object} details - Szczegóły sieci
* @returns {AppError} Błąd sieciowy
*/
export function createNetworkError(message, details = {}) {
return new AppError(message, ErrorTypes.NETWORK, details);
}
/**
* Funkcja pomocnicza do tworzenia błędów plików
* @param {string} message - Wiadomość błędu
* @param {Object} details - Szczegóły pliku
* @returns {AppError} Błąd pliku
*/
export function createFileError(message, details = {}) {
return new AppError(message, ErrorTypes.FILE_IO, details);
}
/**
* Funkcja pomocnicza do bezpiecznego wykonania operacji
* @param {Function} operation - Operacja do wykonania
* @param {*} fallbackValue - Wartość fallback w przypadku błędu
* @param {string} context - Kontekst operacji
* @returns {*} Wynik operacji lub wartość fallback
*/
export async function safeExecute(operation, fallbackValue = null, context = 'SafeExecute') {
try {
return await operation();
} catch (error) {
errorHandler.handle(error, context);
return fallbackValue;
}
}
/**
* Funkcja do retry operacji z exponential backoff
* @param {Function} operation - Operacja do powtórzenia
* @param {number} maxRetries - Maksymalna liczba prób
* @param {number} baseDelay - Podstawowe opóźnienie w ms
* @param {string} context - Kontekst operacji
* @returns {*} Wynik operacji
*/
export async function retryWithBackoff(operation, maxRetries = 3, baseDelay = 1000, context = 'RetryOperation') {
let lastError;
for (let attempt = 0; attempt <= maxRetries; attempt++) {
try {
return await operation();
} catch (error) {
lastError = error;
if (attempt === maxRetries) {
break;
}
const delay = baseDelay * Math.pow(2, attempt);
log.warn(`Attempt ${attempt + 1} failed, retrying in ${delay}ms`, { error: error.message, context });
await new Promise(resolve => setTimeout(resolve, delay));
}
}
throw errorHandler.handle(lastError, context, { attempts: maxRetries + 1 });
}
export { errorHandler };
export default errorHandler;