mirror of
https://github.com/louislam/uptime-kuma.git
synced 2025-06-14 16:42:35 +02:00
Added the option not to send notifications if the master monitor is pending, down or degraded.
This commit is contained in:
parent
64c8a90e8a
commit
7e2503c0dc
7 changed files with 60 additions and 17 deletions
|
@ -1,6 +1,9 @@
|
|||
-- You should not modify if this have pushed to Github, unless it does serious wrong with the db.
|
||||
BEGIN TRANSACTION;
|
||||
|
||||
ALTER TABLE monitor
|
||||
ADD no_notification_if_master_down BOOLEAN default 0 NOT NULL;
|
||||
|
||||
CREATE TABLE dependent_monitors
|
||||
(
|
||||
id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
|
||||
|
|
|
@ -72,6 +72,7 @@ class Monitor extends BeanModel {
|
|||
keyword: this.keyword,
|
||||
ignoreTls: this.getIgnoreTls(),
|
||||
upsideDown: this.isUpsideDown(),
|
||||
noNotificationIfMasterDown: this.getNoNotificationIfMasterDown(),
|
||||
maxredirects: this.maxredirects,
|
||||
accepted_statuscodes: this.getAcceptedStatuscodes(),
|
||||
dns_resolve_type: this.dns_resolve_type,
|
||||
|
@ -108,6 +109,14 @@ class Monitor extends BeanModel {
|
|||
return Boolean(this.upsideDown);
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse to boolean
|
||||
* @returns {boolean}
|
||||
*/
|
||||
getNoNotificationIfMasterDown() {
|
||||
return Boolean(this.noNotificationIfMasterDown);
|
||||
}
|
||||
|
||||
getAcceptedStatuscodes() {
|
||||
return JSON.parse(this.accepted_statuscodes_json);
|
||||
}
|
||||
|
@ -148,7 +157,10 @@ class Monitor extends BeanModel {
|
|||
bean.duration = 0;
|
||||
}
|
||||
|
||||
let isDegraded = false;
|
||||
|
||||
try {
|
||||
isDegraded = await Monitor.isDegraded(this.id);
|
||||
if (this.type === "http" || this.type === "keyword") {
|
||||
// Do not do any queries/high loading things before the "bean.ping"
|
||||
let startTime = dayjs().valueOf();
|
||||
|
@ -363,8 +375,8 @@ class Monitor extends BeanModel {
|
|||
|
||||
retries = 0;
|
||||
|
||||
if (bean.status === UP && await Monitor.isDegraded(this.id)) {
|
||||
bean.msg = "Monitor is degraded, because at least one dependent monitor is DOWN";
|
||||
if (bean.status === UP && isDegraded) {
|
||||
bean.msg = "Monitor is degraded, because at least one master monitor is pending, down or degraded";
|
||||
bean.status = DEGRADED;
|
||||
}
|
||||
|
||||
|
@ -381,6 +393,12 @@ class Monitor extends BeanModel {
|
|||
retries++;
|
||||
bean.status = PENDING;
|
||||
}
|
||||
|
||||
// Do not change this text!
|
||||
// Condition below and in api-router depends on it
|
||||
if (isDegraded && bean.status === DOWN) {
|
||||
bean.msg = "Monitor is down and degraded";
|
||||
}
|
||||
}
|
||||
|
||||
let beatInterval = this.interval;
|
||||
|
@ -393,7 +411,10 @@ class Monitor extends BeanModel {
|
|||
if (isImportant) {
|
||||
bean.important = true;
|
||||
|
||||
if (Monitor.isImportantForNotification(isFirstBeat, previousBeat?.status, bean.status)) {
|
||||
if (this.noNotificationIfMasterDown && isDegraded || previousBeat.msg === "Monitor is down and degraded") {
|
||||
debug(`[${this.name}] will not sendNotification because it is/was degraded`);
|
||||
}
|
||||
else if (Monitor.isImportantForNotification(isFirstBeat, previousBeat?.status, bean.status)) {
|
||||
debug(`[${this.name}] sendNotification`);
|
||||
await Monitor.sendNotification(isFirstBeat, this, bean);
|
||||
}
|
||||
|
@ -801,7 +822,7 @@ class Monitor extends BeanModel {
|
|||
|
||||
static async getPreviousHeartbeat(monitorID) {
|
||||
return await R.getRow(`
|
||||
SELECT status, time FROM heartbeat
|
||||
SELECT msg, status, time FROM heartbeat
|
||||
WHERE id = (select MAX(id) from heartbeat where monitor_id = ?)
|
||||
`, [
|
||||
monitorID
|
||||
|
@ -811,7 +832,7 @@ class Monitor extends BeanModel {
|
|||
static async isDegraded(monitorID) {
|
||||
const monitors = await R.getAll(`
|
||||
SELECT hb.id FROM heartbeat hb JOIN dependent_monitors dm on hb.monitor_id = dm.depends_on JOIN (SELECT MAX(id) AS id FROM heartbeat GROUP BY monitor_id) USING (id)
|
||||
WHERE dm.monitor_id = ? AND hb.status = 0
|
||||
WHERE dm.monitor_id = ? AND (hb.status = 0 OR hb.status = 2 OR hb.status = 4)
|
||||
`, [
|
||||
monitorID
|
||||
]);
|
||||
|
|
|
@ -51,7 +51,9 @@ router.get("/api/push/:pushToken", async (request, response) => {
|
|||
duration = dayjs(bean.time).diff(dayjs(previousHeartbeat.time), "second");
|
||||
}
|
||||
|
||||
if (status === UP && await Monitor.isDegraded(monitor.id)) {
|
||||
const isDegraded = await Monitor.isDegraded(monitor.id)
|
||||
|
||||
if (status === UP && isDegraded) {
|
||||
msg = "Monitor is degraded, because at least one dependent monitor is DOWN";
|
||||
status = DEGRADED;
|
||||
}
|
||||
|
@ -75,7 +77,10 @@ router.get("/api/push/:pushToken", async (request, response) => {
|
|||
ok: true,
|
||||
});
|
||||
|
||||
if (Monitor.isImportantForNotification(isFirstBeat, previousStatus, status)) {
|
||||
if (monitor.noNotificationIfMasterDown && isDegraded || previousHeartbeat.msg === "Monitor is down and degraded") {
|
||||
debug(`[${monitor.name}] will not sendNotification because it is/was degraded`);
|
||||
}
|
||||
else if (Monitor.isImportantForNotification(isFirstBeat, previousStatus, status)) {
|
||||
await Monitor.sendNotification(isFirstBeat, monitor, bean);
|
||||
}
|
||||
|
||||
|
|
|
@ -594,6 +594,7 @@ exports.entryPage = "dashboard";
|
|||
bean.keyword = monitor.keyword;
|
||||
bean.ignoreTls = monitor.ignoreTls;
|
||||
bean.upsideDown = monitor.upsideDown;
|
||||
bean.noNotificationIfMasterDown = monitor.noNotificationIfMasterDown;
|
||||
bean.maxredirects = monitor.maxredirects;
|
||||
bean.accepted_statuscodes_json = JSON.stringify(monitor.accepted_statuscodes);
|
||||
bean.dns_resolve_type = monitor.dns_resolve_type;
|
||||
|
|
|
@ -6,8 +6,11 @@ export default {
|
|||
ignoreTLSError: "Ignore TLS/SSL error for HTTPS websites",
|
||||
upsideDownModeDescription: "Flip the status upside down. If the service is reachable, it is DOWN.",
|
||||
maxRedirectDescription: "Maximum number of redirects to follow. Set to 0 to disable redirects.",
|
||||
sendNotificationTitle: "Do not send notification in case of master monitor failure",
|
||||
sendNotificationDescription: "Do not send any notifications if this monitor is DOWN and at least one master monitor is also DOWN.",
|
||||
Degraded: "Degraded",
|
||||
"Dependent Monitors": "Dependent Monitors",
|
||||
monitorDependsOn: "The status of this monitor depends on",
|
||||
"Pick Dependent Monitors...": "Pick Dependent Monitors...",
|
||||
dependentMonitorsDescription: "Select the monitor(s) on which this monitor depends. If the dependent monitor(s) fails, this monitor will be affected too.",
|
||||
acceptedStatusCodesDescription: "Select status codes which are considered as a successful response.",
|
||||
|
|
|
@ -103,6 +103,14 @@
|
|||
</div>
|
||||
</div>
|
||||
|
||||
<div class="shadow-box table-shadow-box">
|
||||
<label for="dependent-monitors" class="form-label" style="margin-top: 20px; font-weight: bold">{{ $t("monitorDependsOn") }}:</label>
|
||||
<br>
|
||||
<button v-for="monitor in this.dependentMonitors" class="btn btn-monitor" style="margin: 5px; cursor: auto; color: white; font-weight: 500">
|
||||
{{ monitor }}
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div class="shadow-box table-shadow-box">
|
||||
<div class="dropdown dropdown-clear-data">
|
||||
<button class="btn btn-sm btn-outline-danger dropdown-toggle" type="button" data-bs-toggle="dropdown">
|
||||
|
@ -154,14 +162,6 @@
|
|||
</div>
|
||||
</div>
|
||||
|
||||
<div class="shadow-box table-shadow-box">
|
||||
<label for="dependent-monitors" class="form-label" style="margin-top: 20px">{{ $t("Dependent Monitors") }}</label>
|
||||
<br>
|
||||
<button v-for="monitor in this.dependentMonitors" class="btn btn-monitor" style="margin: 5px; cursor: auto; color: white; font-weight: bold">
|
||||
{{ monitor }}
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<Confirm ref="confirmPause" :yes-text="$t('Yes')" :no-text="$t('No')" @yes="pauseMonitor">
|
||||
{{ $t("pauseMonitorMsg") }}
|
||||
</Confirm>
|
||||
|
|
|
@ -156,6 +156,16 @@
|
|||
</div>
|
||||
</div>
|
||||
|
||||
<div v-if="dependentMonitors.length !== 0" class="my-3 form-check">
|
||||
<input id="send-notification" v-model="monitor.noNotificationIfMasterDown" class="form-check-input" type="checkbox">
|
||||
<label class="form-check-label" for="send-notification">
|
||||
{{ $t("sendNotificationTitle") }}
|
||||
</label>
|
||||
<div class="form-text">
|
||||
{{ $t("sendNotificationDescription") }}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- HTTP / Keyword only -->
|
||||
<template v-if="monitor.type === 'http' || monitor.type === 'keyword' ">
|
||||
<div class="my-3">
|
||||
|
@ -200,14 +210,13 @@
|
|||
track-by="id"
|
||||
label="name"
|
||||
:multiple="true"
|
||||
:allow-empty="false"
|
||||
:close-on-select="false"
|
||||
:clear-on-select="false"
|
||||
:preserve-search="true"
|
||||
:placeholder="$t('Pick Dependent Monitors...')"
|
||||
:preselect-first="false"
|
||||
:max-height="600"
|
||||
:taggable="false"
|
||||
:taggable="true"
|
||||
></VueMultiselect>
|
||||
|
||||
<div class="form-text">
|
||||
|
@ -476,6 +485,7 @@ export default {
|
|||
notificationIDList: {},
|
||||
ignoreTls: false,
|
||||
upsideDown: false,
|
||||
noNotificationIfMasterDown: false,
|
||||
maxredirects: 10,
|
||||
accepted_statuscodes: ["200-299"],
|
||||
dns_resolve_type: "A",
|
||||
|
|
Loading…
Add table
Reference in a new issue