Skip to content
7 changes: 7 additions & 0 deletions server/model/monitor.js
Original file line number Diff line number Diff line change
Expand Up @@ -860,6 +860,13 @@ class Monitor extends BeanModel {
let startTime = dayjs().valueOf();
const monitorType = UptimeKumaServer.monitorTypeList[this.type];
await monitorType.check(this, bean, UptimeKumaServer.getInstance());

// If allowCustomStatus is false,
// only UP is allowed, other status must throw error inside check()
if (!monitorType.allowCustomStatus && bean.status !== UP) {
throw new Error("The monitor implementation is incorrect, non-UP error must throw error inside check()");
}

if (!bean.ping) {
bean.ping = dayjs().valueOf() - startTime;
}
Expand Down
8 changes: 6 additions & 2 deletions server/monitor-types/dns.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
const { MonitorType } = require("./monitor-type");
const { UP, DOWN } = require("../../src/util");
const { UP } = require("../../src/util");
const dayjs = require("dayjs");
const { dnsResolve } = require("../util-server");
const { R } = require("redbean-node");
Expand Down Expand Up @@ -79,8 +79,12 @@ class DnsMonitorType extends MonitorType {
await R.exec("UPDATE `monitor` SET dns_last_result = ? WHERE id = ? ", [ dnsMessage, monitor.id ]);
}

if (!conditionsResult) {
throw new Error(dnsMessage);
}

heartbeat.msg = dnsMessage;
heartbeat.status = conditionsResult ? UP : DOWN;
heartbeat.status = UP;
}
}

Expand Down
1 change: 1 addition & 0 deletions server/monitor-types/group.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ const Monitor = require("../model/monitor");

class GroupMonitorType extends MonitorType {
name = "group";
allowCustomStatus = true;

/**
* @inheritdoc
Expand Down
2 changes: 2 additions & 0 deletions server/monitor-types/manual.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ class ManualMonitorType extends MonitorType {
supportsConditions = false;
conditionVariables = [];

allowCustomStatus = true;

/**
* @inheritdoc
*/
Expand Down
9 changes: 9 additions & 0 deletions server/monitor-types/monitor-type.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,17 @@ class MonitorType {
*/
conditionVariables = [];

/**
* Allow to set any custom status to heartbeat, other than UP.
* @type {boolean}
*/
allowCustomStatus = false;

/**
* Run the monitoring check on the given monitor
*
* Successful cases: Should update heartbeat.status to "up" and set response time.
* Failure cases: Throw an error with a descriptive message.
* @param {Monitor} monitor Monitor to check
* @param {Heartbeat} heartbeat Monitor heartbeat to update
* @param {UptimeKumaServer} server Uptime Kuma server
Expand Down
11 changes: 5 additions & 6 deletions server/monitor-types/rabbitmq.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
const { MonitorType } = require("./monitor-type");
const { log, UP, DOWN } = require("../../src/util");
const { log, UP } = require("../../src/util");
const { axiosAbortSignal } = require("../util-server");
const axios = require("axios");

Expand All @@ -17,7 +17,6 @@ class RabbitMqMonitorType extends MonitorType {
throw new Error("Invalid RabbitMQ Nodes");
}

heartbeat.status = DOWN;
for (let baseUrl of baseUrls) {
try {
// Without a trailing slash, path in baseUrl will be removed. https://example.com/api -> https://example.com
Expand Down Expand Up @@ -45,17 +44,17 @@ class RabbitMqMonitorType extends MonitorType {
heartbeat.msg = "OK";
break;
} else if (res.status === 503) {
heartbeat.msg = res.data.reason;
throw new Error(res.data.reason);
} else {
heartbeat.msg = `${res.status} - ${res.statusText}`;
throw new Error(`${res.status} - ${res.statusText}`);
}
} catch (error) {
if (axios.isCancel(error)) {
heartbeat.msg = "Request timed out";
log.debug("monitor", `[${monitor.name}] Request timed out`);
throw new Error("Request timed out");
} else {
log.debug("monitor", `[${monitor.name}] Axios Error: ${JSON.stringify(error.message)}`);
heartbeat.msg = error.message;
throw new Error(error.message);
}
}
}
Expand Down
12 changes: 4 additions & 8 deletions server/monitor-types/tcp.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
const { MonitorType } = require("./monitor-type");
const { UP, DOWN, PING_GLOBAL_TIMEOUT_DEFAULT: TIMEOUT, log } = require("../../src/util");
const { UP, PING_GLOBAL_TIMEOUT_DEFAULT: TIMEOUT, log } = require("../../src/util");
const { checkCertificate } = require("../util-server");
const tls = require("tls");
const net = require("net");
Expand Down Expand Up @@ -47,9 +47,7 @@ class TCPMonitorType extends MonitorType {
heartbeat.msg = `${resp} ms`;
heartbeat.status = UP;
} catch {
heartbeat.status = DOWN;
heartbeat.msg = "Connection failed";
return;
throw new Error("Connection failed");
}

let socket_;
Expand Down Expand Up @@ -133,13 +131,11 @@ class TCPMonitorType extends MonitorType {

await monitor.handleTlsInfo(tlsInfoObject);
if (!tlsInfoObject.valid) {
heartbeat.status = DOWN;
heartbeat.msg = "Certificate is invalid";
throw new Error("Certificate is invalid");
}
} catch (error) {
const message = error instanceof Error ? error.message : "Unknown error";
heartbeat.status = DOWN;
heartbeat.msg = `TLS Connection failed: ${message}`;
throw new Error(`TLS Connection failed: ${message}`);
} finally {
if (socket && !socket.destroyed) {
socket.end();
Expand Down
11 changes: 8 additions & 3 deletions server/monitor-types/websocket-upgrade.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
const { MonitorType } = require("./monitor-type");
const WebSocket = require("ws");
const { UP, DOWN } = require("../../src/util");
const { UP } = require("../../src/util");

class WebSocketMonitorType extends MonitorType {
name = "websocket-upgrade";
Expand All @@ -10,8 +10,13 @@ class WebSocketMonitorType extends MonitorType {
*/
async check(monitor, heartbeat, _server) {
const [ message, code ] = await this.attemptUpgrade(monitor);
heartbeat.status = code === 1000 ? UP : DOWN;
heartbeat.msg = message;

if (code === 1000) {
heartbeat.status = UP;
heartbeat.msg = message;
}

throw new Error(message);
}

/**
Expand Down
Loading