|
@@ -6,48 +6,49 @@
|
|
|
* strategies, and audit trail functionality.
|
|
|
*/
|
|
|
|
|
|
-import { EventEmitter } from 'events';
|
|
|
-import { CredentialManagerError, ErrorType } from '../../types/credential.js';
|
|
|
+import { EventEmitter } from 'events'
|
|
|
+
|
|
|
+import { CredentialManagerError, ErrorType } from '../../types/credential.js'
|
|
|
|
|
|
// ============================================================================
|
|
|
// Types and Interfaces
|
|
|
// ============================================================================
|
|
|
|
|
|
export interface LogEntry {
|
|
|
- timestamp: Date;
|
|
|
- level: LogLevel;
|
|
|
- message: string;
|
|
|
- component: string;
|
|
|
- operation?: string;
|
|
|
- accountId?: string;
|
|
|
- platform?: string;
|
|
|
- error?: Error;
|
|
|
- metadata?: Record<string, any>;
|
|
|
- correlationId?: string;
|
|
|
+ timestamp: Date
|
|
|
+ level: LogLevel
|
|
|
+ message: string
|
|
|
+ component: string
|
|
|
+ operation?: string
|
|
|
+ accountId?: string
|
|
|
+ platform?: string
|
|
|
+ error?: Error
|
|
|
+ metadata?: Record<string, any>
|
|
|
+ correlationId?: string
|
|
|
}
|
|
|
|
|
|
export interface ErrorContext {
|
|
|
- component: string;
|
|
|
- operation: string;
|
|
|
- accountId?: string;
|
|
|
- platform?: string;
|
|
|
- attempt?: number;
|
|
|
- maxRetries?: number;
|
|
|
- metadata?: Record<string, any>;
|
|
|
- correlationId?: string;
|
|
|
+ component: string
|
|
|
+ operation: string
|
|
|
+ accountId?: string
|
|
|
+ platform?: string
|
|
|
+ attempt?: number
|
|
|
+ maxRetries?: number
|
|
|
+ metadata?: Record<string, any>
|
|
|
+ correlationId?: string
|
|
|
}
|
|
|
|
|
|
export interface RecoveryStrategy {
|
|
|
- canHandle(error: Error, context: ErrorContext): boolean;
|
|
|
- handle(error: Error, context: ErrorContext): Promise<RecoveryResult>;
|
|
|
+ canHandle(error: Error, context: ErrorContext): boolean
|
|
|
+ handle(error: Error, context: ErrorContext): Promise<RecoveryResult>
|
|
|
}
|
|
|
|
|
|
export interface RecoveryResult {
|
|
|
- recovered: boolean;
|
|
|
- shouldRetry: boolean;
|
|
|
- retryDelay?: number;
|
|
|
- newError?: Error;
|
|
|
- metadata?: Record<string, any>;
|
|
|
+ recovered: boolean
|
|
|
+ shouldRetry: boolean
|
|
|
+ retryDelay?: number
|
|
|
+ newError?: Error
|
|
|
+ metadata?: Record<string, any>
|
|
|
}
|
|
|
|
|
|
export enum LogLevel {
|
|
@@ -55,25 +56,25 @@ export enum LogLevel {
|
|
|
INFO = 'info',
|
|
|
WARN = 'warn',
|
|
|
ERROR = 'error',
|
|
|
- FATAL = 'fatal'
|
|
|
+ FATAL = 'fatal',
|
|
|
}
|
|
|
|
|
|
export enum ErrorSeverity {
|
|
|
LOW = 'low',
|
|
|
MEDIUM = 'medium',
|
|
|
HIGH = 'high',
|
|
|
- CRITICAL = 'critical'
|
|
|
+ CRITICAL = 'critical',
|
|
|
}
|
|
|
|
|
|
export interface ErrorHandlerOptions {
|
|
|
- enableLogging?: boolean;
|
|
|
- logLevel?: LogLevel;
|
|
|
- enableConsoleOutput?: boolean;
|
|
|
- enableErrorRecovery?: boolean;
|
|
|
- maxRetries?: number;
|
|
|
- retryDelay?: number;
|
|
|
- enableAuditTrail?: boolean;
|
|
|
- enableCorrelationTracking?: boolean;
|
|
|
+ enableLogging?: boolean
|
|
|
+ logLevel?: LogLevel
|
|
|
+ enableConsoleOutput?: boolean
|
|
|
+ enableErrorRecovery?: boolean
|
|
|
+ maxRetries?: number
|
|
|
+ retryDelay?: number
|
|
|
+ enableAuditTrail?: boolean
|
|
|
+ enableCorrelationTracking?: boolean
|
|
|
}
|
|
|
|
|
|
// ============================================================================
|
|
@@ -81,14 +82,14 @@ export interface ErrorHandlerOptions {
|
|
|
// ============================================================================
|
|
|
|
|
|
export class ErrorHandler extends EventEmitter {
|
|
|
- private options: Required<ErrorHandlerOptions>;
|
|
|
- private logEntries: LogEntry[] = [];
|
|
|
- private errorCounts = new Map<string, number>();
|
|
|
- private recoveryStrategies: RecoveryStrategy[] = [];
|
|
|
- private correlationCounter = 0;
|
|
|
+ private options: Required<ErrorHandlerOptions>
|
|
|
+ private logEntries: LogEntry[] = []
|
|
|
+ private errorCounts = new Map<string, number>()
|
|
|
+ private recoveryStrategies: RecoveryStrategy[] = []
|
|
|
+ private correlationCounter = 0
|
|
|
|
|
|
constructor(options: ErrorHandlerOptions = {}) {
|
|
|
- super();
|
|
|
+ super()
|
|
|
|
|
|
this.options = {
|
|
|
enableLogging: options.enableLogging ?? true,
|
|
@@ -98,34 +99,34 @@ export class ErrorHandler extends EventEmitter {
|
|
|
maxRetries: options.maxRetries ?? 3,
|
|
|
retryDelay: options.retryDelay ?? 1000,
|
|
|
enableAuditTrail: options.enableAuditTrail ?? true,
|
|
|
- enableCorrelationTracking: options.enableCorrelationTracking ?? true
|
|
|
- };
|
|
|
+ enableCorrelationTracking: options.enableCorrelationTracking ?? true,
|
|
|
+ }
|
|
|
|
|
|
- this.initializeDefaultRecoveryStrategies();
|
|
|
+ this.initializeDefaultRecoveryStrategies()
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
* Handle an error with context and recovery attempts
|
|
|
*/
|
|
|
async handleError(error: Error, context: ErrorContext): Promise<RecoveryResult> {
|
|
|
- const correlationId = context.correlationId || this.generateCorrelationId();
|
|
|
- const enrichedContext = { ...context, correlationId };
|
|
|
+ const correlationId = context.correlationId || this.generateCorrelationId()
|
|
|
+ const enrichedContext = { ...context, correlationId }
|
|
|
|
|
|
// Log the error
|
|
|
- this.logError(error, enrichedContext);
|
|
|
+ this.logError(error, enrichedContext)
|
|
|
|
|
|
// Track error occurrence
|
|
|
- this.trackError(error, enrichedContext);
|
|
|
+ this.trackError(error, enrichedContext)
|
|
|
|
|
|
// Attempt recovery if enabled
|
|
|
if (this.options.enableErrorRecovery) {
|
|
|
- return await this.attemptRecovery(error, enrichedContext);
|
|
|
+ return await this.attemptRecovery(error, enrichedContext)
|
|
|
}
|
|
|
|
|
|
return {
|
|
|
recovered: false,
|
|
|
- shouldRetry: false
|
|
|
- };
|
|
|
+ shouldRetry: false,
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
/**
|
|
@@ -133,7 +134,7 @@ export class ErrorHandler extends EventEmitter {
|
|
|
*/
|
|
|
log(level: LogLevel, message: string, component: string, metadata?: Record<string, any>): void {
|
|
|
if (!this.shouldLog(level)) {
|
|
|
- return;
|
|
|
+ return
|
|
|
}
|
|
|
|
|
|
const entry: LogEntry = {
|
|
@@ -142,31 +143,31 @@ export class ErrorHandler extends EventEmitter {
|
|
|
message,
|
|
|
component,
|
|
|
metadata,
|
|
|
- correlationId: metadata?.correlationId
|
|
|
- };
|
|
|
+ correlationId: metadata?.correlationId,
|
|
|
+ }
|
|
|
|
|
|
- this.addLogEntry(entry);
|
|
|
+ this.addLogEntry(entry)
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
* Log debug messages
|
|
|
*/
|
|
|
debug(message: string, component: string, metadata?: Record<string, any>): void {
|
|
|
- this.log(LogLevel.DEBUG, message, component, metadata);
|
|
|
+ this.log(LogLevel.DEBUG, message, component, metadata)
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
* Log info messages
|
|
|
*/
|
|
|
info(message: string, component: string, metadata?: Record<string, any>): void {
|
|
|
- this.log(LogLevel.INFO, message, component, metadata);
|
|
|
+ this.log(LogLevel.INFO, message, component, metadata)
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
* Log warning messages
|
|
|
*/
|
|
|
warn(message: string, component: string, metadata?: Record<string, any>): void {
|
|
|
- this.log(LogLevel.WARN, message, component, metadata);
|
|
|
+ this.log(LogLevel.WARN, message, component, metadata)
|
|
|
}
|
|
|
|
|
|
/**
|
|
@@ -180,10 +181,10 @@ export class ErrorHandler extends EventEmitter {
|
|
|
component,
|
|
|
error,
|
|
|
metadata,
|
|
|
- correlationId: metadata?.correlationId
|
|
|
- };
|
|
|
+ correlationId: metadata?.correlationId,
|
|
|
+ }
|
|
|
|
|
|
- this.addLogEntry(entry);
|
|
|
+ this.addLogEntry(entry)
|
|
|
}
|
|
|
|
|
|
/**
|
|
@@ -197,44 +198,42 @@ export class ErrorHandler extends EventEmitter {
|
|
|
component,
|
|
|
error,
|
|
|
metadata,
|
|
|
- correlationId: metadata?.correlationId
|
|
|
- };
|
|
|
+ correlationId: metadata?.correlationId,
|
|
|
+ }
|
|
|
|
|
|
- this.addLogEntry(entry);
|
|
|
+ this.addLogEntry(entry)
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
* Register a custom recovery strategy
|
|
|
*/
|
|
|
registerRecoveryStrategy(strategy: RecoveryStrategy): void {
|
|
|
- this.recoveryStrategies.push(strategy);
|
|
|
+ this.recoveryStrategies.push(strategy)
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
* Get error statistics
|
|
|
*/
|
|
|
getErrorStats(): Record<string, any> {
|
|
|
- const errorsByType = new Map<string, number>();
|
|
|
- const errorsByComponent = new Map<string, number>();
|
|
|
- const recentErrors: LogEntry[] = [];
|
|
|
+ const errorsByType = new Map<string, number>()
|
|
|
+ const errorsByComponent = new Map<string, number>()
|
|
|
+ const recentErrors: LogEntry[] = []
|
|
|
|
|
|
this.logEntries
|
|
|
.filter(entry => entry.level === LogLevel.ERROR || entry.level === LogLevel.FATAL)
|
|
|
.forEach(entry => {
|
|
|
// Count by error type
|
|
|
- const errorType = entry.error instanceof CredentialManagerError
|
|
|
- ? entry.error.type
|
|
|
- : 'unknown';
|
|
|
- errorsByType.set(errorType, (errorsByType.get(errorType) || 0) + 1);
|
|
|
+ const errorType = entry.error instanceof CredentialManagerError ? entry.error.type : 'unknown'
|
|
|
+ errorsByType.set(errorType, (errorsByType.get(errorType) || 0) + 1)
|
|
|
|
|
|
// Count by component
|
|
|
- errorsByComponent.set(entry.component, (errorsByComponent.get(entry.component) || 0) + 1);
|
|
|
+ errorsByComponent.set(entry.component, (errorsByComponent.get(entry.component) || 0) + 1)
|
|
|
|
|
|
// Collect recent errors (last 100)
|
|
|
if (recentErrors.length < 100) {
|
|
|
- recentErrors.push(entry);
|
|
|
+ recentErrors.push(entry)
|
|
|
}
|
|
|
- });
|
|
|
+ })
|
|
|
|
|
|
return {
|
|
|
totalErrors: this.logEntries.filter(e => e.level === LogLevel.ERROR || e.level === LogLevel.FATAL).length,
|
|
@@ -245,9 +244,9 @@ export class ErrorHandler extends EventEmitter {
|
|
|
component: entry.component,
|
|
|
message: entry.message,
|
|
|
errorType: entry.error instanceof CredentialManagerError ? entry.error.type : 'unknown',
|
|
|
- correlationId: entry.correlationId
|
|
|
- }))
|
|
|
- };
|
|
|
+ correlationId: entry.correlationId,
|
|
|
+ })),
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
/**
|
|
@@ -255,33 +254,33 @@ export class ErrorHandler extends EventEmitter {
|
|
|
*/
|
|
|
getAuditTrail(filter?: { component?: string; level?: LogLevel; since?: Date }): LogEntry[] {
|
|
|
if (!this.options.enableAuditTrail) {
|
|
|
- return [];
|
|
|
+ return []
|
|
|
}
|
|
|
|
|
|
- let entries = [...this.logEntries];
|
|
|
+ let entries = [...this.logEntries]
|
|
|
|
|
|
if (filter) {
|
|
|
if (filter.component) {
|
|
|
- entries = entries.filter(e => e.component === filter.component);
|
|
|
+ entries = entries.filter(e => e.component === filter.component)
|
|
|
}
|
|
|
if (filter.level) {
|
|
|
- entries = entries.filter(e => e.level === filter.level);
|
|
|
+ entries = entries.filter(e => e.level === filter.level)
|
|
|
}
|
|
|
if (filter.since) {
|
|
|
- entries = entries.filter(e => e.timestamp >= filter.since);
|
|
|
+ entries = entries.filter(e => e.timestamp >= filter.since)
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- return entries.sort((a, b) => b.timestamp.getTime() - a.timestamp.getTime());
|
|
|
+ return entries.sort((a, b) => b.timestamp.getTime() - a.timestamp.getTime())
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
* Clear logs older than specified date
|
|
|
*/
|
|
|
clearOldLogs(before: Date): number {
|
|
|
- const initialCount = this.logEntries.length;
|
|
|
- this.logEntries = this.logEntries.filter(entry => entry.timestamp >= before);
|
|
|
- return initialCount - this.logEntries.length;
|
|
|
+ const initialCount = this.logEntries.length
|
|
|
+ this.logEntries = this.logEntries.filter(entry => entry.timestamp >= before)
|
|
|
+ return initialCount - this.logEntries.length
|
|
|
}
|
|
|
|
|
|
/**
|
|
@@ -289,11 +288,11 @@ export class ErrorHandler extends EventEmitter {
|
|
|
*/
|
|
|
generateCorrelationId(): string {
|
|
|
if (!this.options.enableCorrelationTracking) {
|
|
|
- return '';
|
|
|
+ return ''
|
|
|
}
|
|
|
|
|
|
- this.correlationCounter = (this.correlationCounter + 1) % 1000000;
|
|
|
- return `cm-${Date.now()}-${this.correlationCounter.toString().padStart(6, '0')}`;
|
|
|
+ this.correlationCounter = (this.correlationCounter + 1) % 1000000
|
|
|
+ return `cm-${Date.now()}-${this.correlationCounter.toString().padStart(6, '0')}`
|
|
|
}
|
|
|
|
|
|
// ============================================================================
|
|
@@ -310,9 +309,9 @@ export class ErrorHandler extends EventEmitter {
|
|
|
handle: async (error: Error, context: ErrorContext) => ({
|
|
|
recovered: false,
|
|
|
shouldRetry: (context.attempt || 0) < (context.maxRetries || this.options.maxRetries),
|
|
|
- retryDelay: this.options.retryDelay * Math.pow(2, context.attempt || 0) // Exponential backoff
|
|
|
- })
|
|
|
- });
|
|
|
+ retryDelay: this.options.retryDelay * Math.pow(2, context.attempt || 0), // Exponential backoff
|
|
|
+ }),
|
|
|
+ })
|
|
|
|
|
|
// File not found recovery
|
|
|
this.registerRecoveryStrategy({
|
|
@@ -322,10 +321,10 @@ export class ErrorHandler extends EventEmitter {
|
|
|
shouldRetry: false,
|
|
|
newError: new CredentialManagerError(
|
|
|
`Configuration file not found: ${error.message}`,
|
|
|
- ErrorType.CONFIG_LOAD_ERROR
|
|
|
- )
|
|
|
- })
|
|
|
- });
|
|
|
+ ErrorType.CONFIG_LOAD_ERROR,
|
|
|
+ ),
|
|
|
+ }),
|
|
|
+ })
|
|
|
|
|
|
// Validation error recovery
|
|
|
this.registerRecoveryStrategy({
|
|
@@ -333,42 +332,43 @@ export class ErrorHandler extends EventEmitter {
|
|
|
handle: async (error: Error, context: ErrorContext) => ({
|
|
|
recovered: false,
|
|
|
shouldRetry: false,
|
|
|
- newError: error // Don't retry validation errors
|
|
|
- })
|
|
|
- });
|
|
|
+ newError: error, // Don't retry validation errors
|
|
|
+ }),
|
|
|
+ })
|
|
|
|
|
|
// Generic retry strategy for temporary failures
|
|
|
this.registerRecoveryStrategy({
|
|
|
- canHandle: (error: Error) => error instanceof CredentialManagerError &&
|
|
|
+ canHandle: (error: Error) =>
|
|
|
+ error instanceof CredentialManagerError &&
|
|
|
[ErrorType.SIGNATURE_ERROR, ErrorType.CONFIG_LOAD_ERROR].includes(error.type),
|
|
|
handle: async (error: Error, context: ErrorContext) => {
|
|
|
- const attempt = context.attempt || 0;
|
|
|
- const maxRetries = context.maxRetries || this.options.maxRetries;
|
|
|
+ const attempt = context.attempt || 0
|
|
|
+ const maxRetries = context.maxRetries || this.options.maxRetries
|
|
|
|
|
|
return {
|
|
|
recovered: false,
|
|
|
shouldRetry: attempt < maxRetries,
|
|
|
- retryDelay: this.options.retryDelay * (attempt + 1)
|
|
|
- };
|
|
|
- }
|
|
|
- });
|
|
|
+ retryDelay: this.options.retryDelay * (attempt + 1),
|
|
|
+ }
|
|
|
+ },
|
|
|
+ })
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
* Log an error with context
|
|
|
*/
|
|
|
private logError(error: Error, context: ErrorContext): void {
|
|
|
- const severity = this.determineErrorSeverity(error);
|
|
|
- const level = severity === ErrorSeverity.CRITICAL ? LogLevel.FATAL : LogLevel.ERROR;
|
|
|
+ const severity = this.determineErrorSeverity(error)
|
|
|
+ const level = severity === ErrorSeverity.CRITICAL ? LogLevel.FATAL : LogLevel.ERROR
|
|
|
|
|
|
- const message = `${context.operation} failed: ${error.message}`;
|
|
|
+ const message = `${context.operation} failed: ${error.message}`
|
|
|
|
|
|
const metadata = {
|
|
|
...context.metadata,
|
|
|
severity,
|
|
|
errorType: error instanceof CredentialManagerError ? error.type : 'unknown',
|
|
|
- correlationId: context.correlationId
|
|
|
- };
|
|
|
+ correlationId: context.correlationId,
|
|
|
+ }
|
|
|
|
|
|
const entry: LogEntry = {
|
|
|
timestamp: new Date(),
|
|
@@ -380,26 +380,26 @@ export class ErrorHandler extends EventEmitter {
|
|
|
platform: context.platform,
|
|
|
error,
|
|
|
metadata,
|
|
|
- correlationId: context.correlationId
|
|
|
- };
|
|
|
+ correlationId: context.correlationId,
|
|
|
+ }
|
|
|
|
|
|
- this.addLogEntry(entry);
|
|
|
+ this.addLogEntry(entry)
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
* Track error occurrences for monitoring
|
|
|
*/
|
|
|
private trackError(error: Error, context: ErrorContext): void {
|
|
|
- const errorKey = `${context.component}:${error.constructor.name}`;
|
|
|
- const count = this.errorCounts.get(errorKey) || 0;
|
|
|
- this.errorCounts.set(errorKey, count + 1);
|
|
|
+ const errorKey = `${context.component}:${error.constructor.name}`
|
|
|
+ const count = this.errorCounts.get(errorKey) || 0
|
|
|
+ this.errorCounts.set(errorKey, count + 1)
|
|
|
|
|
|
// Emit error event for external monitoring
|
|
|
this.emit('error', {
|
|
|
error,
|
|
|
context,
|
|
|
- count: count + 1
|
|
|
- });
|
|
|
+ count: count + 1,
|
|
|
+ })
|
|
|
}
|
|
|
|
|
|
/**
|
|
@@ -409,22 +409,22 @@ export class ErrorHandler extends EventEmitter {
|
|
|
for (const strategy of this.recoveryStrategies) {
|
|
|
if (strategy.canHandle(error, context)) {
|
|
|
try {
|
|
|
- const result = await strategy.handle(error, context);
|
|
|
+ const result = await strategy.handle(error, context)
|
|
|
|
|
|
this.debug(`Recovery strategy applied`, 'ErrorHandler', {
|
|
|
strategy: strategy.constructor.name,
|
|
|
recovered: result.recovered,
|
|
|
shouldRetry: result.shouldRetry,
|
|
|
- correlationId: context.correlationId
|
|
|
- });
|
|
|
+ correlationId: context.correlationId,
|
|
|
+ })
|
|
|
|
|
|
- return result;
|
|
|
+ return result
|
|
|
} catch (recoveryError) {
|
|
|
this.warn(`Recovery strategy failed`, 'ErrorHandler', {
|
|
|
strategy: strategy.constructor.name,
|
|
|
error: recoveryError.message,
|
|
|
- correlationId: context.correlationId
|
|
|
- });
|
|
|
+ correlationId: context.correlationId,
|
|
|
+ })
|
|
|
}
|
|
|
}
|
|
|
}
|
|
@@ -432,8 +432,8 @@ export class ErrorHandler extends EventEmitter {
|
|
|
// No strategy could handle the error
|
|
|
return {
|
|
|
recovered: false,
|
|
|
- shouldRetry: false
|
|
|
- };
|
|
|
+ shouldRetry: false,
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
/**
|
|
@@ -443,24 +443,24 @@ export class ErrorHandler extends EventEmitter {
|
|
|
if (error instanceof CredentialManagerError) {
|
|
|
switch (error.type) {
|
|
|
case ErrorType.VALIDATION_ERROR:
|
|
|
- return ErrorSeverity.MEDIUM;
|
|
|
+ return ErrorSeverity.MEDIUM
|
|
|
case ErrorType.CONFIG_LOAD_ERROR:
|
|
|
- return ErrorSeverity.HIGH;
|
|
|
+ return ErrorSeverity.HIGH
|
|
|
case ErrorType.SIGNATURE_ERROR:
|
|
|
- return ErrorSeverity.HIGH;
|
|
|
+ return ErrorSeverity.HIGH
|
|
|
case ErrorType.PLATFORM_DETECTION_ERROR:
|
|
|
- return ErrorSeverity.MEDIUM;
|
|
|
+ return ErrorSeverity.MEDIUM
|
|
|
default:
|
|
|
- return ErrorSeverity.MEDIUM;
|
|
|
+ return ErrorSeverity.MEDIUM
|
|
|
}
|
|
|
}
|
|
|
|
|
|
// Check for critical system errors
|
|
|
if (error.message.includes('EMFILE') || error.message.includes('ENOMEM')) {
|
|
|
- return ErrorSeverity.CRITICAL;
|
|
|
+ return ErrorSeverity.CRITICAL
|
|
|
}
|
|
|
|
|
|
- return ErrorSeverity.LOW;
|
|
|
+ return ErrorSeverity.LOW
|
|
|
}
|
|
|
|
|
|
/**
|
|
@@ -468,14 +468,14 @@ export class ErrorHandler extends EventEmitter {
|
|
|
*/
|
|
|
private shouldLog(level: LogLevel): boolean {
|
|
|
if (!this.options.enableLogging) {
|
|
|
- return false;
|
|
|
+ return false
|
|
|
}
|
|
|
|
|
|
- const levels = [LogLevel.DEBUG, LogLevel.INFO, LogLevel.WARN, LogLevel.ERROR, LogLevel.FATAL];
|
|
|
- const currentLevelIndex = levels.indexOf(this.options.logLevel);
|
|
|
- const messageLevelIndex = levels.indexOf(level);
|
|
|
+ const levels = [LogLevel.DEBUG, LogLevel.INFO, LogLevel.WARN, LogLevel.ERROR, LogLevel.FATAL]
|
|
|
+ const currentLevelIndex = levels.indexOf(this.options.logLevel)
|
|
|
+ const messageLevelIndex = levels.indexOf(level)
|
|
|
|
|
|
- return messageLevelIndex >= currentLevelIndex;
|
|
|
+ return messageLevelIndex >= currentLevelIndex
|
|
|
}
|
|
|
|
|
|
/**
|
|
@@ -483,70 +483,70 @@ export class ErrorHandler extends EventEmitter {
|
|
|
*/
|
|
|
private addLogEntry(entry: LogEntry): void {
|
|
|
if (this.options.enableAuditTrail) {
|
|
|
- this.logEntries.push(entry);
|
|
|
+ this.logEntries.push(entry)
|
|
|
|
|
|
// Keep only recent entries to prevent memory leaks
|
|
|
if (this.logEntries.length > 10000) {
|
|
|
- this.logEntries = this.logEntries.slice(-5000);
|
|
|
+ this.logEntries = this.logEntries.slice(-5000)
|
|
|
}
|
|
|
}
|
|
|
|
|
|
if (this.options.enableConsoleOutput) {
|
|
|
- this.outputToConsole(entry);
|
|
|
+ this.outputToConsole(entry)
|
|
|
}
|
|
|
|
|
|
// Emit log event for external listeners
|
|
|
- this.emit('log', entry);
|
|
|
+ this.emit('log', entry)
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
* Output log entry to console with appropriate formatting
|
|
|
*/
|
|
|
private outputToConsole(entry: LogEntry): void {
|
|
|
- const timestamp = entry.timestamp.toISOString();
|
|
|
- const level = entry.level.toUpperCase().padEnd(5);
|
|
|
- const component = entry.component.padEnd(20);
|
|
|
+ const timestamp = entry.timestamp.toISOString()
|
|
|
+ const level = entry.level.toUpperCase().padEnd(5)
|
|
|
+ const component = entry.component.padEnd(20)
|
|
|
|
|
|
- let message = `[${timestamp}] ${level} ${component} ${entry.message}`;
|
|
|
+ let message = `[${timestamp}] ${level} ${component} ${entry.message}`
|
|
|
|
|
|
if (entry.correlationId) {
|
|
|
- message += ` [${entry.correlationId}]`;
|
|
|
+ message += ` [${entry.correlationId}]`
|
|
|
}
|
|
|
|
|
|
if (entry.accountId) {
|
|
|
- message += ` (account: ${entry.accountId})`;
|
|
|
+ message += ` (account: ${entry.accountId})`
|
|
|
}
|
|
|
|
|
|
if (entry.platform) {
|
|
|
- message += ` (platform: ${entry.platform})`;
|
|
|
+ message += ` (platform: ${entry.platform})`
|
|
|
}
|
|
|
|
|
|
switch (entry.level) {
|
|
|
case LogLevel.DEBUG:
|
|
|
- console.debug(message);
|
|
|
- break;
|
|
|
+ console.debug(message)
|
|
|
+ break
|
|
|
case LogLevel.INFO:
|
|
|
- console.info(message);
|
|
|
- break;
|
|
|
+ console.info(message)
|
|
|
+ break
|
|
|
case LogLevel.WARN:
|
|
|
- console.warn(message);
|
|
|
- break;
|
|
|
+ console.warn(message)
|
|
|
+ break
|
|
|
case LogLevel.ERROR:
|
|
|
- console.error(message);
|
|
|
+ console.error(message)
|
|
|
if (entry.error) {
|
|
|
- console.error(entry.error.stack);
|
|
|
+ console.error(entry.error.stack)
|
|
|
}
|
|
|
- break;
|
|
|
+ break
|
|
|
case LogLevel.FATAL:
|
|
|
- console.error(message);
|
|
|
+ console.error(message)
|
|
|
if (entry.error) {
|
|
|
- console.error(entry.error.stack);
|
|
|
+ console.error(entry.error.stack)
|
|
|
}
|
|
|
- break;
|
|
|
+ break
|
|
|
}
|
|
|
|
|
|
if (entry.metadata && Object.keys(entry.metadata).length > 0) {
|
|
|
- console.debug('Metadata:', entry.metadata);
|
|
|
+ console.debug('Metadata:', entry.metadata)
|
|
|
}
|
|
|
}
|
|
|
}
|
|
@@ -559,7 +559,7 @@ export class ErrorHandler extends EventEmitter {
|
|
|
* Create error handler with default options
|
|
|
*/
|
|
|
export function createErrorHandler(options?: ErrorHandlerOptions): ErrorHandler {
|
|
|
- return new ErrorHandler(options);
|
|
|
+ return new ErrorHandler(options)
|
|
|
}
|
|
|
|
|
|
/**
|
|
@@ -574,8 +574,8 @@ export function createProductionErrorHandler(): ErrorHandler {
|
|
|
maxRetries: 3,
|
|
|
retryDelay: 1000,
|
|
|
enableAuditTrail: true,
|
|
|
- enableCorrelationTracking: true
|
|
|
- });
|
|
|
+ enableCorrelationTracking: true,
|
|
|
+ })
|
|
|
}
|
|
|
|
|
|
/**
|
|
@@ -590,34 +590,34 @@ export function createDevelopmentErrorHandler(): ErrorHandler {
|
|
|
maxRetries: 5,
|
|
|
retryDelay: 500,
|
|
|
enableAuditTrail: true,
|
|
|
- enableCorrelationTracking: true
|
|
|
- });
|
|
|
+ enableCorrelationTracking: true,
|
|
|
+ })
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
* Global error handler instance for convenience
|
|
|
*/
|
|
|
-let globalErrorHandler: ErrorHandler | null = null;
|
|
|
+let globalErrorHandler: ErrorHandler | null = null
|
|
|
|
|
|
/**
|
|
|
* Get or create global error handler instance
|
|
|
*/
|
|
|
export function getGlobalErrorHandler(): ErrorHandler {
|
|
|
if (!globalErrorHandler) {
|
|
|
- globalErrorHandler = createErrorHandler();
|
|
|
+ globalErrorHandler = createErrorHandler()
|
|
|
}
|
|
|
- return globalErrorHandler;
|
|
|
+ return globalErrorHandler
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
* Set global error handler instance
|
|
|
*/
|
|
|
export function setGlobalErrorHandler(handler: ErrorHandler): void {
|
|
|
- globalErrorHandler = handler;
|
|
|
+ globalErrorHandler = handler
|
|
|
}
|
|
|
|
|
|
// ============================================================================
|
|
|
// Export
|
|
|
// ============================================================================
|
|
|
|
|
|
-export default ErrorHandler;
|
|
|
+export default ErrorHandler
|