2025-06-09 16:03:27 +00:00
|
|
|
import * as plugins from '../plugins.js';
|
|
|
|
import { DcRouter } from '../classes.dcrouter.js';
|
|
|
|
|
|
|
|
export class MetricsManager {
|
|
|
|
private logger: plugins.smartlog.Smartlog;
|
|
|
|
private smartMetrics: plugins.smartmetrics.SmartMetrics;
|
|
|
|
private dcRouter: DcRouter;
|
2025-06-09 17:18:50 +00:00
|
|
|
private resetInterval?: NodeJS.Timeout;
|
|
|
|
|
|
|
|
// Constants
|
|
|
|
private readonly MAX_TOP_DOMAINS = 1000; // Limit topDomains Map size
|
2025-06-09 16:03:27 +00:00
|
|
|
|
|
|
|
// Track email-specific metrics
|
|
|
|
private emailMetrics = {
|
|
|
|
sentToday: 0,
|
|
|
|
receivedToday: 0,
|
|
|
|
failedToday: 0,
|
|
|
|
bouncedToday: 0,
|
|
|
|
queueSize: 0,
|
|
|
|
lastResetDate: new Date().toDateString(),
|
2025-06-22 23:40:02 +00:00
|
|
|
deliveryTimes: [] as number[], // Track delivery times in ms
|
|
|
|
recipients: new Map<string, number>(), // Track email count by recipient
|
|
|
|
recentActivity: [] as Array<{ timestamp: number; type: string; details: string }>,
|
2025-06-09 16:03:27 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
// Track DNS-specific metrics
|
|
|
|
private dnsMetrics = {
|
|
|
|
totalQueries: 0,
|
|
|
|
cacheHits: 0,
|
|
|
|
cacheMisses: 0,
|
|
|
|
queryTypes: {} as Record<string, number>,
|
|
|
|
topDomains: new Map<string, number>(),
|
|
|
|
lastResetDate: new Date().toDateString(),
|
2025-06-22 23:40:02 +00:00
|
|
|
queryTimestamps: [] as number[], // Track query timestamps for rate calculation
|
|
|
|
responseTimes: [] as number[], // Track response times in ms
|
2025-06-09 16:03:27 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
// Track security-specific metrics
|
|
|
|
private securityMetrics = {
|
|
|
|
blockedIPs: 0,
|
|
|
|
authFailures: 0,
|
|
|
|
spamDetected: 0,
|
|
|
|
malwareDetected: 0,
|
|
|
|
phishingDetected: 0,
|
|
|
|
lastResetDate: new Date().toDateString(),
|
2025-06-22 23:40:02 +00:00
|
|
|
incidents: [] as Array<{ timestamp: number; type: string; severity: string; details: string }>,
|
2025-06-09 16:03:27 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
constructor(dcRouter: DcRouter) {
|
|
|
|
this.dcRouter = dcRouter;
|
|
|
|
// Create a new Smartlog instance for metrics
|
|
|
|
this.logger = new plugins.smartlog.Smartlog({
|
|
|
|
logContext: {
|
|
|
|
environment: 'production',
|
|
|
|
runtime: 'node',
|
|
|
|
zone: 'dcrouter-metrics',
|
|
|
|
}
|
|
|
|
});
|
|
|
|
this.smartMetrics = new plugins.smartmetrics.SmartMetrics(this.logger, 'dcrouter');
|
|
|
|
}
|
|
|
|
|
|
|
|
public async start(): Promise<void> {
|
|
|
|
// Start SmartMetrics collection
|
|
|
|
this.smartMetrics.start();
|
|
|
|
|
|
|
|
// Reset daily counters at midnight
|
2025-06-09 17:18:50 +00:00
|
|
|
this.resetInterval = setInterval(() => {
|
2025-06-09 16:03:27 +00:00
|
|
|
const currentDate = new Date().toDateString();
|
|
|
|
|
|
|
|
if (currentDate !== this.emailMetrics.lastResetDate) {
|
|
|
|
this.emailMetrics.sentToday = 0;
|
|
|
|
this.emailMetrics.receivedToday = 0;
|
|
|
|
this.emailMetrics.failedToday = 0;
|
|
|
|
this.emailMetrics.bouncedToday = 0;
|
2025-06-22 23:40:02 +00:00
|
|
|
this.emailMetrics.deliveryTimes = [];
|
|
|
|
this.emailMetrics.recipients.clear();
|
|
|
|
this.emailMetrics.recentActivity = [];
|
2025-06-09 16:03:27 +00:00
|
|
|
this.emailMetrics.lastResetDate = currentDate;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (currentDate !== this.dnsMetrics.lastResetDate) {
|
|
|
|
this.dnsMetrics.totalQueries = 0;
|
|
|
|
this.dnsMetrics.cacheHits = 0;
|
|
|
|
this.dnsMetrics.cacheMisses = 0;
|
|
|
|
this.dnsMetrics.queryTypes = {};
|
|
|
|
this.dnsMetrics.topDomains.clear();
|
2025-06-22 23:40:02 +00:00
|
|
|
this.dnsMetrics.queryTimestamps = [];
|
|
|
|
this.dnsMetrics.responseTimes = [];
|
2025-06-09 16:03:27 +00:00
|
|
|
this.dnsMetrics.lastResetDate = currentDate;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (currentDate !== this.securityMetrics.lastResetDate) {
|
|
|
|
this.securityMetrics.blockedIPs = 0;
|
|
|
|
this.securityMetrics.authFailures = 0;
|
|
|
|
this.securityMetrics.spamDetected = 0;
|
|
|
|
this.securityMetrics.malwareDetected = 0;
|
|
|
|
this.securityMetrics.phishingDetected = 0;
|
2025-06-22 23:40:02 +00:00
|
|
|
this.securityMetrics.incidents = [];
|
2025-06-09 16:03:27 +00:00
|
|
|
this.securityMetrics.lastResetDate = currentDate;
|
|
|
|
}
|
|
|
|
}, 60000); // Check every minute
|
|
|
|
|
|
|
|
this.logger.log('info', 'MetricsManager started');
|
|
|
|
}
|
|
|
|
|
|
|
|
public async stop(): Promise<void> {
|
2025-06-09 17:18:50 +00:00
|
|
|
// Clear the reset interval
|
|
|
|
if (this.resetInterval) {
|
|
|
|
clearInterval(this.resetInterval);
|
|
|
|
this.resetInterval = undefined;
|
|
|
|
}
|
|
|
|
|
2025-06-09 16:03:27 +00:00
|
|
|
this.smartMetrics.stop();
|
|
|
|
this.logger.log('info', 'MetricsManager stopped');
|
|
|
|
}
|
|
|
|
|
|
|
|
// Get server metrics from SmartMetrics and SmartProxy
|
|
|
|
public async getServerStats() {
|
|
|
|
const smartMetricsData = await this.smartMetrics.getMetrics();
|
2025-06-22 23:40:02 +00:00
|
|
|
const proxyMetrics = this.dcRouter.smartProxy ? this.dcRouter.smartProxy.getMetrics() : null;
|
|
|
|
const proxyStats = this.dcRouter.smartProxy ? this.dcRouter.smartProxy.getStatistics() : null;
|
2025-06-09 16:03:27 +00:00
|
|
|
|
|
|
|
return {
|
|
|
|
uptime: process.uptime(),
|
|
|
|
startTime: Date.now() - (process.uptime() * 1000),
|
|
|
|
memoryUsage: {
|
|
|
|
heapUsed: process.memoryUsage().heapUsed,
|
|
|
|
heapTotal: process.memoryUsage().heapTotal,
|
|
|
|
external: process.memoryUsage().external,
|
|
|
|
rss: process.memoryUsage().rss,
|
2025-06-12 11:22:18 +00:00
|
|
|
// Add SmartMetrics memory data
|
|
|
|
maxMemoryMB: this.smartMetrics.maxMemoryMB,
|
|
|
|
actualUsageBytes: smartMetricsData.memoryUsageBytes,
|
|
|
|
actualUsagePercentage: smartMetricsData.memoryPercentage,
|
2025-06-09 16:03:27 +00:00
|
|
|
},
|
|
|
|
cpuUsage: {
|
|
|
|
user: parseFloat(smartMetricsData.cpuUsageText || '0'),
|
|
|
|
system: 0, // SmartMetrics doesn't separate user/system
|
|
|
|
},
|
2025-06-22 23:40:02 +00:00
|
|
|
activeConnections: proxyStats ? proxyStats.activeConnections : 0,
|
|
|
|
totalConnections: proxyMetrics ? proxyMetrics.totals.connections() : 0,
|
|
|
|
requestsPerSecond: proxyMetrics ? proxyMetrics.requests.perSecond() : 0,
|
|
|
|
throughput: proxyMetrics ? {
|
|
|
|
bytesIn: proxyMetrics.totals.bytesIn(),
|
|
|
|
bytesOut: proxyMetrics.totals.bytesOut()
|
|
|
|
} : { bytesIn: 0, bytesOut: 0 },
|
2025-06-09 16:03:27 +00:00
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
// Get email metrics
|
|
|
|
public async getEmailStats() {
|
2025-06-22 23:40:02 +00:00
|
|
|
// Calculate average delivery time
|
|
|
|
const avgDeliveryTime = this.emailMetrics.deliveryTimes.length > 0
|
|
|
|
? this.emailMetrics.deliveryTimes.reduce((a, b) => a + b, 0) / this.emailMetrics.deliveryTimes.length
|
|
|
|
: 0;
|
|
|
|
|
|
|
|
// Get top recipients
|
|
|
|
const topRecipients = Array.from(this.emailMetrics.recipients.entries())
|
|
|
|
.sort((a, b) => b[1] - a[1])
|
|
|
|
.slice(0, 10)
|
|
|
|
.map(([email, count]) => ({ email, count }));
|
|
|
|
|
|
|
|
// Get recent activity (last 50 entries)
|
|
|
|
const recentActivity = this.emailMetrics.recentActivity.slice(-50);
|
|
|
|
|
2025-06-09 16:03:27 +00:00
|
|
|
return {
|
|
|
|
sentToday: this.emailMetrics.sentToday,
|
|
|
|
receivedToday: this.emailMetrics.receivedToday,
|
|
|
|
failedToday: this.emailMetrics.failedToday,
|
|
|
|
bounceRate: this.emailMetrics.bouncedToday > 0
|
|
|
|
? (this.emailMetrics.bouncedToday / this.emailMetrics.sentToday) * 100
|
|
|
|
: 0,
|
|
|
|
deliveryRate: this.emailMetrics.sentToday > 0
|
|
|
|
? ((this.emailMetrics.sentToday - this.emailMetrics.failedToday) / this.emailMetrics.sentToday) * 100
|
|
|
|
: 100,
|
|
|
|
queueSize: this.emailMetrics.queueSize,
|
2025-06-22 23:40:02 +00:00
|
|
|
averageDeliveryTime: Math.round(avgDeliveryTime),
|
|
|
|
topRecipients,
|
|
|
|
recentActivity,
|
2025-06-09 16:03:27 +00:00
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
// Get DNS metrics
|
|
|
|
public async getDnsStats() {
|
|
|
|
const cacheHitRate = this.dnsMetrics.totalQueries > 0
|
|
|
|
? (this.dnsMetrics.cacheHits / this.dnsMetrics.totalQueries) * 100
|
|
|
|
: 0;
|
|
|
|
|
|
|
|
const topDomains = Array.from(this.dnsMetrics.topDomains.entries())
|
|
|
|
.sort((a, b) => b[1] - a[1])
|
|
|
|
.slice(0, 10)
|
|
|
|
.map(([domain, count]) => ({ domain, count }));
|
|
|
|
|
2025-06-22 23:40:02 +00:00
|
|
|
// Calculate queries per second from recent timestamps
|
|
|
|
const now = Date.now();
|
|
|
|
const oneMinuteAgo = now - 60000;
|
|
|
|
const recentQueries = this.dnsMetrics.queryTimestamps.filter(ts => ts >= oneMinuteAgo);
|
|
|
|
const queriesPerSecond = recentQueries.length / 60;
|
|
|
|
|
|
|
|
// Calculate average response time
|
|
|
|
const avgResponseTime = this.dnsMetrics.responseTimes.length > 0
|
|
|
|
? this.dnsMetrics.responseTimes.reduce((a, b) => a + b, 0) / this.dnsMetrics.responseTimes.length
|
|
|
|
: 0;
|
|
|
|
|
2025-06-09 16:03:27 +00:00
|
|
|
return {
|
2025-06-22 23:40:02 +00:00
|
|
|
queriesPerSecond: Math.round(queriesPerSecond * 10) / 10,
|
2025-06-09 16:03:27 +00:00
|
|
|
totalQueries: this.dnsMetrics.totalQueries,
|
|
|
|
cacheHits: this.dnsMetrics.cacheHits,
|
|
|
|
cacheMisses: this.dnsMetrics.cacheMisses,
|
|
|
|
cacheHitRate: cacheHitRate,
|
|
|
|
topDomains: topDomains,
|
|
|
|
queryTypes: this.dnsMetrics.queryTypes,
|
2025-06-22 23:40:02 +00:00
|
|
|
averageResponseTime: Math.round(avgResponseTime),
|
2025-06-09 16:03:27 +00:00
|
|
|
activeDomains: this.dnsMetrics.topDomains.size,
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
// Get security metrics
|
|
|
|
public async getSecurityStats() {
|
2025-06-22 23:40:02 +00:00
|
|
|
// Get recent incidents (last 20)
|
|
|
|
const recentIncidents = this.securityMetrics.incidents.slice(-20);
|
|
|
|
|
2025-06-09 16:03:27 +00:00
|
|
|
return {
|
|
|
|
blockedIPs: this.securityMetrics.blockedIPs,
|
|
|
|
authFailures: this.securityMetrics.authFailures,
|
|
|
|
spamDetected: this.securityMetrics.spamDetected,
|
|
|
|
malwareDetected: this.securityMetrics.malwareDetected,
|
|
|
|
phishingDetected: this.securityMetrics.phishingDetected,
|
|
|
|
totalThreatsBlocked: this.securityMetrics.spamDetected +
|
|
|
|
this.securityMetrics.malwareDetected +
|
|
|
|
this.securityMetrics.phishingDetected,
|
2025-06-22 23:40:02 +00:00
|
|
|
recentIncidents,
|
2025-06-09 16:03:27 +00:00
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
// Get connection info from SmartProxy
|
|
|
|
public async getConnectionInfo() {
|
2025-06-22 23:40:02 +00:00
|
|
|
const proxyMetrics = this.dcRouter.smartProxy ? this.dcRouter.smartProxy.getMetrics() : null;
|
2025-06-09 16:03:27 +00:00
|
|
|
|
2025-06-22 23:40:02 +00:00
|
|
|
if (!proxyMetrics) {
|
2025-06-09 16:03:27 +00:00
|
|
|
return [];
|
|
|
|
}
|
|
|
|
|
2025-06-22 23:40:02 +00:00
|
|
|
const connectionsByRoute = proxyMetrics.connections.byRoute();
|
2025-06-09 16:03:27 +00:00
|
|
|
const connectionInfo = [];
|
|
|
|
|
|
|
|
for (const [routeName, count] of connectionsByRoute) {
|
|
|
|
connectionInfo.push({
|
|
|
|
type: 'https',
|
|
|
|
count,
|
|
|
|
source: routeName,
|
|
|
|
lastActivity: new Date(),
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
return connectionInfo;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Email event tracking methods
|
2025-06-22 23:40:02 +00:00
|
|
|
public trackEmailSent(recipient?: string, deliveryTimeMs?: number): void {
|
2025-06-09 16:03:27 +00:00
|
|
|
this.emailMetrics.sentToday++;
|
2025-06-22 23:40:02 +00:00
|
|
|
|
|
|
|
if (recipient) {
|
|
|
|
const count = this.emailMetrics.recipients.get(recipient) || 0;
|
|
|
|
this.emailMetrics.recipients.set(recipient, count + 1);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (deliveryTimeMs) {
|
|
|
|
this.emailMetrics.deliveryTimes.push(deliveryTimeMs);
|
|
|
|
// Keep only last 1000 delivery times
|
|
|
|
if (this.emailMetrics.deliveryTimes.length > 1000) {
|
|
|
|
this.emailMetrics.deliveryTimes.shift();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
this.emailMetrics.recentActivity.push({
|
|
|
|
timestamp: Date.now(),
|
|
|
|
type: 'sent',
|
|
|
|
details: recipient || 'unknown',
|
|
|
|
});
|
|
|
|
|
|
|
|
// Keep only last 1000 activities
|
|
|
|
if (this.emailMetrics.recentActivity.length > 1000) {
|
|
|
|
this.emailMetrics.recentActivity.shift();
|
|
|
|
}
|
2025-06-09 16:03:27 +00:00
|
|
|
}
|
|
|
|
|
2025-06-22 23:40:02 +00:00
|
|
|
public trackEmailReceived(sender?: string): void {
|
2025-06-09 16:03:27 +00:00
|
|
|
this.emailMetrics.receivedToday++;
|
2025-06-22 23:40:02 +00:00
|
|
|
|
|
|
|
this.emailMetrics.recentActivity.push({
|
|
|
|
timestamp: Date.now(),
|
|
|
|
type: 'received',
|
|
|
|
details: sender || 'unknown',
|
|
|
|
});
|
|
|
|
|
|
|
|
// Keep only last 1000 activities
|
|
|
|
if (this.emailMetrics.recentActivity.length > 1000) {
|
|
|
|
this.emailMetrics.recentActivity.shift();
|
|
|
|
}
|
2025-06-09 16:03:27 +00:00
|
|
|
}
|
|
|
|
|
2025-06-22 23:40:02 +00:00
|
|
|
public trackEmailFailed(recipient?: string, reason?: string): void {
|
2025-06-09 16:03:27 +00:00
|
|
|
this.emailMetrics.failedToday++;
|
2025-06-22 23:40:02 +00:00
|
|
|
|
|
|
|
this.emailMetrics.recentActivity.push({
|
|
|
|
timestamp: Date.now(),
|
|
|
|
type: 'failed',
|
|
|
|
details: `${recipient || 'unknown'}: ${reason || 'unknown error'}`,
|
|
|
|
});
|
|
|
|
|
|
|
|
// Keep only last 1000 activities
|
|
|
|
if (this.emailMetrics.recentActivity.length > 1000) {
|
|
|
|
this.emailMetrics.recentActivity.shift();
|
|
|
|
}
|
2025-06-09 16:03:27 +00:00
|
|
|
}
|
|
|
|
|
2025-06-22 23:40:02 +00:00
|
|
|
public trackEmailBounced(recipient?: string): void {
|
2025-06-09 16:03:27 +00:00
|
|
|
this.emailMetrics.bouncedToday++;
|
2025-06-22 23:40:02 +00:00
|
|
|
|
|
|
|
this.emailMetrics.recentActivity.push({
|
|
|
|
timestamp: Date.now(),
|
|
|
|
type: 'bounced',
|
|
|
|
details: recipient || 'unknown',
|
|
|
|
});
|
|
|
|
|
|
|
|
// Keep only last 1000 activities
|
|
|
|
if (this.emailMetrics.recentActivity.length > 1000) {
|
|
|
|
this.emailMetrics.recentActivity.shift();
|
|
|
|
}
|
2025-06-09 16:03:27 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
public updateQueueSize(size: number): void {
|
|
|
|
this.emailMetrics.queueSize = size;
|
|
|
|
}
|
|
|
|
|
|
|
|
// DNS event tracking methods
|
2025-06-22 23:40:02 +00:00
|
|
|
public trackDnsQuery(queryType: string, domain: string, cacheHit: boolean, responseTimeMs?: number): void {
|
2025-06-09 16:03:27 +00:00
|
|
|
this.dnsMetrics.totalQueries++;
|
|
|
|
|
|
|
|
if (cacheHit) {
|
|
|
|
this.dnsMetrics.cacheHits++;
|
|
|
|
} else {
|
|
|
|
this.dnsMetrics.cacheMisses++;
|
|
|
|
}
|
|
|
|
|
2025-06-22 23:40:02 +00:00
|
|
|
// Track query timestamp
|
|
|
|
this.dnsMetrics.queryTimestamps.push(Date.now());
|
|
|
|
|
|
|
|
// Keep only timestamps from last 5 minutes
|
|
|
|
const fiveMinutesAgo = Date.now() - 300000;
|
|
|
|
this.dnsMetrics.queryTimestamps = this.dnsMetrics.queryTimestamps.filter(ts => ts >= fiveMinutesAgo);
|
|
|
|
|
|
|
|
// Track response time if provided
|
|
|
|
if (responseTimeMs) {
|
|
|
|
this.dnsMetrics.responseTimes.push(responseTimeMs);
|
|
|
|
// Keep only last 1000 response times
|
|
|
|
if (this.dnsMetrics.responseTimes.length > 1000) {
|
|
|
|
this.dnsMetrics.responseTimes.shift();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2025-06-09 16:03:27 +00:00
|
|
|
// Track query types
|
|
|
|
this.dnsMetrics.queryTypes[queryType] = (this.dnsMetrics.queryTypes[queryType] || 0) + 1;
|
|
|
|
|
2025-06-09 17:18:50 +00:00
|
|
|
// Track top domains with size limit
|
2025-06-09 16:03:27 +00:00
|
|
|
const currentCount = this.dnsMetrics.topDomains.get(domain) || 0;
|
|
|
|
this.dnsMetrics.topDomains.set(domain, currentCount + 1);
|
2025-06-09 17:18:50 +00:00
|
|
|
|
|
|
|
// If we've exceeded the limit, remove the least accessed domains
|
|
|
|
if (this.dnsMetrics.topDomains.size > this.MAX_TOP_DOMAINS) {
|
|
|
|
// Convert to array, sort by count, and keep only top domains
|
|
|
|
const sortedDomains = Array.from(this.dnsMetrics.topDomains.entries())
|
|
|
|
.sort((a, b) => b[1] - a[1])
|
|
|
|
.slice(0, Math.floor(this.MAX_TOP_DOMAINS * 0.8)); // Keep 80% to avoid frequent cleanup
|
|
|
|
|
|
|
|
// Clear and repopulate with top domains
|
|
|
|
this.dnsMetrics.topDomains.clear();
|
|
|
|
sortedDomains.forEach(([domain, count]) => {
|
|
|
|
this.dnsMetrics.topDomains.set(domain, count);
|
|
|
|
});
|
|
|
|
}
|
2025-06-09 16:03:27 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Security event tracking methods
|
2025-06-22 23:40:02 +00:00
|
|
|
public trackBlockedIP(ip?: string, reason?: string): void {
|
2025-06-09 16:03:27 +00:00
|
|
|
this.securityMetrics.blockedIPs++;
|
2025-06-22 23:40:02 +00:00
|
|
|
|
|
|
|
this.securityMetrics.incidents.push({
|
|
|
|
timestamp: Date.now(),
|
|
|
|
type: 'ip_blocked',
|
|
|
|
severity: 'medium',
|
|
|
|
details: `IP ${ip || 'unknown'} blocked: ${reason || 'security policy'}`,
|
|
|
|
});
|
|
|
|
|
|
|
|
// Keep only last 1000 incidents
|
|
|
|
if (this.securityMetrics.incidents.length > 1000) {
|
|
|
|
this.securityMetrics.incidents.shift();
|
|
|
|
}
|
2025-06-09 16:03:27 +00:00
|
|
|
}
|
|
|
|
|
2025-06-22 23:40:02 +00:00
|
|
|
public trackAuthFailure(username?: string, ip?: string): void {
|
2025-06-09 16:03:27 +00:00
|
|
|
this.securityMetrics.authFailures++;
|
2025-06-22 23:40:02 +00:00
|
|
|
|
|
|
|
this.securityMetrics.incidents.push({
|
|
|
|
timestamp: Date.now(),
|
|
|
|
type: 'auth_failure',
|
|
|
|
severity: 'low',
|
|
|
|
details: `Authentication failed for ${username || 'unknown'} from ${ip || 'unknown'}`,
|
|
|
|
});
|
|
|
|
|
|
|
|
// Keep only last 1000 incidents
|
|
|
|
if (this.securityMetrics.incidents.length > 1000) {
|
|
|
|
this.securityMetrics.incidents.shift();
|
|
|
|
}
|
2025-06-09 16:03:27 +00:00
|
|
|
}
|
|
|
|
|
2025-06-22 23:40:02 +00:00
|
|
|
public trackSpamDetected(sender?: string): void {
|
2025-06-09 16:03:27 +00:00
|
|
|
this.securityMetrics.spamDetected++;
|
2025-06-22 23:40:02 +00:00
|
|
|
|
|
|
|
this.securityMetrics.incidents.push({
|
|
|
|
timestamp: Date.now(),
|
|
|
|
type: 'spam_detected',
|
|
|
|
severity: 'low',
|
|
|
|
details: `Spam detected from ${sender || 'unknown'}`,
|
|
|
|
});
|
|
|
|
|
|
|
|
// Keep only last 1000 incidents
|
|
|
|
if (this.securityMetrics.incidents.length > 1000) {
|
|
|
|
this.securityMetrics.incidents.shift();
|
|
|
|
}
|
2025-06-09 16:03:27 +00:00
|
|
|
}
|
|
|
|
|
2025-06-22 23:40:02 +00:00
|
|
|
public trackMalwareDetected(source?: string): void {
|
2025-06-09 16:03:27 +00:00
|
|
|
this.securityMetrics.malwareDetected++;
|
2025-06-22 23:40:02 +00:00
|
|
|
|
|
|
|
this.securityMetrics.incidents.push({
|
|
|
|
timestamp: Date.now(),
|
|
|
|
type: 'malware_detected',
|
|
|
|
severity: 'high',
|
|
|
|
details: `Malware detected from ${source || 'unknown'}`,
|
|
|
|
});
|
|
|
|
|
|
|
|
// Keep only last 1000 incidents
|
|
|
|
if (this.securityMetrics.incidents.length > 1000) {
|
|
|
|
this.securityMetrics.incidents.shift();
|
|
|
|
}
|
2025-06-09 16:03:27 +00:00
|
|
|
}
|
|
|
|
|
2025-06-22 23:40:02 +00:00
|
|
|
public trackPhishingDetected(source?: string): void {
|
2025-06-09 16:03:27 +00:00
|
|
|
this.securityMetrics.phishingDetected++;
|
2025-06-22 23:40:02 +00:00
|
|
|
|
|
|
|
this.securityMetrics.incidents.push({
|
|
|
|
timestamp: Date.now(),
|
|
|
|
type: 'phishing_detected',
|
|
|
|
severity: 'high',
|
|
|
|
details: `Phishing attempt from ${source || 'unknown'}`,
|
|
|
|
});
|
|
|
|
|
|
|
|
// Keep only last 1000 incidents
|
|
|
|
if (this.securityMetrics.incidents.length > 1000) {
|
|
|
|
this.securityMetrics.incidents.shift();
|
|
|
|
}
|
2025-06-09 16:03:27 +00:00
|
|
|
}
|
2025-06-20 10:56:53 +00:00
|
|
|
|
|
|
|
// Get network metrics from SmartProxy
|
|
|
|
public async getNetworkStats() {
|
2025-06-22 23:40:02 +00:00
|
|
|
const proxyMetrics = this.dcRouter.smartProxy ? this.dcRouter.smartProxy.getMetrics() : null;
|
2025-06-20 10:56:53 +00:00
|
|
|
|
2025-06-22 23:40:02 +00:00
|
|
|
if (!proxyMetrics) {
|
2025-06-20 10:56:53 +00:00
|
|
|
return {
|
|
|
|
connectionsByIP: new Map<string, number>(),
|
|
|
|
throughputRate: { bytesInPerSecond: 0, bytesOutPerSecond: 0 },
|
|
|
|
topIPs: [],
|
|
|
|
totalDataTransferred: { bytesIn: 0, bytesOut: 0 },
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
2025-06-22 23:40:02 +00:00
|
|
|
// Get metrics using the new API
|
|
|
|
const connectionsByIP = proxyMetrics.connections.byIP();
|
|
|
|
const instantThroughput = proxyMetrics.throughput.instant();
|
|
|
|
|
|
|
|
// Get throughput rate
|
|
|
|
const throughputRate = {
|
|
|
|
bytesInPerSecond: instantThroughput.in,
|
|
|
|
bytesOutPerSecond: instantThroughput.out
|
|
|
|
};
|
|
|
|
|
|
|
|
// Get top IPs
|
|
|
|
const topIPs = proxyMetrics.connections.topIPs(10);
|
|
|
|
|
|
|
|
// Get total data transferred
|
|
|
|
const totalDataTransferred = {
|
|
|
|
bytesIn: proxyMetrics.totals.bytesIn(),
|
|
|
|
bytesOut: proxyMetrics.totals.bytesOut()
|
|
|
|
};
|
2025-06-20 10:56:53 +00:00
|
|
|
|
|
|
|
return {
|
|
|
|
connectionsByIP,
|
|
|
|
throughputRate,
|
|
|
|
topIPs,
|
2025-06-22 23:40:02 +00:00
|
|
|
totalDataTransferred,
|
2025-06-20 10:56:53 +00:00
|
|
|
};
|
|
|
|
}
|
2025-06-09 16:03:27 +00:00
|
|
|
}
|