implement uptime

pull/6/head
LouisLam 2021-07-01 13:11:16 +08:00
parent 82afddcfd6
commit 84c21b71c0
7 changed files with 145 additions and 49 deletions

View File

@ -20,7 +20,7 @@ class Monitor extends BeanModel {
id: this.id,
name: this.name,
url: this.url,
upRate: this.upRate,
weight: this.weight,
active: this.active,
type: this.type,
interval: this.interval,
@ -91,15 +91,20 @@ class Monitor extends BeanModel {
static async sendStats(io, monitorID, userID) {
Monitor.sendAvgPing(24, io, monitorID, userID);
//Monitor.sendUptime(24, io, this.id);
//Monitor.sendUptime(24 * 30, io, this.id);
Monitor.sendUptime(24, io, monitorID, userID);
Monitor.sendUptime(24 * 30, io, monitorID, userID);
}
/**
*
* @param duration : int Hours
*/
static async sendAvgPing(duration, io, monitorID, userID) {
let avgPing = parseInt(await R.getCell(`
SELECT AVG(ping)
FROM heartbeat
WHERE time > DATE('now', ? || ' hours')
AND ping IS NOT NULL
AND monitor_id = ? `, [
-duration,
monitorID
@ -108,8 +113,25 @@ class Monitor extends BeanModel {
io.to(userID).emit("avgPing", monitorID, avgPing);
}
sendUptime(duration) {
/**
*
* @param duration : int Hours
*/
static async sendUptime(duration, io, monitorID, userID) {
let downtime = parseInt(await R.getCell(`
SELECT SUM(duration)
FROM heartbeat
WHERE time > DATE('now', ? || ' hours')
AND status = 0
AND monitor_id = ? `, [
-duration,
monitorID
]));
let sec = duration * 3600;
let uptime = (sec - downtime) / sec;
io.to(userID).emit("uptime", monitorID, duration, uptime);
}
}

View File

@ -340,7 +340,7 @@ async function afterLogin(socket, user) {
async function getMonitorJSONList(userID) {
let result = {};
let monitorList = await R.find("monitor", " user_id = ? ORDER BY active DESC, name ASC ", [
let monitorList = await R.find("monitor", " user_id = ? ", [
userID
])

View File

@ -18,9 +18,6 @@ export default {
computed: {
displayText() {
console.log(dayjs.tz.guess())
return this.value
},
}

61
src/components/Uptime.vue Normal file
View File

@ -0,0 +1,61 @@
<template>
<span :class="className">{{ uptime }}</span>
</template>
<script>
export default {
props: {
monitor : Object,
type: String,
pill: {
Boolean,
default: false,
},
},
computed: {
uptime() {
let key = this.monitor.id + "_" + this.type;
if (this.$root.uptimeList[key]) {
return Math.round(this.$root.uptimeList[key] * 10000) / 100 + "%";
} else {
return "N/A"
}
},
color() {
if (this.lastHeartBeat.status === 0) {
return "danger"
} else if (this.lastHeartBeat.status === 1) {
return "primary"
} else {
return "secondary"
}
},
lastHeartBeat() {
if (this.monitor.id in this.$root.lastHeartbeatList && this.$root.lastHeartbeatList[this.monitor.id]) {
return this.$root.lastHeartbeatList[this.monitor.id]
} else {
return { status: -1 }
}
},
className() {
if (this.pill) {
return `badge rounded-pill bg-${this.color}`;
} else {
return "";
}
},
},
}
</script>
<style scoped>
</style>

View File

@ -17,18 +17,11 @@ export default {
},
allowLoginDialog: false, // Allowed to show login dialog, but "loggedIn" have to be true too. This exists because prevent the login dialog show 0.1s in first before the socket server auth-ed.
loggedIn: false,
monitorList: [
],
heartbeatList: {
},
importantHeartbeatList: {
},
avgPingList: {
}
monitorList: { },
heartbeatList: { },
importantHeartbeatList: { },
avgPingList: { },
uptimeList: { }
}
},
@ -85,6 +78,10 @@ export default {
this.avgPingList[monitorID] = data
});
socket.on('uptime', (monitorID, type, data) => {
this.uptimeList[`${monitorID}_${type}`] = data
});
socket.on('importantHeartbeatList', (monitorID, data) => {
if (! (monitorID in this.importantHeartbeatList)) {
this.importantHeartbeatList[monitorID] = data;

View File

@ -11,18 +11,18 @@
<span v-if="$root.monitorList.length === 0">No Monitors, please <router-link to="/add">add one</router-link>.</span>
<router-link :to="monitorURL(item.id)" class="item" :class="{ 'disabled': ! item.active }" v-for="item in $root.monitorList">
<router-link :to="monitorURL(item.id)" class="item" :class="{ 'disabled': ! item.active }" v-for="item in sortedMonitorList">
<div class="row">
<div class="col-6">
<div class="col-6 col-md-8 small-padding">
<div class="info">
<span class="badge rounded-pill bg-primary">{{ item.upRate }}%</span>
<Uptime :monitor="item" type="24" :pill="true" />
{{ item.name }}
</div>
</div>
<div class="col-6">
<div class="col-6 col-md-4">
<HeartbeatBar size="small" :monitor-id="item.id" />
</div>
</div>
@ -42,15 +42,49 @@
<script>
import HeartbeatBar from "../components/HeartbeatBar.vue";
import Uptime from "../components/Uptime.vue";
export default {
components: {
Uptime,
HeartbeatBar
},
data() {
return {
}
},
computed: {
sortedMonitorList() {
let result = Object.values(this.$root.monitorList);
result.sort((m1, m2) => {
if (m1.active !== m2.active) {
if (m1.active === 0) {
return 1;
}
if (m2.active === 0) {
return -1;
}
}
if (m1.weight !== m2.weight) {
if (m1.weight > m2.weight) {
return -1;
}
if (m1.weight < m2.weight) {
return 1;
}
}
return m1.name.localeCompare(m2.name);
})
return result;
},
},
methods: {
monitorURL(id) {
return "/dashboard/" + id;
@ -98,29 +132,13 @@ export default {
}
}
.hp-bar {
white-space: nowrap;
margin-top: 4px;
text-align: right;
.badge {
min-width: 58px;
}
div {
display: inline-block;
background-color: $primary;
width: 0.35rem;
height: 1rem;
margin: 0.15rem;
border-radius: 50rem;
transition: all ease-in-out 0.15s;
&.empty {
background-color: aliceblue;
}
&:hover {
opacity: 0.8;
transform: scale(1.5);
}
}
.small-padding {
padding-left: 5px !important;
padding-right: 5px !important;
}
</style>

View File

@ -36,12 +36,12 @@
<div class="col">
<h4>Uptime</h4>
<p>(24-hour)</p>
<span class="num"></span>
<span class="num"><Uptime :monitor="monitor" type="24" /></span>
</div>
<div class="col">
<h4>Uptime</h4>
<p>(30-day)</p>
<span class="num"></span>
<span class="num"><Uptime :monitor="monitor" type="720" /></span>
</div>
</div>
</div>
@ -86,9 +86,11 @@ import HeartbeatBar from "../components/HeartbeatBar.vue";
import Status from "../components/Status.vue";
import Datetime from "../components/Datetime.vue";
import CountUp from "../components/CountUp.vue";
import Uptime from "../components/Uptime.vue";
export default {
components: {
Uptime,
CountUp,
Datetime,
HeartbeatBar,
@ -233,7 +235,6 @@ table {
font-size: 14px;
tr {
--bs-table-accent-bg: white;
transition: all ease-in-out 0.2ms;
}
}