|
|
@ -12,7 +12,6 @@ class UptimeCalculator {
|
|
|
|
* @private
|
|
|
|
* @private
|
|
|
|
* @type {{string:UptimeCalculator}}
|
|
|
|
* @type {{string:UptimeCalculator}}
|
|
|
|
*/
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
|
|
static list = {};
|
|
|
|
static list = {};
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
/**
|
|
|
@ -55,6 +54,15 @@ class UptimeCalculator {
|
|
|
|
lastHourlyStatBean = null;
|
|
|
|
lastHourlyStatBean = null;
|
|
|
|
lastMinutelyStatBean = null;
|
|
|
|
lastMinutelyStatBean = null;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
|
|
* For migration purposes.
|
|
|
|
|
|
|
|
* @type {boolean}
|
|
|
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
migrationMode = false;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
statMinutelyKeepHour = 24;
|
|
|
|
|
|
|
|
statHourlyKeepDay = 30;
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
/**
|
|
|
|
* Get the uptime calculator for a monitor
|
|
|
|
* Get the uptime calculator for a monitor
|
|
|
|
* Initializes and returns the monitor if it does not exist
|
|
|
|
* Initializes and returns the monitor if it does not exist
|
|
|
@ -189,16 +197,19 @@ class UptimeCalculator {
|
|
|
|
/**
|
|
|
|
/**
|
|
|
|
* @param {number} status status
|
|
|
|
* @param {number} status status
|
|
|
|
* @param {number} ping Ping
|
|
|
|
* @param {number} ping Ping
|
|
|
|
|
|
|
|
* @param {dayjs.Dayjs} date Date (Only for migration)
|
|
|
|
* @returns {dayjs.Dayjs} date
|
|
|
|
* @returns {dayjs.Dayjs} date
|
|
|
|
* @throws {Error} Invalid status
|
|
|
|
* @throws {Error} Invalid status
|
|
|
|
*/
|
|
|
|
*/
|
|
|
|
async update(status, ping = 0) {
|
|
|
|
async update(status, ping = 0, date) {
|
|
|
|
let date = this.getCurrentDate();
|
|
|
|
if (!date) {
|
|
|
|
|
|
|
|
date = this.getCurrentDate();
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
let flatStatus = this.flatStatus(status);
|
|
|
|
let flatStatus = this.flatStatus(status);
|
|
|
|
|
|
|
|
|
|
|
|
if (flatStatus === DOWN && ping > 0) {
|
|
|
|
if (flatStatus === DOWN && ping > 0) {
|
|
|
|
log.warn("uptime-calc", "The ping is not effective when the status is DOWN");
|
|
|
|
log.debug("uptime-calc", "The ping is not effective when the status is DOWN");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
let divisionKey = this.getMinutelyKey(date);
|
|
|
|
let divisionKey = this.getMinutelyKey(date);
|
|
|
@ -297,47 +308,61 @@ class UptimeCalculator {
|
|
|
|
}
|
|
|
|
}
|
|
|
|
await R.store(dailyStatBean);
|
|
|
|
await R.store(dailyStatBean);
|
|
|
|
|
|
|
|
|
|
|
|
let hourlyStatBean = await this.getHourlyStatBean(hourlyKey);
|
|
|
|
let currentDate = this.getCurrentDate();
|
|
|
|
hourlyStatBean.up = hourlyData.up;
|
|
|
|
|
|
|
|
hourlyStatBean.down = hourlyData.down;
|
|
|
|
// For migration mode, we don't need to store old hourly and minutely data, but we need 30-day's hourly data
|
|
|
|
hourlyStatBean.ping = hourlyData.avgPing;
|
|
|
|
// Run anyway for non-migration mode
|
|
|
|
hourlyStatBean.pingMin = hourlyData.minPing;
|
|
|
|
if (!this.migrationMode || date.isAfter(currentDate.subtract(this.statHourlyKeepDay, "day"))) {
|
|
|
|
hourlyStatBean.pingMax = hourlyData.maxPing;
|
|
|
|
let hourlyStatBean = await this.getHourlyStatBean(hourlyKey);
|
|
|
|
{
|
|
|
|
hourlyStatBean.up = hourlyData.up;
|
|
|
|
// eslint-disable-next-line no-unused-vars
|
|
|
|
hourlyStatBean.down = hourlyData.down;
|
|
|
|
const { up, down, avgPing, minPing, maxPing, timestamp, ...extras } = hourlyData;
|
|
|
|
hourlyStatBean.ping = hourlyData.avgPing;
|
|
|
|
if (Object.keys(extras).length > 0) {
|
|
|
|
hourlyStatBean.pingMin = hourlyData.minPing;
|
|
|
|
hourlyStatBean.extras = JSON.stringify(extras);
|
|
|
|
hourlyStatBean.pingMax = hourlyData.maxPing;
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
// eslint-disable-next-line no-unused-vars
|
|
|
|
|
|
|
|
const { up, down, avgPing, minPing, maxPing, timestamp, ...extras } = hourlyData;
|
|
|
|
|
|
|
|
if (Object.keys(extras).length > 0) {
|
|
|
|
|
|
|
|
hourlyStatBean.extras = JSON.stringify(extras);
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
await R.store(hourlyStatBean);
|
|
|
|
await R.store(hourlyStatBean);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
let minutelyStatBean = await this.getMinutelyStatBean(divisionKey);
|
|
|
|
// For migration mode, we don't need to store old hourly and minutely data, but we need 24-hour's minutely data
|
|
|
|
minutelyStatBean.up = minutelyData.up;
|
|
|
|
// Run anyway for non-migration mode
|
|
|
|
minutelyStatBean.down = minutelyData.down;
|
|
|
|
if (!this.migrationMode || date.isAfter(currentDate.subtract(this.statMinutelyKeepHour, "hour"))) {
|
|
|
|
minutelyStatBean.ping = minutelyData.avgPing;
|
|
|
|
let minutelyStatBean = await this.getMinutelyStatBean(divisionKey);
|
|
|
|
minutelyStatBean.pingMin = minutelyData.minPing;
|
|
|
|
minutelyStatBean.up = minutelyData.up;
|
|
|
|
minutelyStatBean.pingMax = minutelyData.maxPing;
|
|
|
|
minutelyStatBean.down = minutelyData.down;
|
|
|
|
{
|
|
|
|
minutelyStatBean.ping = minutelyData.avgPing;
|
|
|
|
// eslint-disable-next-line no-unused-vars
|
|
|
|
minutelyStatBean.pingMin = minutelyData.minPing;
|
|
|
|
const { up, down, avgPing, minPing, maxPing, timestamp, ...extras } = minutelyData;
|
|
|
|
minutelyStatBean.pingMax = minutelyData.maxPing;
|
|
|
|
if (Object.keys(extras).length > 0) {
|
|
|
|
{
|
|
|
|
minutelyStatBean.extras = JSON.stringify(extras);
|
|
|
|
// eslint-disable-next-line no-unused-vars
|
|
|
|
|
|
|
|
const { up, down, avgPing, minPing, maxPing, timestamp, ...extras } = minutelyData;
|
|
|
|
|
|
|
|
if (Object.keys(extras).length > 0) {
|
|
|
|
|
|
|
|
minutelyStatBean.extras = JSON.stringify(extras);
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
await R.store(minutelyStatBean);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
await R.store(minutelyStatBean);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Remove the old data
|
|
|
|
// No need to remove old data in migration mode
|
|
|
|
log.debug("uptime-calc", "Remove old data");
|
|
|
|
if (!this.migrationMode) {
|
|
|
|
await R.exec("DELETE FROM stat_minutely WHERE monitor_id = ? AND timestamp < ?", [
|
|
|
|
// Remove the old data
|
|
|
|
this.monitorID,
|
|
|
|
// TODO: Improvement: Convert it to a job?
|
|
|
|
this.getMinutelyKey(date.subtract(24, "hour")),
|
|
|
|
log.debug("uptime-calc", "Remove old data");
|
|
|
|
]);
|
|
|
|
await R.exec("DELETE FROM stat_minutely WHERE monitor_id = ? AND timestamp < ?", [
|
|
|
|
|
|
|
|
this.monitorID,
|
|
|
|
|
|
|
|
this.getMinutelyKey(currentDate.subtract(this.statMinutelyKeepHour, "hour")),
|
|
|
|
|
|
|
|
]);
|
|
|
|
|
|
|
|
|
|
|
|
await R.exec("DELETE FROM stat_hourly WHERE monitor_id = ? AND timestamp < ?", [
|
|
|
|
await R.exec("DELETE FROM stat_hourly WHERE monitor_id = ? AND timestamp < ?", [
|
|
|
|
this.monitorID,
|
|
|
|
this.monitorID,
|
|
|
|
this.getHourlyKey(date.subtract(30, "day")),
|
|
|
|
this.getHourlyKey(currentDate.subtract(this.statHourlyKeepDay, "day")),
|
|
|
|
]);
|
|
|
|
]);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
return date;
|
|
|
|
return date;
|
|
|
|
}
|
|
|
|
}
|
|
|
@ -812,6 +837,14 @@ class UptimeCalculator {
|
|
|
|
return dayjs.utc();
|
|
|
|
return dayjs.utc();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
|
|
* For migration purposes.
|
|
|
|
|
|
|
|
* @param {boolean} value Migration mode on/off
|
|
|
|
|
|
|
|
* @returns {void}
|
|
|
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
setMigrationMode(value) {
|
|
|
|
|
|
|
|
this.migrationMode = value;
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
class UptimeDataResult {
|
|
|
|
class UptimeDataResult {
|
|
|
|