@iota-big3/sdk-security
Version:
Advanced security features including zero trust, quantum-safe crypto, and ML threat detection
366 lines • 14.7 kB
JavaScript
"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