49 lines
1.4 KiB
TypeScript
49 lines
1.4 KiB
TypeScript
import { appendFile } from 'fs/promises';
|
|
|
|
type AlertSeverity = 'info' | 'warn' | 'critical';
|
|
type AlertInstance = 'vijay' | 'bheem' | 'all';
|
|
|
|
interface DashboardWarningInput {
|
|
severity: AlertSeverity;
|
|
instance: AlertInstance;
|
|
message: string;
|
|
}
|
|
|
|
const DEDUPE_WINDOW_MS = 60 * 60 * 1000;
|
|
const recent = new Map<string, number>();
|
|
|
|
function severityToken(severity: AlertSeverity): string {
|
|
if (severity === 'critical') return 'CRITICAL';
|
|
if (severity === 'warn') return 'WARNING';
|
|
return 'INFO';
|
|
}
|
|
|
|
function alertKey(input: DashboardWarningInput): string {
|
|
return `${input.severity}\0${input.instance}\0${input.message}`;
|
|
}
|
|
|
|
function purgeExpired(now: number): void {
|
|
for (const [key, at] of recent) {
|
|
if (now - at > DEDUPE_WINDOW_MS) recent.delete(key);
|
|
}
|
|
}
|
|
|
|
export async function appendDashboardWarning(input: DashboardWarningInput, now = Date.now()): Promise<boolean> {
|
|
const logPath = process.env.HERMES_DASHBOARD_ALERT_LOG;
|
|
if (!logPath) return false;
|
|
|
|
purgeExpired(now);
|
|
const key = alertKey(input);
|
|
const previous = recent.get(key);
|
|
if (previous && now - previous <= DEDUPE_WINDOW_MS) return false;
|
|
|
|
recent.set(key, now);
|
|
const line = `${new Date(now).toISOString()} ${severityToken(input.severity)} instance=${input.instance} ${input.message}\n`;
|
|
await appendFile(logPath, line, 'utf8');
|
|
return true;
|
|
}
|
|
|
|
export function clearDashboardWarningDedupe(): void {
|
|
recent.clear();
|
|
}
|