fix(monitoring): use a per-second ring buffer for DNS query metrics, improve DNS logging rate limiting and security event aggregation, and bump smartmta dependency
This commit is contained in:
@@ -162,8 +162,9 @@ export class SecurityLogger {
|
||||
}
|
||||
}
|
||||
|
||||
// Return most recent events up to limit
|
||||
// Return most recent events up to limit (slice first to avoid mutating source)
|
||||
return filteredEvents
|
||||
.slice()
|
||||
.sort((a, b) => b.timestamp - a.timestamp)
|
||||
.slice(0, limit);
|
||||
}
|
||||
@@ -249,58 +250,46 @@ export class SecurityLogger {
|
||||
topIPs: Array<{ ip: string; count: number }>;
|
||||
topDomains: Array<{ domain: string; count: number }>;
|
||||
} {
|
||||
// Filter by time window if provided
|
||||
let events = this.securityEvents;
|
||||
if (timeWindow) {
|
||||
const cutoff = Date.now() - timeWindow;
|
||||
events = events.filter(e => e.timestamp >= cutoff);
|
||||
const cutoff = timeWindow ? Date.now() - timeWindow : 0;
|
||||
|
||||
// Initialize counters
|
||||
const byLevel = {} as Record<SecurityLogLevel, number>;
|
||||
for (const level of Object.values(SecurityLogLevel)) {
|
||||
byLevel[level] = 0;
|
||||
}
|
||||
const byType = {} as Record<SecurityEventType, number>;
|
||||
for (const type of Object.values(SecurityEventType)) {
|
||||
byType[type] = 0;
|
||||
}
|
||||
|
||||
// Count by level
|
||||
const byLevel = Object.values(SecurityLogLevel).reduce((acc, level) => {
|
||||
acc[level] = events.filter(e => e.level === level).length;
|
||||
return acc;
|
||||
}, {} as Record<SecurityLogLevel, number>);
|
||||
|
||||
// Count by type
|
||||
const byType = Object.values(SecurityEventType).reduce((acc, type) => {
|
||||
acc[type] = events.filter(e => e.type === type).length;
|
||||
return acc;
|
||||
}, {} as Record<SecurityEventType, number>);
|
||||
|
||||
// Count by IP
|
||||
const ipCounts = new Map<string, number>();
|
||||
events.forEach(e => {
|
||||
const domainCounts = new Map<string, number>();
|
||||
|
||||
// Single pass over all events
|
||||
let total = 0;
|
||||
for (const e of this.securityEvents) {
|
||||
if (cutoff && e.timestamp < cutoff) continue;
|
||||
total++;
|
||||
byLevel[e.level]++;
|
||||
byType[e.type]++;
|
||||
if (e.ipAddress) {
|
||||
ipCounts.set(e.ipAddress, (ipCounts.get(e.ipAddress) || 0) + 1);
|
||||
}
|
||||
});
|
||||
|
||||
// Count by domain
|
||||
const domainCounts = new Map<string, number>();
|
||||
events.forEach(e => {
|
||||
if (e.domain) {
|
||||
domainCounts.set(e.domain, (domainCounts.get(e.domain) || 0) + 1);
|
||||
}
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
// Sort and limit top entries
|
||||
const topIPs = Array.from(ipCounts.entries())
|
||||
.map(([ip, count]) => ({ ip, count }))
|
||||
.sort((a, b) => b.count - a.count)
|
||||
.slice(0, 10);
|
||||
|
||||
|
||||
const topDomains = Array.from(domainCounts.entries())
|
||||
.map(([domain, count]) => ({ domain, count }))
|
||||
.sort((a, b) => b.count - a.count)
|
||||
.slice(0, 10);
|
||||
|
||||
return {
|
||||
total: events.length,
|
||||
byLevel,
|
||||
byType,
|
||||
topIPs,
|
||||
topDomains
|
||||
};
|
||||
|
||||
return { total, byLevel, byType, topIPs, topDomains };
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user