feat: Add enhanced Discord webhook alerts with timestamps and downtime duration

- Add 'Went Offline' timestamp using Discord's timestamp format (<t:timestamp:F>)
- Add 'Back Online' timestamp using Discord's timestamp format (<t:timestamp:F>)
- Add 'Downtime Duration' using Discord's relative timestamp format (<t:timestamp:R>)
- Query database for last DOWN heartbeat to calculate downtime duration

Resolves #5535
This commit is contained in:
0xsid0703 2026-01-15 19:39:39 +01:00
parent 2b2941cd83
commit 021af1233a

View File

@ -1,6 +1,7 @@
const NotificationProvider = require("./notification-provider");
const axios = require("axios");
const { DOWN, UP } = require("../../src/util");
const { R } = require("redbean-node");
class Discord extends NotificationProvider {
name = "discord";
@ -48,6 +49,11 @@ class Discord extends NotificationProvider {
// If heartbeatJSON is not null, we go into the normal alerting loop.
let addess = this.extractAddress(monitorJSON);
if (heartbeatJSON["status"] === DOWN) {
// Format timestamp for Discord using Discord's timestamp format
// <t:timestamp:format> where format is F for full date/time
const wentOfflineTimestamp = Math.floor(new Date(heartbeatJSON["time"]).getTime() / 1000);
const wentOfflineFormatted = `<t:${wentOfflineTimestamp}:F>`;
let discorddowndata = {
username: discordDisplayName,
embeds: [
@ -68,6 +74,10 @@ class Discord extends NotificationProvider {
},
]
: []),
{
name: "Went Offline",
value: wentOfflineFormatted,
},
{
name: `Time (${heartbeatJSON["timezone"]})`,
value: heartbeatJSON["localDateTime"],
@ -93,6 +103,35 @@ class Discord extends NotificationProvider {
await axios.post(webhookUrl.toString(), discorddowndata, config);
return okMsg;
} else if (heartbeatJSON["status"] === UP) {
// Format timestamp for Discord using Discord's timestamp format
const backOnlineTimestamp = Math.floor(new Date(heartbeatJSON["time"]).getTime() / 1000);
const backOnlineFormatted = `<t:${backOnlineTimestamp}:F>`;
// Calculate downtime duration by finding the last DOWN heartbeat
let downtimeDuration = null;
let wentOfflineFormatted = null;
try {
if (monitorJSON && monitorJSON.id) {
const lastDownHeartbeat = await R.getRow(
"SELECT time FROM heartbeat WHERE monitor_id = ? AND status = ? ORDER BY time DESC LIMIT 1",
[monitorJSON.id, DOWN]
);
if (lastDownHeartbeat && lastDownHeartbeat.time) {
const wentOfflineTimestamp = Math.floor(new Date(lastDownHeartbeat.time).getTime() / 1000);
wentOfflineFormatted = `<t:${wentOfflineTimestamp}:F>`;
// Calculate downtime duration in seconds
const downtimeSeconds = backOnlineTimestamp - wentOfflineTimestamp;
// Format as relative time using Discord's relative timestamp (R format)
downtimeDuration = `<t:${wentOfflineTimestamp}:R>`;
}
}
} catch (error) {
// If we can't calculate downtime, just continue without it
// Silently fail to avoid disrupting notification sending
}
let discordupdata = {
username: discordDisplayName,
embeds: [
@ -113,6 +152,26 @@ class Discord extends NotificationProvider {
},
]
: []),
{
name: "Back Online",
value: backOnlineFormatted,
},
...(wentOfflineFormatted
? [
{
name: "Went Offline",
value: wentOfflineFormatted,
},
]
: []),
...(downtimeDuration
? [
{
name: "Downtime Duration",
value: downtimeDuration,
},
]
: []),
{
name: `Time (${heartbeatJSON["timezone"]})`,
value: heartbeatJSON["localDateTime"],