UNPKG

@ahmedhegazee/nestjs-telescope

Version:

Advanced observability and monitoring solution for NestJS applications with ML-powered analytics, enterprise features, and production-ready scaling

272 lines 11.9 kB
"use strict"; var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) { var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d; if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc); else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r; return c > 3 && r && Object.defineProperty(target, key, r), r; }; var __metadata = (this && this.__metadata) || function (k, v) { if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v); }; var PerformanceOptimizerService_1; Object.defineProperty(exports, "__esModule", { value: true }); exports.PerformanceOptimizerService = void 0; const common_1 = require("@nestjs/common"); const rxjs_1 = require("rxjs"); const operators_1 = require("rxjs/operators"); let PerformanceOptimizerService = PerformanceOptimizerService_1 = class PerformanceOptimizerService { constructor() { this.logger = new common_1.Logger(PerformanceOptimizerService_1.name); this.metricsSubject = new rxjs_1.Subject(); this.settingsSubject = new rxjs_1.BehaviorSubject({ batchSize: 100, flushInterval: 1000, maxConcurrency: 3, memoryThreshold: 100 * 1024 * 1024, adaptiveOptimization: true }); this.performanceHistory = []; this.maxHistorySize = 100; this.lastOptimizationTime = 0; this.optimizationInterval = 30000; this.startPerformanceMonitoring(); } startPerformanceMonitoring() { setInterval(() => { this.collectSystemMetrics(); }, 5000); setInterval(() => { this.analyzeAndOptimize(); }, this.optimizationInterval); } collectSystemMetrics() { const metrics = { averageProcessingTime: this.calculateAverageProcessingTime(), throughput: this.calculateThroughput(), memoryUsage: this.getMemoryUsage(), cpuUsage: this.getCpuUsage(), errorRate: this.calculateErrorRate(), queueSize: this.getCurrentQueueSize() }; this.metricsSubject.next(metrics); this.addToHistory(metrics); } calculateAverageProcessingTime() { return this.performanceHistory.length > 0 ? this.performanceHistory.slice(-10).reduce((sum, m) => sum + m.averageProcessingTime, 0) / Math.min(10, this.performanceHistory.length) : 0; } calculateThroughput() { const recentMetrics = this.performanceHistory.slice(-12); if (recentMetrics.length < 2) return 0; const timeSpan = 60; const totalProcessed = recentMetrics.reduce((sum, m) => sum + (m.throughput || 0), 0); return totalProcessed / timeSpan; } getMemoryUsage() { const memUsage = process.memoryUsage(); return memUsage.heapUsed; } getCpuUsage() { const usage = process.cpuUsage(); return (usage.user + usage.system) / 1000000; } calculateErrorRate() { const recentMetrics = this.performanceHistory.slice(-12); if (recentMetrics.length === 0) return 0; const totalErrors = recentMetrics.reduce((sum, m) => sum + (m.errorRate || 0), 0); return totalErrors / recentMetrics.length; } getCurrentQueueSize() { return 0; } addToHistory(metrics) { this.performanceHistory.push(metrics); if (this.performanceHistory.length > this.maxHistorySize) { this.performanceHistory.shift(); } } analyzeAndOptimize() { const now = Date.now(); if (now - this.lastOptimizationTime < this.optimizationInterval) { return; } const currentSettings = this.settingsSubject.value; if (!currentSettings.adaptiveOptimization) { return; } const recommendations = this.generateOptimizationRecommendations(); if (recommendations.length > 0) { this.logger.log(`Generated ${recommendations.length} optimization recommendations`); this.applyOptimizations(recommendations); } this.lastOptimizationTime = now; } generateOptimizationRecommendations() { const recommendations = []; const currentSettings = this.settingsSubject.value; const recentMetrics = this.performanceHistory.slice(-12); if (recentMetrics.length < 5) { return recommendations; } const avgMetrics = this.calculateAverageMetrics(recentMetrics); if (avgMetrics.averageProcessingTime > 5000) { recommendations.push({ type: 'batch_size', current: currentSettings.batchSize, recommended: Math.max(10, currentSettings.batchSize * 0.8), reason: 'High processing time detected', impact: 'medium', confidence: 0.7 }); } else if (avgMetrics.averageProcessingTime < 1000 && avgMetrics.throughput > 50) { recommendations.push({ type: 'batch_size', current: currentSettings.batchSize, recommended: Math.min(500, currentSettings.batchSize * 1.2), reason: 'Low processing time with high throughput', impact: 'low', confidence: 0.6 }); } if (avgMetrics.queueSize > currentSettings.batchSize * 0.8) { recommendations.push({ type: 'flush_interval', current: currentSettings.flushInterval, recommended: Math.max(500, currentSettings.flushInterval * 0.8), reason: 'High queue size detected', impact: 'medium', confidence: 0.8 }); } if (avgMetrics.cpuUsage > 80) { recommendations.push({ type: 'concurrency', current: currentSettings.maxConcurrency, recommended: Math.max(1, currentSettings.maxConcurrency - 1), reason: 'High CPU usage detected', impact: 'high', confidence: 0.9 }); } else if (avgMetrics.cpuUsage < 30 && avgMetrics.averageProcessingTime > 3000) { recommendations.push({ type: 'concurrency', current: currentSettings.maxConcurrency, recommended: Math.min(10, currentSettings.maxConcurrency + 1), reason: 'Low CPU usage with high processing time', impact: 'medium', confidence: 0.7 }); } if (avgMetrics.memoryUsage > currentSettings.memoryThreshold) { recommendations.push({ type: 'memory', current: currentSettings.batchSize, recommended: Math.max(10, currentSettings.batchSize * 0.7), reason: 'Memory usage above threshold', impact: 'high', confidence: 0.8 }); } return recommendations; } calculateAverageMetrics(metrics) { const count = metrics.length; return { averageProcessingTime: metrics.reduce((sum, m) => sum + m.averageProcessingTime, 0) / count, throughput: metrics.reduce((sum, m) => sum + m.throughput, 0) / count, memoryUsage: metrics.reduce((sum, m) => sum + m.memoryUsage, 0) / count, cpuUsage: metrics.reduce((sum, m) => sum + m.cpuUsage, 0) / count, errorRate: metrics.reduce((sum, m) => sum + m.errorRate, 0) / count, queueSize: metrics.reduce((sum, m) => sum + m.queueSize, 0) / count }; } applyOptimizations(recommendations) { const currentSettings = this.settingsSubject.value; const newSettings = { ...currentSettings }; const sortedRecommendations = recommendations.sort((a, b) => { const impactOrder = { high: 3, medium: 2, low: 1 }; return (impactOrder[b.impact] * b.confidence) - (impactOrder[a.impact] * a.confidence); }); for (const recommendation of sortedRecommendations) { if (recommendation.confidence < 0.6) { continue; } switch (recommendation.type) { case 'batch_size': newSettings.batchSize = Math.round(recommendation.recommended); this.logger.log(`Optimized batch size: ${recommendation.current} → ${newSettings.batchSize}`); break; case 'flush_interval': newSettings.flushInterval = Math.round(recommendation.recommended); this.logger.log(`Optimized flush interval: ${recommendation.current} → ${newSettings.flushInterval}`); break; case 'concurrency': newSettings.maxConcurrency = Math.round(recommendation.recommended); this.logger.log(`Optimized concurrency: ${recommendation.current} → ${newSettings.maxConcurrency}`); break; case 'memory': newSettings.batchSize = Math.round(recommendation.recommended); this.logger.log(`Optimized for memory: batch size ${recommendation.current} → ${newSettings.batchSize}`); break; } } this.settingsSubject.next(newSettings); } getMetricsStream() { return this.metricsSubject.asObservable().pipe((0, operators_1.shareReplay)(1)); } getSettingsStream() { return this.settingsSubject.asObservable().pipe((0, operators_1.shareReplay)(1)); } getCurrentMetrics() { return this.performanceHistory.length > 0 ? this.performanceHistory[this.performanceHistory.length - 1] : null; } getCurrentSettings() { return this.settingsSubject.value; } updateSettings(settings) { const currentSettings = this.settingsSubject.value; const newSettings = { ...currentSettings, ...settings }; this.settingsSubject.next(newSettings); this.logger.log('Performance settings updated:', settings); } generatePerformanceReport() { const recommendations = this.generateOptimizationRecommendations(); const recentHistory = this.performanceHistory.slice(-20); return { currentMetrics: this.getCurrentMetrics(), settings: this.getCurrentSettings(), recommendations, trends: { processingTime: recentHistory.map(m => m.averageProcessingTime), throughput: recentHistory.map(m => m.throughput), memoryUsage: recentHistory.map(m => m.memoryUsage), errorRate: recentHistory.map(m => m.errorRate) } }; } resetOptimizations() { const defaultSettings = { batchSize: 100, flushInterval: 1000, maxConcurrency: 3, memoryThreshold: 100 * 1024 * 1024, adaptiveOptimization: true }; this.settingsSubject.next(defaultSettings); this.logger.log('Performance settings reset to defaults'); } }; exports.PerformanceOptimizerService = PerformanceOptimizerService; exports.PerformanceOptimizerService = PerformanceOptimizerService = PerformanceOptimizerService_1 = __decorate([ (0, common_1.Injectable)(), __metadata("design:paramtypes", []) ], PerformanceOptimizerService); //# sourceMappingURL=performance-optimizer.service.js.map