From 08ea84220670b9de29f371d48361bf852eb12608 Mon Sep 17 00:00:00 2001 From: nmemmert <67961292+nmemmert@users.noreply.github.com> Date: Wed, 10 Dec 2025 15:15:10 -0500 Subject: [PATCH] Add detailed emails with check type and recent performance graph --- server/notificationService.js | 78 ++++++++++++++++++++++++++++++++--- server/scheduler.js | 10 ++++- 2 files changed, 81 insertions(+), 7 deletions(-) diff --git a/server/notificationService.js b/server/notificationService.js index 4a3a0b4..565fdbf 100644 --- a/server/notificationService.js +++ b/server/notificationService.js @@ -48,15 +48,17 @@ class NotificationService { } } - async sendAlert(resource, incident) { - const message = incident.type === 'started' - ? `🔴 ${resource.name} is DOWN!\n\nURL: ${resource.url}\nTime: ${new Date().toLocaleString()}` - : `🟢 ${resource.name} is back UP!\n\nURL: ${resource.url}\nTime: ${new Date().toLocaleString()}`; + async sendAlert(resource, incident, stats = null) { + const isDown = incident.type === 'started'; + const statusEmoji = isDown ? '🔴' : '🟢'; + const statusText = isDown ? 'DOWN' : 'UP'; + + const message = `${statusEmoji} ${resource.name} is ${statusText}!\n\nURL: ${resource.url}\nCheck Type: ${resource.type || 'http'}\nTime: ${new Date().toLocaleString()}`; const promises = []; if (this.emailEnabled) { - promises.push(this.sendEmail(resource, message, incident.type)); + promises.push(this.sendEmail(resource, message, incident.type, stats)); } if (this.webhookEnabled) { @@ -66,18 +68,51 @@ class NotificationService { await Promise.allSettled(promises); } - async sendEmail(resource, message, type) { + async sendEmail(resource, message, type, stats = null) { if (!this.transporter) { console.error('Email config incomplete; skipping email'); return; } try { + let htmlContent = ` +
Resource: ${resource.name}
+Status: ${type === 'started' ? 'DOWN' : 'UP'}
+URL: ${resource.url}
+Check Type: ${resource.type || 'http'}
+Time: ${new Date().toLocaleString()}
+ `; + + if (stats) { + htmlContent += ` +Uptime: ${(stats.uptime * 100).toFixed(2)}%
+Avg Response Time: ${stats.avgResponseTime.toFixed(0)}ms
+Last Check: ${stats.lastCheck || 'Never'}
+ `; + + if (stats.recentChecks && stats.recentChecks.length > 0) { + const graph = this.generateAsciiGraph(stats.recentChecks); + htmlContent += ` +Recent Response Times (last 12 checks):
+${graph}
+ `;
+ }
+
+ htmlContent += `