Skip to content

Commit

Permalink
Add Overall Status and Uptime to DashboardHome
Browse files Browse the repository at this point in the history
- expand sended stats with sendAverageUptime(duration)
- Display 24h, 7d, 30d, 90d average uptime of all monitors
- Change Uptime.vue component to support displaying average uptime of all monitors

Issue louislam#312
  • Loading branch information
lucasra1 committed Sep 18, 2021
1 parent c3122a9 commit 5b1a869
Show file tree
Hide file tree
Showing 22 changed files with 581 additions and 8 deletions.
72 changes: 70 additions & 2 deletions server/model/monitor.js
Original file line number Diff line number Diff line change
Expand Up @@ -372,6 +372,10 @@ class Monitor extends BeanModel {
await Monitor.sendAvgPing(24, io, monitorID, userID);
await Monitor.sendUptime(24, io, monitorID, userID);
await Monitor.sendUptime(24 * 30, io, monitorID, userID);
await Monitor.sendAverageUptime(24, io, userID);
await Monitor.sendAverageUptime(24 * 7, io, userID);
await Monitor.sendAverageUptime(24 * 30, io, userID);
await Monitor.sendAverageUptime(24 * 90, io, userID);
await Monitor.sendCertInfo(io, monitorID, userID);
} else {
debug("No clients in the room, no need to send stats");
Expand Down Expand Up @@ -422,13 +426,14 @@ class Monitor extends BeanModel {

// Handle if heartbeat duration longer than the target duration
// e.g. If the last beat's duration is bigger that the 24hrs window, it will use the duration between the (beat time - window margin) (THEN case in SQL)
// JOIN is necessary, because heartbeat has still data of deleted monitors.
let result = await R.getRow(`
SELECT
-- SUM all duration, also trim off the beat out of time window
SUM(
CASE
WHEN (JULIANDAY(\`time\`) - JULIANDAY(?)) * 86400 < duration
THEN (JULIANDAY(\`time\`) - JULIANDAY(?)) * 86400
THEN (JULIANDAY(\`time\`) - JULIANDAY(?)) * 86400
ELSE duration
END
) AS total_duration,
Expand Down Expand Up @@ -468,14 +473,77 @@ class Monitor extends BeanModel {
} else {
// Handle new monitor with only one beat, because the beat's duration = 0
let status = parseInt(await R.getCell("SELECT `status` FROM heartbeat WHERE monitor_id = ?", [ monitorID ]));
console.log("here???" + status);
if (status === UP) {
uptime = 1;
}
}

io.to(userID).emit("uptime", monitorID, duration, uptime);
}

/**
* Average Uptime of all Monitors
* Calculation based on:
* https://www.uptrends.com/support/kb/reporting/calculation-of-uptime-and-downtime
* @param duration : int Hours
*/
static async sendAverageUptime(duration, io, userID) {
const timeLogger = new TimeLogger();

const startTime = R.isoDateTime(dayjs.utc().subtract(duration, "hour"));

// Handle if heartbeat duration longer than the target duration
// e.g. If the last beat's duration is bigger that the 24hrs window, it will use the duration between the (beat time - window margin) (THEN case in SQL)
let result = await R.getRow(`
SELECT
-- SUM all duration, also trim off the beat out of time window
SUM(
CASE
WHEN (JULIANDAY(\`time\`) - JULIANDAY(?)) * 86400 < duration
THEN (JULIANDAY(\`time\`) - JULIANDAY(?)) * 86400
ELSE duration
END
) AS total_duration,
-- SUM all uptime duration, also trim off the beat out of time window
SUM(
CASE
WHEN (status = 1)
THEN
CASE
WHEN (JULIANDAY(\`time\`) - JULIANDAY(?)) * 86400 < duration
THEN (JULIANDAY(\`time\`) - JULIANDAY(?)) * 86400
ELSE duration
END
END
) AS uptime_duration
FROM heartbeat
JOIN monitor on monitor.id == heartbeat.monitor_id
WHERE time > ?
`, [
startTime, startTime, startTime, startTime, startTime
]);

timeLogger.print(`[${duration}] sendAverageUptime`);

let totalDuration = result.total_duration;
let uptimeDuration = result.uptime_duration;
let uptime = 0;

if (totalDuration > 0) {
uptime = uptimeDuration / totalDuration;
if (uptime < 0) {
uptime = 0;
}

} else {
// Handle new monitor with only one beat, because the beat's duration = 0
let result = await R.getRow("SELECT SUM(`status`) AS up_monitor, COUNT(`status`) AS sum_monitor FROM heartbeat JOIN monitor on monitor.id == heartbeat.monitor_id");
uptime = result.up_monitor / result.sum_monitor;
}

io.to(userID).emit("average_uptime", duration, uptime);
}
}

module.exports = Monitor;
16 changes: 11 additions & 5 deletions src/components/Uptime.vue
Original file line number Diff line number Diff line change
Expand Up @@ -15,11 +15,17 @@ export default {
computed: {
uptime() {
// If monitor is not set, display average uptime of all monitors
if (this.monitor) {
let key = this.monitor.id + "_" + this.type;
let key = this.monitor.id + "_" + this.type;
if (this.$root.uptimeList[key] !== undefined) {
return Math.round(this.$root.uptimeList[key] * 10000) / 100 + "%";
if (this.$root.uptimeList[key] !== undefined) {
return Math.round(this.$root.uptimeList[key] * 10000) / 100 + "%";
}
} else {
if (this.$root.averageUptimeList[this.type] !== undefined) {
return Math.round(this.$root.averageUptimeList[this.type] * 10000) / 100 + "%";
}
}
return this.$t("notAvailableShort")
Expand All @@ -42,7 +48,7 @@ export default {
},
lastHeartBeat() {
if (this.monitor.id in this.$root.lastHeartbeatList && this.$root.lastHeartbeatList[this.monitor.id]) {
if (this.monitor && this.monitor.id in this.$root.lastHeartbeatList && this.$root.lastHeartbeatList[this.monitor.id]) {
return this.$root.lastHeartbeatList[this.monitor.id]
}
Expand Down
28 changes: 28 additions & 0 deletions src/languages/da-DK.js
Original file line number Diff line number Diff line change
Expand Up @@ -143,4 +143,32 @@ export default {
Token: "Token",
"Show URI": "Show URI",
"Clear all statistics": "Clear all Statistics",
retryCheckEverySecond: "Retry every {0} seconds.",
importHandleDescription: "Choose 'Skip existing' if you want to skip every monitor or notification with the same name. 'Overwrite' will delete every existing monitor and notification.",
confirmImportMsg: "Are you sure to import the backup? Please make sure you've selected the right import option.",
"Heartbeat Retry Interval": "Heartbeat Retry Interval",
"Import Backup": "Import Backup",
"Export Backup": "Export Backup",
"Skip existing": "Skip existing",
Overwrite: "Overwrite",
Options: "Options",
"Keep both": "Keep both",
Tags: "Tags",
"Add New below or Select...": "Add New below or Select...",
"Tag with this name already exist.": "Tag with this name already exist.",
"Tag with this value already exist.": "Tag with this value already exist.",
color: "color",
"value (optional)": "value (optional)",
Gray: "Gray",
Red: "Red",
Orange: "Orange",
Green: "Green",
Blue: "Blue",
Indigo: "Indigo",
Purple: "Purple",
Pink: "Pink",
"Search...": "Search...",
allMonitorsOperational: "All Systems operational",
notAllMonitorsOperational: "Not all systems operational",
overallUptime: "Overall uptime",
}
3 changes: 3 additions & 0 deletions src/languages/de-DE.js
Original file line number Diff line number Diff line change
Expand Up @@ -167,4 +167,7 @@ export default {
retryCheckEverySecond: "Versuche alle {0} Sekunden",
"Import Backup": "Import Backup",
"Export Backup": "Export Backup",
allMonitorsOperational: "Alle Systeme in Betrieb",
notAllMonitorsOperational: "Nicht alle Systeme in Betrieb",
overallUptime: "Durchschnittliche Verfügbarkeit",
}
3 changes: 3 additions & 0 deletions src/languages/en.js
Original file line number Diff line number Diff line change
Expand Up @@ -167,4 +167,7 @@ export default {
Purple: "Purple",
Pink: "Pink",
"Search...": "Search...",
allMonitorsOperational: "All systems operational",
notAllMonitorsOperational: "Not all systems operational",
overallUptime: "Overall uptime",
}
28 changes: 28 additions & 0 deletions src/languages/es-ES.js
Original file line number Diff line number Diff line change
Expand Up @@ -143,4 +143,32 @@ export default {
Token: "Token",
"Show URI": "Show URI",
"Clear all statistics": "Clear all Statistics",
retryCheckEverySecond: "Retry every {0} seconds.",
importHandleDescription: "Choose 'Skip existing' if you want to skip every monitor or notification with the same name. 'Overwrite' will delete every existing monitor and notification.",
confirmImportMsg: "Are you sure to import the backup? Please make sure you've selected the right import option.",
"Heartbeat Retry Interval": "Heartbeat Retry Interval",
"Import Backup": "Import Backup",
"Export Backup": "Export Backup",
"Skip existing": "Skip existing",
Overwrite: "Overwrite",
Options: "Options",
"Keep both": "Keep both",
Tags: "Tags",
"Add New below or Select...": "Add New below or Select...",
"Tag with this name already exist.": "Tag with this name already exist.",
"Tag with this value already exist.": "Tag with this value already exist.",
color: "color",
"value (optional)": "value (optional)",
Gray: "Gray",
Red: "Red",
Orange: "Orange",
Green: "Green",
Blue: "Blue",
Indigo: "Indigo",
Purple: "Purple",
Pink: "Pink",
"Search...": "Search...",
allMonitorsOperational: "All Systems operational",
notAllMonitorsOperational: "Not all systems operational",
overallUptime: "Overall uptime",
}
28 changes: 28 additions & 0 deletions src/languages/et-EE.js
Original file line number Diff line number Diff line change
Expand Up @@ -143,4 +143,32 @@ export default {
Token: "Token",
"Show URI": "Show URI",
"Clear all statistics": "Clear all Statistics",
retryCheckEverySecond: "Retry every {0} seconds.",
importHandleDescription: "Choose 'Skip existing' if you want to skip every monitor or notification with the same name. 'Overwrite' will delete every existing monitor and notification.",
confirmImportMsg: "Are you sure to import the backup? Please make sure you've selected the right import option.",
"Heartbeat Retry Interval": "Heartbeat Retry Interval",
"Import Backup": "Import Backup",
"Export Backup": "Export Backup",
"Skip existing": "Skip existing",
Overwrite: "Overwrite",
Options: "Options",
"Keep both": "Keep both",
Tags: "Tags",
"Add New below or Select...": "Add New below or Select...",
"Tag with this name already exist.": "Tag with this name already exist.",
"Tag with this value already exist.": "Tag with this value already exist.",
color: "color",
"value (optional)": "value (optional)",
Gray: "Gray",
Red: "Red",
Orange: "Orange",
Green: "Green",
Blue: "Blue",
Indigo: "Indigo",
Purple: "Purple",
Pink: "Pink",
"Search...": "Search...",
allMonitorsOperational: "All Systems operational",
notAllMonitorsOperational: "Not all systems operational",
overallUptime: "Overall uptime",
}
28 changes: 28 additions & 0 deletions src/languages/fr-FR.js
Original file line number Diff line number Diff line change
Expand Up @@ -143,4 +143,32 @@ export default {
Token: "Token",
"Show URI": "Show URI",
"Clear all statistics": "Clear all Statistics",
retryCheckEverySecond: "Retry every {0} seconds.",
importHandleDescription: "Choose 'Skip existing' if you want to skip every monitor or notification with the same name. 'Overwrite' will delete every existing monitor and notification.",
confirmImportMsg: "Are you sure to import the backup? Please make sure you've selected the right import option.",
"Heartbeat Retry Interval": "Heartbeat Retry Interval",
"Import Backup": "Import Backup",
"Export Backup": "Export Backup",
"Skip existing": "Skip existing",
Overwrite: "Overwrite",
Options: "Options",
"Keep both": "Keep both",
Tags: "Tags",
"Add New below or Select...": "Add New below or Select...",
"Tag with this name already exist.": "Tag with this name already exist.",
"Tag with this value already exist.": "Tag with this value already exist.",
color: "color",
"value (optional)": "value (optional)",
Gray: "Gray",
Red: "Red",
Orange: "Orange",
Green: "Green",
Blue: "Blue",
Indigo: "Indigo",
Purple: "Purple",
Pink: "Pink",
"Search...": "Search...",
allMonitorsOperational: "All Systems operational",
notAllMonitorsOperational: "Not all systems operational",
overallUptime: "Overall uptime",
}
13 changes: 13 additions & 0 deletions src/languages/it-IT.js
Original file line number Diff line number Diff line change
Expand Up @@ -158,4 +158,17 @@ export default {
Purple: "Viola",
Pink: "Rosa",
"Search...": "Cerca...",
retryCheckEverySecond: "Retry every {0} seconds.",
importHandleDescription: "Choose 'Skip existing' if you want to skip every monitor or notification with the same name. 'Overwrite' will delete every existing monitor and notification.",
confirmImportMsg: "Are you sure to import the backup? Please make sure you've selected the right import option.",
"Heartbeat Retry Interval": "Heartbeat Retry Interval",
"Import Backup": "Import Backup",
"Export Backup": "Export Backup",
"Skip existing": "Skip existing",
Overwrite: "Overwrite",
Options: "Options",
"Keep both": "Keep both",
allMonitorsOperational: "All Systems operational",
notAllMonitorsOperational: "Not all systems operational",
overallUptime: "Overall uptime",
}
28 changes: 28 additions & 0 deletions src/languages/ja.js
Original file line number Diff line number Diff line change
Expand Up @@ -143,4 +143,32 @@ export default {
Token: "Token",
"Show URI": "Show URI",
"Clear all statistics": "Clear all Statistics",
retryCheckEverySecond: "Retry every {0} seconds.",
importHandleDescription: "Choose 'Skip existing' if you want to skip every monitor or notification with the same name. 'Overwrite' will delete every existing monitor and notification.",
confirmImportMsg: "Are you sure to import the backup? Please make sure you've selected the right import option.",
"Heartbeat Retry Interval": "Heartbeat Retry Interval",
"Import Backup": "Import Backup",
"Export Backup": "Export Backup",
"Skip existing": "Skip existing",
Overwrite: "Overwrite",
Options: "Options",
"Keep both": "Keep both",
Tags: "Tags",
"Add New below or Select...": "Add New below or Select...",
"Tag with this name already exist.": "Tag with this name already exist.",
"Tag with this value already exist.": "Tag with this value already exist.",
color: "color",
"value (optional)": "value (optional)",
Gray: "Gray",
Red: "Red",
Orange: "Orange",
Green: "Green",
Blue: "Blue",
Indigo: "Indigo",
Purple: "Purple",
Pink: "Pink",
"Search...": "Search...",
allMonitorsOperational: "All Systems operational",
notAllMonitorsOperational: "Not all systems operational",
overallUptime: "Overall uptime",
}
28 changes: 28 additions & 0 deletions src/languages/ko-KR.js
Original file line number Diff line number Diff line change
Expand Up @@ -143,4 +143,32 @@ export default {
Token: "Token",
"Show URI": "Show URI",
"Clear all statistics": "Clear all Statistics",
retryCheckEverySecond: "Retry every {0} seconds.",
importHandleDescription: "Choose 'Skip existing' if you want to skip every monitor or notification with the same name. 'Overwrite' will delete every existing monitor and notification.",
confirmImportMsg: "Are you sure to import the backup? Please make sure you've selected the right import option.",
"Heartbeat Retry Interval": "Heartbeat Retry Interval",
"Import Backup": "Import Backup",
"Export Backup": "Export Backup",
"Skip existing": "Skip existing",
Overwrite: "Overwrite",
Options: "Options",
"Keep both": "Keep both",
Tags: "Tags",
"Add New below or Select...": "Add New below or Select...",
"Tag with this name already exist.": "Tag with this name already exist.",
"Tag with this value already exist.": "Tag with this value already exist.",
color: "color",
"value (optional)": "value (optional)",
Gray: "Gray",
Red: "Red",
Orange: "Orange",
Green: "Green",
Blue: "Blue",
Indigo: "Indigo",
Purple: "Purple",
Pink: "Pink",
"Search...": "Search...",
allMonitorsOperational: "All Systems operational",
notAllMonitorsOperational: "Not all systems operational",
overallUptime: "Overall uptime",
}
Loading

0 comments on commit 5b1a869

Please sign in to comment.