import { DomainEventBus } from '../runtime/DomainEventBus'; // 异常信息 export interface ExceptionInfo { id: string; type: string; message: string; stack?: string; service: string; context?: Record; severity: 'low' | 'medium' | 'high' | 'critical'; status: 'open' | 'processing' | 'resolved' | 'ignored'; createdAt: Date; lastUpdated: Date; resolvedAt?: Date; resolvedBy?: string; } // 异常统计 export interface ExceptionStats { total: number; bySeverity: { low: number; medium: number; high: number; critical: number; }; byStatus: { open: number; processing: number; resolved: number; ignored: number; }; byService: Record; byType: Record; averageResolutionTime: number; // 平均解决时间(分钟) last24Hours: number; last7Days: number; } // 异常监控 export class ExceptionMonitor { private static instance: ExceptionMonitor; private exceptions: Map = new Map(); private eventBus: DomainEventBus; private severityThresholds: Record = { low: 10, medium: 5, high: 2, critical: 1 }; private constructor() { this.eventBus = DomainEventBus.getInstance(); } static getInstance(): ExceptionMonitor { if (!ExceptionMonitor.instance) { ExceptionMonitor.instance = new ExceptionMonitor(); } return ExceptionMonitor.instance; } // 记录异常 async recordException(exception: Omit): Promise { const id = `exception_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`; const newException: ExceptionInfo = { ...exception, id, status: 'open', createdAt: new Date(), lastUpdated: new Date() }; this.exceptions.set(id, newException); this.eventBus.publish('exception.recorded', newException); // 检查是否需要触发告警 await this.checkAlertThreshold(newException); return newException; } // 获取异常信息 getException(exceptionId: string): ExceptionInfo | undefined { return this.exceptions.get(exceptionId); } // 获取所有异常 getAllExceptions(filters?: { severity?: string; status?: string; service?: string; type?: string; startDate?: Date; endDate?: Date; }): ExceptionInfo[] { let result = Array.from(this.exceptions.values()); if (filters) { if (filters.severity) { result = result.filter(e => e.severity === filters.severity); } if (filters.status) { result = result.filter(e => e.status === filters.status); } if (filters.service) { result = result.filter(e => e.service === filters.service); } if (filters.type) { result = result.filter(e => e.type === filters.type); } if (filters.startDate) { result = result.filter(e => e.createdAt >= filters.startDate!); } if (filters.endDate) { result = result.filter(e => e.createdAt <= filters.endDate!); } } return result.sort((a, b) => b.createdAt.getTime() - a.createdAt.getTime()); } // 更新异常状态 async updateExceptionStatus(exceptionId: string, status: 'open' | 'processing' | 'resolved' | 'ignored', resolvedBy?: string): Promise { const exception = this.exceptions.get(exceptionId); if (!exception) { return null; } const updatedException = { ...exception, status, lastUpdated: new Date(), resolvedAt: status === 'resolved' ? new Date() : exception.resolvedAt, resolvedBy: status === 'resolved' ? resolvedBy : exception.resolvedBy }; this.exceptions.set(exceptionId, updatedException); this.eventBus.publish('exception.status.updated', updatedException); return updatedException; } // 更新异常信息 async updateException(exceptionId: string, updates: Partial): Promise { const exception = this.exceptions.get(exceptionId); if (!exception) { return null; } const updatedException = { ...exception, ...updates, lastUpdated: new Date() }; this.exceptions.set(exceptionId, updatedException); this.eventBus.publish('exception.updated', updatedException); return updatedException; } // 检查告警阈值 private async checkAlertThreshold(exception: ExceptionInfo): Promise { const threshold = this.severityThresholds[exception.severity]; if (!threshold) return; // 检查过去24小时内相同类型的异常数量 const last24Hours = new Date(); last24Hours.setHours(last24Hours.getHours() - 24); const similarExceptions = Array.from(this.exceptions.values()).filter(e => e.type === exception.type && e.service === exception.service && e.createdAt >= last24Hours ); if (similarExceptions.length >= threshold) { this.eventBus.publish('exception.alert', { exception, count: similarExceptions.length, threshold, timestamp: new Date() }); } } // 获取异常统计 getExceptionStats(): ExceptionStats { const exceptions = Array.from(this.exceptions.values()); const total = exceptions.length; const bySeverity = { low: 0, medium: 0, high: 0, critical: 0 }; const byStatus = { open: 0, processing: 0, resolved: 0, ignored: 0 }; const byService: Record = {}; const byType: Record = {}; let totalResolutionTime = 0; let resolvedExceptions = 0; const last24Hours = new Date(); last24Hours.setHours(last24Hours.getHours() - 24); const last7Days = new Date(); last7Days.setDate(last7Days.getDate() - 7); let exceptionsLast24Hours = 0; let exceptionsLast7Days = 0; for (const exception of exceptions) { bySeverity[exception.severity]++; byStatus[exception.status]++; byService[exception.service] = (byService[exception.service] || 0) + 1; byType[exception.type] = (byType[exception.type] || 0) + 1; if (exception.status === 'resolved' && exception.resolvedAt) { const resolutionTime = (exception.resolvedAt.getTime() - exception.createdAt.getTime()) / (1000 * 60); // 转换为分钟 totalResolutionTime += resolutionTime; resolvedExceptions++; } if (exception.createdAt >= last24Hours) { exceptionsLast24Hours++; } if (exception.createdAt >= last7Days) { exceptionsLast7Days++; } } const averageResolutionTime = resolvedExceptions > 0 ? totalResolutionTime / resolvedExceptions : 0; return { total, bySeverity, byStatus, byService, byType, averageResolutionTime, last24Hours: exceptionsLast24Hours, last7Days: exceptionsLast7Days }; } // 获取服务异常统计 getServiceExceptionStats(service: string): ExceptionStats { const serviceExceptions = Array.from(this.exceptions.values()).filter(e => e.service === service); const total = serviceExceptions.length; const bySeverity = { low: 0, medium: 0, high: 0, critical: 0 }; const byStatus = { open: 0, processing: 0, resolved: 0, ignored: 0 }; const byType: Record = {}; let totalResolutionTime = 0; let resolvedExceptions = 0; const last24Hours = new Date(); last24Hours.setHours(last24Hours.getHours() - 24); const last7Days = new Date(); last7Days.setDate(last7Days.getDate() - 7); let exceptionsLast24Hours = 0; let exceptionsLast7Days = 0; for (const exception of serviceExceptions) { bySeverity[exception.severity]++; byStatus[exception.status]++; byType[exception.type] = (byType[exception.type] || 0) + 1; if (exception.status === 'resolved' && exception.resolvedAt) { const resolutionTime = (exception.resolvedAt.getTime() - exception.createdAt.getTime()) / (1000 * 60); // 转换为分钟 totalResolutionTime += resolutionTime; resolvedExceptions++; } if (exception.createdAt >= last24Hours) { exceptionsLast24Hours++; } if (exception.createdAt >= last7Days) { exceptionsLast7Days++; } } const averageResolutionTime = resolvedExceptions > 0 ? totalResolutionTime / resolvedExceptions : 0; return { total, bySeverity, byStatus, byService: { [service]: total }, byType, averageResolutionTime, last24Hours: exceptionsLast24Hours, last7Days: exceptionsLast7Days }; } // 清理旧异常 async cleanupOldExceptions(days: number = 30): Promise { const cutoffDate = new Date(); cutoffDate.setDate(cutoffDate.getDate() - days); let removedCount = 0; for (const [id, exception] of this.exceptions.entries()) { if (exception.createdAt < cutoffDate && exception.status === 'resolved') { this.exceptions.delete(id); removedCount++; } } if (removedCount > 0) { this.eventBus.publish('exception.cleanup', { removedCount, cutoffDate, timestamp: new Date() }); } return removedCount; } // 生成异常报告 async generateExceptionReport(startDate: Date, endDate: Date): Promise<{ summary: ExceptionStats; topExceptions: ExceptionInfo[]; serviceStats: Record; }> { const filteredExceptions = Array.from(this.exceptions.values()).filter( e => e.createdAt >= startDate && e.createdAt <= endDate ); // 按频率排序的异常类型 const typeFrequency: Record = {}; for (const exception of filteredExceptions) { typeFrequency[exception.type] = (typeFrequency[exception.type] || 0) + 1; } const sortedTypes = Object.entries(typeFrequency) .sort(([, a], [, b]) => b - a) .slice(0, 10) .map(([type]) => type); const topExceptions = filteredExceptions .filter(e => sortedTypes.includes(e.type)) .slice(0, 20); // 按服务分组的统计 const serviceStats: Record = {}; const services = Array.from(new Set(filteredExceptions.map(e => e.service))); for (const service of services) { serviceStats[service] = this.getServiceExceptionStats(service); } return { summary: this.getExceptionStats(), topExceptions, serviceStats }; } // 设置严重性阈值 setSeverityThresholds(thresholds: Record): void { this.severityThresholds = { ...this.severityThresholds, ...thresholds }; } // 获取严重性阈值 getSeverityThresholds(): Record { return { ...this.severityThresholds }; } }