UNPKG

@iota-big3/sdk-security

Version:

Advanced security features including zero trust, quantum-safe crypto, and ML threat detection

366 lines 14.7 kB
"use strict"; /** * @iota-big3/sdk-security - Performance Monitoring * Real-time metrics collection and analysis for production readiness */ Object.defineProperty(exports, "__esModule", { value: true }); exports.PerformanceMonitor = void 0; const events_1 = require("events"); class PerformanceMonitor extends events_1.EventEmitter { constructor(config) { super(); this.config = config; this.metrics = new Map(); this.thresholds = []; this.alerts = []; this.isActive = false; this.metricsHistory = []; // Performance tracking this.operationTimers = new Map(); this.operationCounts = new Map(); this.circuitBreakers = new Map(); this.setupDefaultThresholds(); } setupDefaultThresholds() { this.thresholds = [ // Latency thresholds { metric: 'authLatencyP99', operator: '>', value: 100, action: 'alert' }, { metric: 'authLatencyP99', operator: '>', value: 500, action: 'circuit_break' }, { metric: 'rbacCheckLatency', operator: '>', value: 50, action: 'alert' }, { metric: 'complianceCheckDuration', operator: '>', value: 30000, action: 'alert' }, // Success rate thresholds { metric: 'authSuccessRate', operator: '<', value: 95, action: 'alert' }, { metric: 'authSuccessRate', operator: '<', value: 90, action: 'degrade' }, // Resource thresholds { metric: 'cpuUsage', operator: '>', value: 80, action: 'alert' }, { metric: 'memoryUsage', operator: '>', value: 85, action: 'degrade' }, { metric: 'eventLoopLag', operator: '>', value: 50, action: 'alert' }, // Queue depth thresholds { metric: 'scanQueueDepth', operator: '>', value: 1000, action: 'alert' }, { metric: 'scanQueueDepth', operator: '>', value: 5000, action: 'circuit_break' } ]; } async start() { if (this.isActive) return; this.isActive = true; this.emit('monitor:started'); // Start metrics collection this.collectionInterval = setInterval(() => { this.collectMetrics(); }, this.config.collectionIntervalMs); } async stop() { if (!this.isActive) return; this.isActive = false; if (this.collectionInterval) { clearInterval(this.collectionInterval); } this.emit('monitor:stopped'); } // Operation timing startOperation(operationName, tags) { const operationId = `${operationName}-${Date.now()}-${Math.random()}`; this.operationTimers.set(operationId, Date.now()); // Track operation count const count = this.operationCounts.get(operationName) || 0; this.operationCounts.set(operationName, count + 1); return operationId; } endOperation(operationId, success = true) { const startTime = this.operationTimers.get(operationId); if (!startTime) return; const duration = Date.now() - startTime; const parts = operationId.split('-'); const operationName = parts[0] || 'unknown'; // Record metric this.recordMetric({ name: `${operationName}.latency`, value: duration, unit: 'ms', timestamp: Date.now(), tags: { success: success.toString() } }); this.operationTimers.delete(operationId); // Check circuit breaker if (this.config.enableCircuitBreakers) { this.updateCircuitBreaker(operationName, success, duration); } } // Circuit breaker management updateCircuitBreaker(operation, success, latency) { let breaker = this.circuitBreakers.get(operation); if (!breaker) { breaker = new CircuitBreaker(operation, { failureThreshold: 5, resetTimeout: 60000, latencyThreshold: 1000 }); this.circuitBreakers.set(operation, breaker); } breaker.recordResult(success, latency); if (breaker.isOpen()) { this.emit('circuit:opened', { operation, reason: breaker.getFailureReason() }); } } isCircuitOpen(operation) { const breaker = this.circuitBreakers.get(operation); return breaker ? breaker.isOpen() : false; } // Metric recording recordMetric(metric) { let buffer = this.metrics.get(metric.name); if (!buffer) { buffer = { values: [], timestamps: [], maxSize: 1000 }; this.metrics.set(metric.name, buffer); } buffer.values.push(metric.value); buffer.timestamps.push(metric.timestamp); // Maintain buffer size if (buffer.values.length > buffer.maxSize) { buffer.values.shift(); buffer.timestamps.shift(); } // Check thresholds this.checkThresholds(metric); } checkThresholds(metric) { for (const threshold of this.thresholds) { if (threshold.metric !== metric.name) continue; const violated = this.evaluateThreshold(metric.value, threshold); if (violated) { this.handleThresholdViolation(metric, threshold); } } } evaluateThreshold(value, threshold) { switch (threshold.operator) { case '<': return value < threshold.value; case '>': return value > threshold.value; case '<=': return value <= threshold.value; case '>=': return value >= threshold.value; case '==': return value === threshold.value; default: return false; } } handleThresholdViolation(metric, threshold) { const alert = { id: `alert-${Date.now()}-${Math.random()}`, timestamp: Date.now(), metric: metric.name, value: metric.value, threshold: threshold.value, severity: this.getSeverity(threshold.action), message: `${metric.name} ${threshold.operator} ${threshold.value} (actual: ${metric.value})` }; this.alerts.push(alert); this.emit('performance:alert', alert); // Take action based on threshold switch (threshold.action) { case 'degrade': this.emit('performance:degrade', { metric: metric.name, reason: alert.message }); break; case 'circuit_break': this.emit('performance:circuit_break', { metric: metric.name, reason: alert.message }); break; } } getSeverity(action) { switch (action) { case 'alert': return 'medium'; case 'degrade': return 'high'; case 'circuit_break': return 'critical'; default: return 'low'; } } // Metrics collection async collectMetrics() { const snapshot = { timestamp: Date.now(), metrics: { // Calculate percentiles for auth latency authLatencyP50: this.calculatePercentile('auth.latency', 50), authLatencyP95: this.calculatePercentile('auth.latency', 95), authLatencyP99: this.calculatePercentile('auth.latency', 99), authSuccessRate: this.calculateSuccessRate('auth'), authFailureRate: 100 - this.calculateSuccessRate('auth'), // Access control metrics rbacCheckLatency: this.getAverageMetric('rbac.check.latency'), abacCheckLatency: this.getAverageMetric('abac.check.latency'), accessDecisionCacheHitRate: this.getLatestMetric('cache.hit.rate'), // Security scanning metrics scanQueueDepth: this.getLatestMetric('scan.queue.depth'), averageScanDuration: this.getAverageMetric('scan.duration'), scanThroughput: this.calculateThroughput('scan'), // Compliance metrics complianceCheckDuration: this.getAverageMetric('compliance.check.duration'), evidenceCollectionRate: this.calculateRate('evidence.collected'), auditLogWriteLatency: this.getAverageMetric('audit.write.latency'), // Threat detection metrics threatDetectionLatency: this.getAverageMetric('threat.detection.latency'), anomalyDetectionRate: this.calculateRate('anomaly.detected'), falsePositiveRate: this.calculateFalsePositiveRate(), // System metrics cpuUsage: this.calculateCpuUsage(), memoryUsage: this.calculateMemoryUsage(), eventLoopLag: this.measureEventLoopLag(), activeConnections: this.getLatestMetric('connections.active') }, alerts: this.alerts.filter(a => a.timestamp > Date.now() - 300000) // Last 5 minutes }; this.metricsHistory.push(snapshot); // Maintain history size if (this.metricsHistory.length > this.config.historySize) { this.metricsHistory.shift(); } this.emit('metrics:collected', snapshot); } // Metric calculations calculatePercentile(metricName, percentile) { const buffer = this.metrics.get(metricName); if (!buffer || buffer.values.length === 0) return 0; const sorted = [...buffer.values].sort((a, b) => a - b); const index = Math.ceil((percentile / 100) * sorted.length) - 1; return sorted[Math.max(0, index)] || 0; } getAverageMetric(metricName) { const buffer = this.metrics.get(metricName); if (!buffer || buffer.values.length === 0) return 0; const sum = buffer.values.reduce((a, b) => a + b, 0); return sum / buffer.values.length; } getLatestMetric(metricName) { const buffer = this.metrics.get(metricName); if (!buffer || buffer.values.length === 0) return 0; return buffer.values[buffer.values.length - 1]; } calculateSuccessRate(operation) { const successBuffer = this.metrics.get(`${operation}.success`); const totalBuffer = this.metrics.get(`${operation}.total`); if (!successBuffer || !totalBuffer || totalBuffer.values.length === 0) return 100; const successes = successBuffer.values.reduce((a, b) => a + b, 0); const total = totalBuffer.values.reduce((a, b) => a + b, 0); return total > 0 ? (successes / total) * 100 : 100; } calculateThroughput(operation) { const count = this.operationCounts.get(operation) || 0; const timeWindow = this.config.collectionIntervalMs / 1000; // Convert to seconds return count / timeWindow; } calculateRate(event) { const buffer = this.metrics.get(event); if (!buffer || buffer.values.length < 2) return 0; const timeRange = buffer.timestamps[buffer.timestamps.length - 1] - buffer.timestamps[0]; const eventCount = buffer.values.reduce((a, b) => a + b, 0); return timeRange > 0 ? (eventCount / timeRange) * 1000 : 0; // Events per second } calculateFalsePositiveRate() { const falsePositives = this.getLatestMetric('threat.false_positives'); const totalAlerts = this.getLatestMetric('threat.total_alerts'); return totalAlerts > 0 ? (falsePositives / totalAlerts) * 100 : 0; } calculateCpuUsage() { const usage = process.cpuUsage(); const totalTime = usage.user + usage.system; const elapsedTime = process.uptime() * 1000000; // Convert to microseconds return (totalTime / elapsedTime) * 100; } calculateMemoryUsage() { const memUsage = process.memoryUsage(); const totalMemory = memUsage.heapTotal; const usedMemory = memUsage.heapUsed; return (usedMemory / totalMemory) * 100; } measureEventLoopLag() { let lag = 0; const start = Date.now(); setImmediate(() => { lag = Date.now() - start; }); return lag; } // Data retrieval getSnapshot() { return this.metricsHistory[this.metricsHistory.length - 1] || null; } getHistory(duration = 3600000) { const cutoff = Date.now() - duration; return this.metricsHistory.filter(s => s.timestamp > cutoff); } getAlerts(severity) { if (severity) { return this.alerts.filter(a => a.severity === severity); } return this.alerts; } // Export for dashboards exportMetrics(format = 'json') { const snapshot = this.getSnapshot(); if (!snapshot) return ''; if (format === 'prometheus') { return this.toPrometheusFormat(snapshot); } return JSON.stringify(snapshot, null, 2); } toPrometheusFormat(snapshot) { const lines = []; for (const [key, value] of Object.entries(snapshot.metrics)) { lines.push(`# HELP security_${key} ${key} metric`); lines.push(`# TYPE security_${key} gauge`); lines.push(`security_${key} ${value}`); } return lines.join('\n'); } } exports.PerformanceMonitor = PerformanceMonitor; // Circuit breaker implementation class CircuitBreaker { constructor(name, config) { this.name = name; this.config = config; this.failures = 0; this.lastFailureTime = 0; this.state = 'closed'; } recordResult(success, latency) { if (!success || latency > this.config.latencyThreshold) { this.failures++; this.lastFailureTime = Date.now(); if (this.failures >= this.config.failureThreshold) { this.state = 'open'; } } else if (this.state === 'half-open') { this.reset(); } // Check if we should move to half-open if (this.state === 'open' && Date.now() - this.lastFailureTime > this.config.resetTimeout) { this.state = 'half-open'; } } isOpen() { return this.state === 'open'; } getFailureReason() { return `Circuit breaker open: ${this.failures} failures detected`; } reset() { this.failures = 0; this.state = 'closed'; } } //# sourceMappingURL=performance-monitor.js.map