mirror of
https://github.com/louislam/uptime-kuma.git
synced 2025-03-05 00:44:46 +00:00
Reimplement functionality from
https://github.com/louislam/uptime-kuma/pull/1878 with modern knex_migration
This commit is contained in:
parent
87b2e45fbf
commit
daacc2842e
5 changed files with 171 additions and 1 deletions
20
db/knex_migrations/2023-10-26-slow-response-notification.js
Normal file
20
db/knex_migrations/2023-10-26-slow-response-notification.js
Normal file
|
@ -0,0 +1,20 @@
|
||||||
|
exports.up = function (knex) {
|
||||||
|
// add various slow_response_notification parameters
|
||||||
|
return knex.schema
|
||||||
|
.alterTable("monitor", function(table) {
|
||||||
|
table.boolean("slow_response_notification").defaultTo(false);
|
||||||
|
table.integer("slow_response_notification_threshold").defaultTo(0);
|
||||||
|
table.integer("slow_response_notification_range").defaultTo(0);
|
||||||
|
table.string("slow_response_notification_method").defaultTo("");
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
exports.down = function (knex) {
|
||||||
|
return knex.schema
|
||||||
|
.alterTable("monitor", function(table) {
|
||||||
|
table.boolean("slow_response_notification").defaultTo(false);
|
||||||
|
table.integer("slow_response_notification_threshold").defaultTo(0);
|
||||||
|
table.integer("slow_response_notification_range").defaultTo(0);
|
||||||
|
table.string("slow_response_notification_method").defaultTo("");
|
||||||
|
});
|
||||||
|
}
|
|
@ -132,6 +132,10 @@ class Monitor extends BeanModel {
|
||||||
mqttSuccessMessage: this.mqttSuccessMessage,
|
mqttSuccessMessage: this.mqttSuccessMessage,
|
||||||
databaseQuery: this.databaseQuery,
|
databaseQuery: this.databaseQuery,
|
||||||
authMethod: this.authMethod,
|
authMethod: this.authMethod,
|
||||||
|
slowResponseNotification: this.isEnabledSlowResponseNotification(),
|
||||||
|
slowResponseNotificationThreshold: this.slowResponseNotificationThreshold,
|
||||||
|
slowResponseNotificationRange: this.slowResponseNotificationRange,
|
||||||
|
slowResponseNotificationMethod: this.slowResponseNotificationMethod,
|
||||||
grpcUrl: this.grpcUrl,
|
grpcUrl: this.grpcUrl,
|
||||||
grpcProtobuf: this.grpcProtobuf,
|
grpcProtobuf: this.grpcProtobuf,
|
||||||
grpcMethod: this.grpcMethod,
|
grpcMethod: this.grpcMethod,
|
||||||
|
@ -298,6 +302,14 @@ class Monitor extends BeanModel {
|
||||||
return Boolean(this.gamedigGivenPortOnly);
|
return Boolean(this.gamedigGivenPortOnly);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Is the slow response notification enabled?
|
||||||
|
* @returns {boolean}
|
||||||
|
*/
|
||||||
|
isEnabledSlowResponseNotification() {
|
||||||
|
return Boolean(this.slowResponseNotification);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Start monitor
|
* Start monitor
|
||||||
* @param {Server} io Socket server instance
|
* @param {Server} io Socket server instance
|
||||||
|
@ -938,6 +950,11 @@ class Monitor extends BeanModel {
|
||||||
log.debug("monitor", `[${this.name}] Store`);
|
log.debug("monitor", `[${this.name}] Store`);
|
||||||
await R.store(bean);
|
await R.store(bean);
|
||||||
|
|
||||||
|
if (this.isEnabledSlowResponseNotification()) {
|
||||||
|
log.debug("monitor", `[${this.name}] Check response is slow`);
|
||||||
|
await this.checkSlowResponseNotification(this);
|
||||||
|
}
|
||||||
|
|
||||||
log.debug("monitor", `[${this.name}] prometheus.update`);
|
log.debug("monitor", `[${this.name}] prometheus.update`);
|
||||||
this.prometheus?.update(bean, tlsInfo);
|
this.prometheus?.update(bean, tlsInfo);
|
||||||
|
|
||||||
|
@ -1375,6 +1392,71 @@ class Monitor extends BeanModel {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check heartbeat response time is slower than threshold.
|
||||||
|
* @param {Monitor} monitor The monitor to send a notification about
|
||||||
|
* @returns {Promise<void>}
|
||||||
|
*/
|
||||||
|
async checkSlowResponseNotification(monitor) {
|
||||||
|
|
||||||
|
//Get recent heartbeat list with range of time
|
||||||
|
const afterThisDate = new Date(Date.now() - (1000 * monitor.slowResponseNotificationRange));
|
||||||
|
const previousBeats = await R.getAll(`
|
||||||
|
SELECT * FROM heartbeat
|
||||||
|
WHERE monitor_id = ? AND time > datetime(?) AND status = ?`,
|
||||||
|
[
|
||||||
|
monitor.id,
|
||||||
|
afterThisDate.toISOString(),
|
||||||
|
UP,
|
||||||
|
]);
|
||||||
|
const method = monitor.slowResponseNotificationMethod;
|
||||||
|
const thresholdResponseTime = monitor.slowResponseNotificationThreshold;
|
||||||
|
let actualResponseTime = 0;
|
||||||
|
|
||||||
|
switch (method) {
|
||||||
|
case "average":
|
||||||
|
previousBeats.forEach(beat => {
|
||||||
|
actualResponseTime = actualResponseTime + beat.ping;
|
||||||
|
});
|
||||||
|
actualResponseTime = actualResponseTime / previousBeats.length;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case "max":
|
||||||
|
previousBeats.forEach(beat => {
|
||||||
|
actualResponseTime = Math.max(actualResponseTime, beat.ping);
|
||||||
|
});
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
log.error("monitor", `[${this.name}] Unknown slow response notification method ${method}`);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (actualResponseTime < thresholdResponseTime) {
|
||||||
|
log.debug("monitor", `[${this.name}] No need to send slow notification. ${actualResponseTime} < ${thresholdResponseTime}`);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
log.debug("monitor", `[${this.name}] Try to send slow response notification (${actualResponseTime} > ${thresholdResponseTime})`);
|
||||||
|
|
||||||
|
const notificationList = await Monitor.getNotificationList(monitor);
|
||||||
|
|
||||||
|
if (notificationList.length > 0) {
|
||||||
|
for (let notification of notificationList) {
|
||||||
|
try {
|
||||||
|
log.debug("monitor", `[${this.name}] Sending to ${notification.name}`);
|
||||||
|
await Notification.send(JSON.parse(notification.config), `[${this.name}] Responding slowly (${actualResponseTime}ms > ${thresholdResponseTime}ms)`);
|
||||||
|
} catch (e) {
|
||||||
|
log.error("monitor", `[${this.name}] Cannot send slow response notification to ${notification.name}`);
|
||||||
|
log.error("monitor", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} else {
|
||||||
|
log.debug("monitor", `[${this.name}] No notification, no need to send slow response notification`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the status of the previous heartbeat
|
* Get the status of the previous heartbeat
|
||||||
* @param {number} monitorID ID of monitor to check
|
* @param {number} monitorID ID of monitor to check
|
||||||
|
|
|
@ -43,7 +43,8 @@ log.debug("server", "Arguments");
|
||||||
log.debug("server", args);
|
log.debug("server", args);
|
||||||
|
|
||||||
if (! process.env.NODE_ENV) {
|
if (! process.env.NODE_ENV) {
|
||||||
process.env.NODE_ENV = "production";
|
// process.env.NODE_ENV = "production";
|
||||||
|
process.env.NODE_ENV = "development";
|
||||||
}
|
}
|
||||||
|
|
||||||
log.info("server", "Env: " + process.env.NODE_ENV);
|
log.info("server", "Env: " + process.env.NODE_ENV);
|
||||||
|
@ -803,6 +804,10 @@ let needSetup = false;
|
||||||
bean.authMethod = monitor.authMethod;
|
bean.authMethod = monitor.authMethod;
|
||||||
bean.authWorkstation = monitor.authWorkstation;
|
bean.authWorkstation = monitor.authWorkstation;
|
||||||
bean.authDomain = monitor.authDomain;
|
bean.authDomain = monitor.authDomain;
|
||||||
|
bean.slowResponseNotification = monitor.slowResponseNotification;
|
||||||
|
bean.slowResponseNotificationThreshold = monitor.slowResponseNotificationThreshold;
|
||||||
|
bean.slowResponseNotificationRange = monitor.slowResponseNotificationRange;
|
||||||
|
bean.slowResponseNotificationMethod = monitor.slowResponseNotificationMethod;
|
||||||
bean.grpcUrl = monitor.grpcUrl;
|
bean.grpcUrl = monitor.grpcUrl;
|
||||||
bean.grpcProtobuf = monitor.grpcProtobuf;
|
bean.grpcProtobuf = monitor.grpcProtobuf;
|
||||||
bean.grpcServiceName = monitor.grpcServiceName;
|
bean.grpcServiceName = monitor.grpcServiceName;
|
||||||
|
|
|
@ -485,6 +485,18 @@
|
||||||
"uninstall": "Uninstall",
|
"uninstall": "Uninstall",
|
||||||
"uninstalling": "Uninstalling",
|
"uninstalling": "Uninstalling",
|
||||||
"confirmUninstallPlugin": "Are you sure want to uninstall this plugin?",
|
"confirmUninstallPlugin": "Are you sure want to uninstall this plugin?",
|
||||||
|
"slowResponseNotification": "Slow Response Notification",
|
||||||
|
"slowResponseNotificationUse": "Use Slow Response Notification",
|
||||||
|
"slowResponseNotificationUseDescription": "When response time is slow, notify.",
|
||||||
|
"slowResponseNotificationThreshold": "Threshold (ms)",
|
||||||
|
"slowResponseNotificationThresholdDescription": "If response time greater than {0} ms, notify.",
|
||||||
|
"slowResponseNotificationRange": "Time Range (seconds)",
|
||||||
|
"slowResponseNotificationRangeDescription": "Gets the heartbeat information for the last {0} seconds and calculates the condition.",
|
||||||
|
"slowResponseNotificationMethod": "Calculation Method",
|
||||||
|
"slowResponseNotificationMethodAverage": "Average",
|
||||||
|
"slowResponseNotificationMethodAverageDescription": "Get the average response time of the last {0} seconds.",
|
||||||
|
"slowResponseNotificationMethodMax": "Max",
|
||||||
|
"slowResponseNotificationMethodMaxDescription": "Get the max response time of the last {0} seconds.",
|
||||||
"notificationRegional": "Regional",
|
"notificationRegional": "Regional",
|
||||||
"Clone Monitor": "Clone Monitor",
|
"Clone Monitor": "Clone Monitor",
|
||||||
"Clone": "Clone",
|
"Clone": "Clone",
|
||||||
|
|
|
@ -418,6 +418,53 @@
|
||||||
<input id="resend-interval" v-model="monitor.resendInterval" type="number" class="form-control" required min="0" step="1">
|
<input id="resend-interval" v-model="monitor.resendInterval" type="number" class="form-control" required min="0" step="1">
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<h2 class="mt-5 mb-2">{{ $t("slowResponseNotification") }}</h2>
|
||||||
|
|
||||||
|
<div class="my-3 form-check">
|
||||||
|
<input id="slow-response-notification" v-model="monitor.slowResponseNotification" class="form-check-input" type="checkbox">
|
||||||
|
<label class="form-check-label" for="slow-response-notification">
|
||||||
|
{{ $t("slowResponseNotificationUse") }}
|
||||||
|
</label>
|
||||||
|
<div class="form-text">
|
||||||
|
{{ $t("slowResponseNotificationUseDescription") }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Method -->
|
||||||
|
<div v-if="monitor.slowResponseNotification" class="my-3">
|
||||||
|
<label for="method" class="form-label">{{ $t("slowResponseNotificationMethod") }}</label>
|
||||||
|
<select id="method" v-model="monitor.slowResponseNotificationMethod" class="form-select">
|
||||||
|
<option value="average">
|
||||||
|
{{ $t("slowResponseNotificationMethodAverage") }}
|
||||||
|
</option>
|
||||||
|
<option value="max">
|
||||||
|
{{ $t("slowResponseNotificationMethodMax") }}
|
||||||
|
</option>
|
||||||
|
</select>
|
||||||
|
<div v-if="monitor.slowResponseNotificationMethod === 'average'" class="form-text">
|
||||||
|
{{ $t("slowResponseNotificationMethodAverageDescription", [monitor.slowResponseNotificationRange]) }}
|
||||||
|
</div>
|
||||||
|
<div v-if="monitor.slowResponseNotificationMethod === 'max'" class="form-text">
|
||||||
|
{{ $t("slowResponseNotificationMethodMaxDescription", [monitor.slowResponseNotificationRange]) }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div v-if="monitor.slowResponseNotification" class="my-3">
|
||||||
|
<label for="slow-response-notification-threshold" class="form-label">{{ $t("slowResponseNotificationThreshold") }}</label>
|
||||||
|
<input id="slow-response-notification-threshold" v-model="monitor.slowResponseNotificationThreshold" type="number" class="form-control" required min="0" step="1">
|
||||||
|
<div class="form-text">
|
||||||
|
{{ $t("slowResponseNotificationThresholdDescription", [monitor.slowResponseNotificationThreshold]) }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div v-if="monitor.slowResponseNotification" class="my-3">
|
||||||
|
<label for="slow-response-notification-range" class="form-label">{{ $t("slowResponseNotificationRange") }}</label>
|
||||||
|
<input id="slow-response-notification-range" v-model="monitor.slowResponseNotificationRange" type="number" class="form-control" required min="0" step="1">
|
||||||
|
<div class="form-text">
|
||||||
|
{{ $t("slowResponseNotificationRangeDescription", [monitor.slowResponseNotificationRange]) }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<h2 v-if="monitor.type !== 'push'" class="mt-5 mb-2">{{ $t("Advanced") }}</h2>
|
<h2 v-if="monitor.type !== 'push'" class="mt-5 mb-2">{{ $t("Advanced") }}</h2>
|
||||||
|
|
||||||
<div v-if="monitor.type === 'http' || monitor.type === 'keyword' || monitor.type === 'json-query' " class="my-3 form-check">
|
<div v-if="monitor.type === 'http' || monitor.type === 'keyword' || monitor.type === 'json-query' " class="my-3 form-check">
|
||||||
|
@ -888,6 +935,10 @@ const monitorDefaults = {
|
||||||
},
|
},
|
||||||
kafkaProducerSsl: false,
|
kafkaProducerSsl: false,
|
||||||
gamedigGivenPortOnly: true,
|
gamedigGivenPortOnly: true,
|
||||||
|
slowResponseNotification: false,
|
||||||
|
slowResponseNotificationThreshold: 5000,
|
||||||
|
slowResponseNotificationRange: 60,
|
||||||
|
slowResponseNotificationMethod: "average",
|
||||||
};
|
};
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
|
|
Loading…
Add table
Reference in a new issue