mirror of
https://github.com/louislam/uptime-kuma.git
synced 2024-11-23 14:54:05 +00:00
Compare commits
8 commits
3a5eda0dbd
...
4015bd8277
Author | SHA1 | Date | |
---|---|---|---|
|
4015bd8277 | ||
|
c01494ec33 | ||
|
a7e9bdd43e | ||
|
062fba33e7 | ||
|
131cf81a39 | ||
|
68b02f1b39 | ||
|
800d868d3f | ||
|
e85789ecae |
35 changed files with 452 additions and 242 deletions
17
db/knex_migrations/2024-10-1315-rabbitmq-monitor.js
Normal file
17
db/knex_migrations/2024-10-1315-rabbitmq-monitor.js
Normal file
|
@ -0,0 +1,17 @@
|
|||
exports.up = function (knex) {
|
||||
return knex.schema.alterTable("monitor", function (table) {
|
||||
table.text("rabbitmq_nodes");
|
||||
table.string("rabbitmq_username");
|
||||
table.string("rabbitmq_password");
|
||||
});
|
||||
|
||||
};
|
||||
|
||||
exports.down = function (knex) {
|
||||
return knex.schema.alterTable("monitor", function (table) {
|
||||
table.dropColumn("rabbitmq_nodes");
|
||||
table.dropColumn("rabbitmq_username");
|
||||
table.dropColumn("rabbitmq_password");
|
||||
});
|
||||
|
||||
};
|
17
package-lock.json
generated
17
package-lock.json
generated
|
@ -93,6 +93,7 @@
|
|||
"@playwright/test": "~1.39.0",
|
||||
"@popperjs/core": "~2.10.2",
|
||||
"@testcontainers/hivemq": "^10.13.1",
|
||||
"@testcontainers/rabbitmq": "^10.13.2",
|
||||
"@types/bootstrap": "~5.1.9",
|
||||
"@types/node": "^20.8.6",
|
||||
"@typescript-eslint/eslint-plugin": "^6.7.5",
|
||||
|
@ -4172,6 +4173,15 @@
|
|||
"testcontainers": "^10.13.1"
|
||||
}
|
||||
},
|
||||
"node_modules/@testcontainers/rabbitmq": {
|
||||
"version": "10.13.2",
|
||||
"resolved": "https://registry.npmjs.org/@testcontainers/rabbitmq/-/rabbitmq-10.13.2.tgz",
|
||||
"integrity": "sha512-npBKBnq3c6hETmxGZ/gVMke9cc1J/pcftNW9S3WidL48hxFBIPjYNM9FdTfWuoNER/8kuf4xJ8yCuJEYGH3ZAg==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"testcontainers": "^10.13.2"
|
||||
}
|
||||
},
|
||||
"node_modules/@tootallnate/once": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/@tootallnate/once/-/once-2.0.0.tgz",
|
||||
|
@ -15925,11 +15935,10 @@
|
|||
}
|
||||
},
|
||||
"node_modules/testcontainers": {
|
||||
"version": "10.13.1",
|
||||
"resolved": "https://registry.npmjs.org/testcontainers/-/testcontainers-10.13.1.tgz",
|
||||
"integrity": "sha512-JBbOhxmygj/ouH/47GnoVNt+c55Telh/45IjVxEbDoswsLchVmJiuKiw/eF6lE5i7LN+/99xsrSCttI3YRtirg==",
|
||||
"version": "10.13.2",
|
||||
"resolved": "https://registry.npmjs.org/testcontainers/-/testcontainers-10.13.2.tgz",
|
||||
"integrity": "sha512-LfEll+AG/1Ks3n4+IA5lpyBHLiYh/hSfI4+ERa6urwfQscbDU+M2iW1qPQrHQi+xJXQRYy4whyK1IEHdmxWa3Q==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@balena/dockerignore": "^1.0.2",
|
||||
"@types/dockerode": "^3.3.29",
|
||||
|
|
|
@ -155,6 +155,7 @@
|
|||
"@playwright/test": "~1.39.0",
|
||||
"@popperjs/core": "~2.10.2",
|
||||
"@testcontainers/hivemq": "^10.13.1",
|
||||
"@testcontainers/rabbitmq": "^10.13.2",
|
||||
"@types/bootstrap": "~5.1.9",
|
||||
"@types/node": "^20.8.6",
|
||||
"@typescript-eslint/eslint-plugin": "^6.7.5",
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
const basicAuth = require("express-basic-auth");
|
||||
const passwordHash = require("./password-hash");
|
||||
const { R } = require("redbean-node");
|
||||
const { setting } = require("./util-server");
|
||||
const { log } = require("../src/util");
|
||||
const { loginRateLimiter, apiRateLimiter } = require("./rate-limiter");
|
||||
const { Settings } = require("./settings");
|
||||
|
@ -139,7 +138,7 @@ exports.basicAuth = async function (req, res, next) {
|
|||
challenge: true,
|
||||
});
|
||||
|
||||
const disabledAuth = await setting("disableAuth");
|
||||
const disabledAuth = await Settings.get("disableAuth");
|
||||
|
||||
if (!disabledAuth) {
|
||||
middleware(req, res, next);
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
const { setSetting, setting } = require("./util-server");
|
||||
const axios = require("axios");
|
||||
const compareVersions = require("compare-versions");
|
||||
const { log } = require("../src/util");
|
||||
const { Settings } = require("./settings");
|
||||
|
||||
exports.version = require("../package.json").version;
|
||||
exports.latestVersion = null;
|
||||
|
@ -14,7 +14,7 @@ let interval;
|
|||
|
||||
exports.startInterval = () => {
|
||||
let check = async () => {
|
||||
if (await setting("checkUpdate") === false) {
|
||||
if (await Settings.get("checkUpdate") === false) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -28,7 +28,7 @@ exports.startInterval = () => {
|
|||
res.data.slow = "1000.0.0";
|
||||
}
|
||||
|
||||
let checkBeta = await setting("checkBeta");
|
||||
let checkBeta = await Settings.get("checkBeta");
|
||||
|
||||
if (checkBeta && res.data.beta) {
|
||||
if (compareVersions.compare(res.data.beta, res.data.slow, ">")) {
|
||||
|
@ -57,7 +57,7 @@ exports.startInterval = () => {
|
|||
* @returns {Promise<void>}
|
||||
*/
|
||||
exports.enableCheckUpdate = async (value) => {
|
||||
await setSetting("checkUpdate", value);
|
||||
await Settings.set("checkUpdate", value);
|
||||
|
||||
clearInterval(interval);
|
||||
|
||||
|
|
|
@ -6,8 +6,8 @@ const { R } = require("redbean-node");
|
|||
const { UptimeKumaServer } = require("./uptime-kuma-server");
|
||||
const server = UptimeKumaServer.getInstance();
|
||||
const io = server.io;
|
||||
const { setting } = require("./util-server");
|
||||
const checkVersion = require("./check-version");
|
||||
const { Settings } = require("./settings");
|
||||
const Database = require("./database");
|
||||
|
||||
/**
|
||||
|
@ -158,8 +158,8 @@ async function sendInfo(socket, hideVersion = false) {
|
|||
version,
|
||||
latestVersion,
|
||||
isContainer,
|
||||
primaryBaseURL: await Settings.get("primaryBaseURL"),
|
||||
dbType,
|
||||
primaryBaseURL: await setting("primaryBaseURL"),
|
||||
serverTimezone: await server.getTimezone(),
|
||||
serverTimezoneOffset: server.getTimezoneOffset(),
|
||||
});
|
||||
|
|
|
@ -1,11 +1,11 @@
|
|||
const fs = require("fs");
|
||||
const { R } = require("redbean-node");
|
||||
const { setSetting, setting } = require("./util-server");
|
||||
const { log, sleep } = require("../src/util");
|
||||
const knex = require("knex");
|
||||
const path = require("path");
|
||||
const { EmbeddedMariaDB } = require("./embedded-mariadb");
|
||||
const mysql = require("mysql2/promise");
|
||||
const { Settings } = require("./settings");
|
||||
|
||||
/**
|
||||
* Database & App Data Folder
|
||||
|
@ -420,7 +420,7 @@ class Database {
|
|||
* @deprecated
|
||||
*/
|
||||
static async patchSqlite() {
|
||||
let version = parseInt(await setting("database_version"));
|
||||
let version = parseInt(await Settings.get("database_version"));
|
||||
|
||||
if (! version) {
|
||||
version = 0;
|
||||
|
@ -445,7 +445,7 @@ class Database {
|
|||
log.info("db", `Patching ${sqlFile}`);
|
||||
await Database.importSQLFile(sqlFile);
|
||||
log.info("db", `Patched ${sqlFile}`);
|
||||
await setSetting("database_version", i);
|
||||
await Settings.set("database_version", i);
|
||||
}
|
||||
} catch (ex) {
|
||||
await Database.close();
|
||||
|
@ -471,7 +471,7 @@ class Database {
|
|||
*/
|
||||
static async patchSqlite2() {
|
||||
log.debug("db", "Database Patch 2.0 Process");
|
||||
let databasePatchedFiles = await setting("databasePatchedFiles");
|
||||
let databasePatchedFiles = await Settings.get("databasePatchedFiles");
|
||||
|
||||
if (! databasePatchedFiles) {
|
||||
databasePatchedFiles = {};
|
||||
|
@ -499,7 +499,7 @@ class Database {
|
|||
process.exit(1);
|
||||
}
|
||||
|
||||
await setSetting("databasePatchedFiles", databasePatchedFiles);
|
||||
await Settings.set("databasePatchedFiles", databasePatchedFiles);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -512,27 +512,27 @@ class Database {
|
|||
// Fix 1.13.0 empty slug bug
|
||||
await R.exec("UPDATE status_page SET slug = 'empty-slug-recover' WHERE TRIM(slug) = ''");
|
||||
|
||||
let title = await setting("title");
|
||||
let title = await Settings.get("title");
|
||||
|
||||
if (title) {
|
||||
console.log("Migrating Status Page");
|
||||
log.info("database", "Migrating Status Page");
|
||||
|
||||
let statusPageCheck = await R.findOne("status_page", " slug = 'default' ");
|
||||
|
||||
if (statusPageCheck !== null) {
|
||||
console.log("Migrating Status Page - Skip, default slug record is already existing");
|
||||
log.info("database", "Migrating Status Page - Skip, default slug record is already existing");
|
||||
return;
|
||||
}
|
||||
|
||||
let statusPage = R.dispense("status_page");
|
||||
statusPage.slug = "default";
|
||||
statusPage.title = title;
|
||||
statusPage.description = await setting("description");
|
||||
statusPage.icon = await setting("icon");
|
||||
statusPage.theme = await setting("statusPageTheme");
|
||||
statusPage.published = !!await setting("statusPagePublished");
|
||||
statusPage.search_engine_index = !!await setting("searchEngineIndex");
|
||||
statusPage.show_tags = !!await setting("statusPageTags");
|
||||
statusPage.description = await Settings.get("description");
|
||||
statusPage.icon = await Settings.get("icon");
|
||||
statusPage.theme = await Settings.get("statusPageTheme");
|
||||
statusPage.published = !!await Settings.get("statusPagePublished");
|
||||
statusPage.search_engine_index = !!await Settings.get("searchEngineIndex");
|
||||
statusPage.show_tags = !!await Settings.get("statusPageTags");
|
||||
statusPage.password = null;
|
||||
|
||||
if (!statusPage.title) {
|
||||
|
@ -560,13 +560,13 @@ class Database {
|
|||
await R.exec("DELETE FROM setting WHERE type = 'statusPage'");
|
||||
|
||||
// Migrate Entry Page if it is status page
|
||||
let entryPage = await setting("entryPage");
|
||||
let entryPage = await Settings.get("entryPage");
|
||||
|
||||
if (entryPage === "statusPage") {
|
||||
await setSetting("entryPage", "statusPage-default", "general");
|
||||
await Settings.set("entryPage", "statusPage-default", "general");
|
||||
}
|
||||
|
||||
console.log("Migrating Status Page - Done");
|
||||
log.info("database", "Migrating Status Page - Done");
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
const { R } = require("redbean-node");
|
||||
const { log } = require("../../src/util");
|
||||
const { setSetting, setting } = require("../util-server");
|
||||
const Database = require("../database");
|
||||
const { Settings } = require("../settings");
|
||||
|
||||
const DEFAULT_KEEP_PERIOD = 180;
|
||||
|
||||
|
@ -11,11 +11,11 @@ const DEFAULT_KEEP_PERIOD = 180;
|
|||
*/
|
||||
|
||||
const clearOldData = async () => {
|
||||
let period = await setting("keepDataPeriodDays");
|
||||
let period = await Settings.get("keepDataPeriodDays");
|
||||
|
||||
// Set Default Period
|
||||
if (period == null) {
|
||||
await setSetting("keepDataPeriodDays", DEFAULT_KEEP_PERIOD, "general");
|
||||
await Settings.set("keepDataPeriodDays", DEFAULT_KEEP_PERIOD, "general");
|
||||
period = DEFAULT_KEEP_PERIOD;
|
||||
}
|
||||
|
||||
|
@ -25,7 +25,7 @@ const clearOldData = async () => {
|
|||
parsedPeriod = parseInt(period);
|
||||
} catch (_) {
|
||||
log.warn("clearOldData", "Failed to parse setting, resetting to default..");
|
||||
await setSetting("keepDataPeriodDays", DEFAULT_KEEP_PERIOD, "general");
|
||||
await Settings.set("keepDataPeriodDays", DEFAULT_KEEP_PERIOD, "general");
|
||||
parsedPeriod = DEFAULT_KEEP_PERIOD;
|
||||
}
|
||||
|
||||
|
|
|
@ -4,7 +4,7 @@ const { Prometheus } = require("../prometheus");
|
|||
const { log, UP, DOWN, PENDING, MAINTENANCE, flipStatus, MAX_INTERVAL_SECOND, MIN_INTERVAL_SECOND,
|
||||
SQL_DATETIME_FORMAT, evaluateJsonQuery
|
||||
} = require("../../src/util");
|
||||
const { tcping, ping, checkCertificate, checkStatusCode, getTotalClientInRoom, setting, mssqlQuery, postgresQuery, mysqlQuery, setSetting, httpNtlm, radius, grpcQuery,
|
||||
const { tcping, ping, checkCertificate, checkStatusCode, getTotalClientInRoom, mssqlQuery, postgresQuery, mysqlQuery, httpNtlm, radius, grpcQuery,
|
||||
redisPingAsync, kafkaProducerAsync, getOidcTokenClientCredentials, rootCertificatesFingerprints, axiosAbortSignal
|
||||
} = require("../util-server");
|
||||
const { R } = require("redbean-node");
|
||||
|
@ -24,6 +24,7 @@ const { CookieJar } = require("tough-cookie");
|
|||
const { HttpsCookieAgent } = require("http-cookie-agent/http");
|
||||
const https = require("https");
|
||||
const http = require("http");
|
||||
const { Settings } = require("../settings");
|
||||
|
||||
const rootCertificates = rootCertificatesFingerprints();
|
||||
|
||||
|
@ -153,6 +154,7 @@ class Monitor extends BeanModel {
|
|||
snmpOid: this.snmpOid,
|
||||
jsonPathOperator: this.jsonPathOperator,
|
||||
snmpVersion: this.snmpVersion,
|
||||
rabbitmqNodes: JSON.parse(this.rabbitmqNodes),
|
||||
conditions: JSON.parse(this.conditions),
|
||||
};
|
||||
|
||||
|
@ -183,6 +185,8 @@ class Monitor extends BeanModel {
|
|||
tlsCert: this.tlsCert,
|
||||
tlsKey: this.tlsKey,
|
||||
kafkaProducerSaslOptions: JSON.parse(this.kafkaProducerSaslOptions),
|
||||
rabbitmqUsername: this.rabbitmqUsername,
|
||||
rabbitmqPassword: this.rabbitmqPassword,
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -651,7 +655,7 @@ class Monitor extends BeanModel {
|
|||
|
||||
} else if (this.type === "steam") {
|
||||
const steamApiUrl = "https://api.steampowered.com/IGameServersService/GetServerList/v1/";
|
||||
const steamAPIKey = await setting("steamAPIKey");
|
||||
const steamAPIKey = await Settings.get("steamAPIKey");
|
||||
const filter = `addr\\${this.hostname}:${this.port}`;
|
||||
|
||||
if (!steamAPIKey) {
|
||||
|
@ -1373,11 +1377,11 @@ class Monitor extends BeanModel {
|
|||
return;
|
||||
}
|
||||
|
||||
let notifyDays = await setting("tlsExpiryNotifyDays");
|
||||
let notifyDays = await Settings.get("tlsExpiryNotifyDays");
|
||||
if (notifyDays == null || !Array.isArray(notifyDays)) {
|
||||
// Reset Default
|
||||
await setSetting("tlsExpiryNotifyDays", [ 7, 14, 21 ], "general");
|
||||
notifyDays = [ 7, 14, 21 ];
|
||||
await Settings.set("tlsExpiryNotifyDays", notifyDays, "general");
|
||||
}
|
||||
|
||||
if (Array.isArray(notifyDays)) {
|
||||
|
|
67
server/monitor-types/rabbitmq.js
Normal file
67
server/monitor-types/rabbitmq.js
Normal file
|
@ -0,0 +1,67 @@
|
|||
const { MonitorType } = require("./monitor-type");
|
||||
const { log, UP, DOWN } = require("../../src/util");
|
||||
const { axiosAbortSignal } = require("../util-server");
|
||||
const axios = require("axios");
|
||||
|
||||
class RabbitMqMonitorType extends MonitorType {
|
||||
name = "rabbitmq";
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
async check(monitor, heartbeat, server) {
|
||||
let baseUrls = [];
|
||||
try {
|
||||
baseUrls = JSON.parse(monitor.rabbitmqNodes);
|
||||
} catch (error) {
|
||||
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
|
||||
if ( !baseUrl.endsWith("/") ) {
|
||||
baseUrl += "/";
|
||||
}
|
||||
const options = {
|
||||
// Do not start with slash, it will strip the trailing slash from baseUrl
|
||||
url: new URL("api/health/checks/alarms/", baseUrl).href,
|
||||
method: "get",
|
||||
timeout: monitor.timeout * 1000,
|
||||
headers: {
|
||||
"Accept": "application/json",
|
||||
"Authorization": "Basic " + Buffer.from(`${monitor.rabbitmqUsername || ""}:${monitor.rabbitmqPassword || ""}`).toString("base64"),
|
||||
},
|
||||
signal: axiosAbortSignal((monitor.timeout + 10) * 1000),
|
||||
// Capture reason for 503 status
|
||||
validateStatus: (status) => status === 200 || status === 503,
|
||||
};
|
||||
log.debug("monitor", `[${monitor.name}] Axios Request: ${JSON.stringify(options)}`);
|
||||
const res = await axios.request(options);
|
||||
log.debug("monitor", `[${monitor.name}] Axios Response: status=${res.status} body=${JSON.stringify(res.data)}`);
|
||||
if (res.status === 200) {
|
||||
heartbeat.status = UP;
|
||||
heartbeat.msg = "OK";
|
||||
break;
|
||||
} else if (res.status === 503) {
|
||||
heartbeat.msg = res.data.reason;
|
||||
} else {
|
||||
heartbeat.msg = `${res.status} - ${res.statusText}`;
|
||||
}
|
||||
} catch (error) {
|
||||
if (axios.isCancel(error)) {
|
||||
heartbeat.msg = "Request timed out";
|
||||
log.debug("monitor", `[${monitor.name}] Request timed out`);
|
||||
} else {
|
||||
log.debug("monitor", `[${monitor.name}] Axios Error: ${JSON.stringify(error.message)}`);
|
||||
heartbeat.msg = error.message;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
RabbitMqMonitorType,
|
||||
};
|
|
@ -63,7 +63,7 @@ if (process.platform === "win32") {
|
|||
* @returns {Promise<boolean>} The executable is allowed?
|
||||
*/
|
||||
async function isAllowedChromeExecutable(executablePath) {
|
||||
console.log(config.args);
|
||||
log.info("Chromium", config.args);
|
||||
if (config.args["allow-all-chrome-exec"] || process.env.UPTIME_KUMA_ALLOW_ALL_CHROME_EXEC === "1") {
|
||||
return true;
|
||||
}
|
||||
|
@ -102,7 +102,7 @@ async function getBrowser() {
|
|||
*/
|
||||
async function getRemoteBrowser(remoteBrowserID, userId) {
|
||||
let remoteBrowser = await RemoteBrowser.get(remoteBrowserID, userId);
|
||||
log.debug("MONITOR", `Using remote browser: ${remoteBrowser.name} (${remoteBrowser.id})`);
|
||||
log.debug("Chromium", `Using remote browser: ${remoteBrowser.name} (${remoteBrowser.id})`);
|
||||
browser = await chromium.connect(remoteBrowser.url);
|
||||
return browser;
|
||||
}
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
const NotificationProvider = require("./notification-provider");
|
||||
const axios = require("axios");
|
||||
const { setting } = require("../util-server");
|
||||
const { getMonitorRelativeURL, UP, DOWN } = require("../../src/util");
|
||||
const { Settings } = require("../settings");
|
||||
|
||||
class AlertNow extends NotificationProvider {
|
||||
name = "AlertNow";
|
||||
|
@ -29,7 +29,7 @@ class AlertNow extends NotificationProvider {
|
|||
|
||||
textMsg += ` - ${msg}`;
|
||||
|
||||
const baseURL = await setting("primaryBaseURL");
|
||||
const baseURL = await Settings.get("primaryBaseURL");
|
||||
if (baseURL && monitorJSON) {
|
||||
textMsg += ` >> ${baseURL + getMonitorRelativeURL(monitorJSON.id)}`;
|
||||
}
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
const NotificationProvider = require("./notification-provider");
|
||||
const axios = require("axios");
|
||||
const { UP, DOWN, getMonitorRelativeURL } = require("../../src/util");
|
||||
const { setting } = require("../util-server");
|
||||
const { Settings } = require("../settings");
|
||||
const successMessage = "Sent Successfully.";
|
||||
|
||||
class FlashDuty extends NotificationProvider {
|
||||
|
@ -84,7 +84,7 @@ class FlashDuty extends NotificationProvider {
|
|||
}
|
||||
};
|
||||
|
||||
const baseURL = await setting("primaryBaseURL");
|
||||
const baseURL = await Settings.get("primaryBaseURL");
|
||||
if (baseURL && monitorInfo) {
|
||||
options.client = "Uptime Kuma";
|
||||
options.client_url = baseURL + getMonitorRelativeURL(monitorInfo.id);
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
const NotificationProvider = require("./notification-provider");
|
||||
const axios = require("axios");
|
||||
const { setting } = require("../util-server");
|
||||
const { getMonitorRelativeURL, UP } = require("../../src/util");
|
||||
const { Settings } = require("../settings");
|
||||
|
||||
class GoogleChat extends NotificationProvider {
|
||||
name = "GoogleChat";
|
||||
|
@ -45,7 +45,7 @@ class GoogleChat extends NotificationProvider {
|
|||
}
|
||||
|
||||
// add button for monitor link if available
|
||||
const baseURL = await setting("primaryBaseURL");
|
||||
const baseURL = await Settings.get("primaryBaseURL");
|
||||
if (baseURL) {
|
||||
const urlPath = monitorJSON ? getMonitorRelativeURL(monitorJSON.id) : "/";
|
||||
sectionWidgets.push({
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
const NotificationProvider = require("./notification-provider");
|
||||
const axios = require("axios");
|
||||
const { UP, DOWN, getMonitorRelativeURL } = require("../../src/util");
|
||||
const { setting } = require("../util-server");
|
||||
const { Settings } = require("../settings");
|
||||
let successMessage = "Sent Successfully.";
|
||||
|
||||
class PagerDuty extends NotificationProvider {
|
||||
|
@ -95,7 +95,7 @@ class PagerDuty extends NotificationProvider {
|
|||
}
|
||||
};
|
||||
|
||||
const baseURL = await setting("primaryBaseURL");
|
||||
const baseURL = await Settings.get("primaryBaseURL");
|
||||
if (baseURL && monitorInfo) {
|
||||
options.client = "Uptime Kuma";
|
||||
options.client_url = baseURL + getMonitorRelativeURL(monitorInfo.id);
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
const NotificationProvider = require("./notification-provider");
|
||||
const axios = require("axios");
|
||||
const { UP, DOWN, getMonitorRelativeURL } = require("../../src/util");
|
||||
const { setting } = require("../util-server");
|
||||
const { Settings } = require("../settings");
|
||||
let successMessage = "Sent Successfully.";
|
||||
|
||||
class PagerTree extends NotificationProvider {
|
||||
|
@ -74,7 +74,7 @@ class PagerTree extends NotificationProvider {
|
|||
}
|
||||
};
|
||||
|
||||
const baseURL = await setting("primaryBaseURL");
|
||||
const baseURL = await Settings.get("primaryBaseURL");
|
||||
if (baseURL && monitorJSON) {
|
||||
options.client = "Uptime Kuma";
|
||||
options.client_url = baseURL + getMonitorRelativeURL(monitorJSON.id);
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
const NotificationProvider = require("./notification-provider");
|
||||
const axios = require("axios");
|
||||
const Slack = require("./slack");
|
||||
const { setting } = require("../util-server");
|
||||
const { getMonitorRelativeURL, DOWN } = require("../../src/util");
|
||||
const { Settings } = require("../settings");
|
||||
|
||||
class RocketChat extends NotificationProvider {
|
||||
name = "rocket.chat";
|
||||
|
@ -49,7 +49,7 @@ class RocketChat extends NotificationProvider {
|
|||
await Slack.deprecateURL(notification.rocketbutton);
|
||||
}
|
||||
|
||||
const baseURL = await setting("primaryBaseURL");
|
||||
const baseURL = await Settings.get("primaryBaseURL");
|
||||
|
||||
if (baseURL) {
|
||||
data.attachments[0].title_link = baseURL + getMonitorRelativeURL(monitorJSON.id);
|
||||
|
|
|
@ -1,7 +1,8 @@
|
|||
const NotificationProvider = require("./notification-provider");
|
||||
const axios = require("axios");
|
||||
const { setSettings, setting } = require("../util-server");
|
||||
const { getMonitorRelativeURL, UP } = require("../../src/util");
|
||||
const { Settings } = require("../settings");
|
||||
const { log } = require("../../src/util");
|
||||
|
||||
class Slack extends NotificationProvider {
|
||||
name = "slack";
|
||||
|
@ -14,15 +15,13 @@ class Slack extends NotificationProvider {
|
|||
* @returns {Promise<void>}
|
||||
*/
|
||||
static async deprecateURL(url) {
|
||||
let currentPrimaryBaseURL = await setting("primaryBaseURL");
|
||||
let currentPrimaryBaseURL = await Settings.get("primaryBaseURL");
|
||||
|
||||
if (!currentPrimaryBaseURL) {
|
||||
console.log("Move the url to be the primary base URL");
|
||||
await setSettings("general", {
|
||||
primaryBaseURL: url,
|
||||
});
|
||||
log.error("notification", "Move the url to be the primary base URL");
|
||||
await Settings.set("primaryBaseURL", url, "general");
|
||||
} else {
|
||||
console.log("Already there, no need to move the primary base URL");
|
||||
log.debug("notification", "Already there, no need to move the primary base URL");
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -136,7 +135,7 @@ class Slack extends NotificationProvider {
|
|||
return okMsg;
|
||||
}
|
||||
|
||||
const baseURL = await setting("primaryBaseURL");
|
||||
const baseURL = await Settings.get("primaryBaseURL");
|
||||
|
||||
const title = "Uptime Kuma Alert";
|
||||
let data = {
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
const NotificationProvider = require("./notification-provider");
|
||||
const axios = require("axios");
|
||||
const { UP, DOWN, getMonitorRelativeURL } = require("../../src/util");
|
||||
const { setting } = require("../util-server");
|
||||
const { Settings } = require("../settings");
|
||||
let successMessage = "Sent Successfully.";
|
||||
|
||||
class Splunk extends NotificationProvider {
|
||||
|
@ -95,7 +95,7 @@ class Splunk extends NotificationProvider {
|
|||
}
|
||||
};
|
||||
|
||||
const baseURL = await setting("primaryBaseURL");
|
||||
const baseURL = await Settings.get("primaryBaseURL");
|
||||
if (baseURL && monitorInfo) {
|
||||
options.client = "Uptime Kuma";
|
||||
options.client_url = baseURL + getMonitorRelativeURL(monitorInfo.id);
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
const NotificationProvider = require("./notification-provider");
|
||||
const axios = require("axios");
|
||||
const { setting } = require("../util-server");
|
||||
const { getMonitorRelativeURL } = require("../../src/util");
|
||||
const { Settings } = require("../settings");
|
||||
|
||||
class Stackfield extends NotificationProvider {
|
||||
name = "stackfield";
|
||||
|
@ -23,7 +23,7 @@ class Stackfield extends NotificationProvider {
|
|||
|
||||
textMsg += `\n${msg}`;
|
||||
|
||||
const baseURL = await setting("primaryBaseURL");
|
||||
const baseURL = await Settings.get("primaryBaseURL");
|
||||
if (baseURL) {
|
||||
textMsg += `\n${baseURL + getMonitorRelativeURL(monitorJSON.id)}`;
|
||||
}
|
||||
|
|
|
@ -2,7 +2,7 @@ const { R } = require("redbean-node");
|
|||
const HttpProxyAgent = require("http-proxy-agent");
|
||||
const HttpsProxyAgent = require("https-proxy-agent");
|
||||
const SocksProxyAgent = require("socks-proxy-agent");
|
||||
const { debug } = require("../src/util");
|
||||
const { log } = require("../src/util");
|
||||
const { UptimeKumaServer } = require("./uptime-kuma-server");
|
||||
const { CookieJar } = require("tough-cookie");
|
||||
const { createCookieAgent } = require("http-cookie-agent/http");
|
||||
|
@ -110,9 +110,9 @@ class Proxy {
|
|||
proxyOptions.auth = `${proxy.username}:${proxy.password}`;
|
||||
}
|
||||
|
||||
debug(`Proxy Options: ${JSON.stringify(proxyOptions)}`);
|
||||
debug(`HTTP Agent Options: ${JSON.stringify(httpAgentOptions)}`);
|
||||
debug(`HTTPS Agent Options: ${JSON.stringify(httpsAgentOptions)}`);
|
||||
log.debug("update-proxy", `Proxy Options: ${JSON.stringify(proxyOptions)}`);
|
||||
log.debug("update-proxy", `HTTP Agent Options: ${JSON.stringify(httpAgentOptions)}`);
|
||||
log.debug("update-proxy", `HTTPS Agent Options: ${JSON.stringify(httpsAgentOptions)}`);
|
||||
|
||||
switch (proxy.protocol) {
|
||||
case "http":
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
let express = require("express");
|
||||
const {
|
||||
setting,
|
||||
allowDevAllOrigin,
|
||||
allowAllOrigin,
|
||||
percentageToColor,
|
||||
|
@ -18,6 +17,7 @@ const { makeBadge } = require("badge-maker");
|
|||
const { Prometheus } = require("../prometheus");
|
||||
const Database = require("../database");
|
||||
const { UptimeCalculator } = require("../uptime-calculator");
|
||||
const { Settings } = require("../settings");
|
||||
|
||||
let router = express.Router();
|
||||
|
||||
|
@ -30,7 +30,7 @@ router.get("/api/entry-page", async (request, response) => {
|
|||
|
||||
let result = { };
|
||||
let hostname = request.hostname;
|
||||
if ((await setting("trustProxy")) && request.headers["x-forwarded-host"]) {
|
||||
if ((await Settings.get("trustProxy")) && request.headers["x-forwarded-host"]) {
|
||||
hostname = request.headers["x-forwarded-host"];
|
||||
}
|
||||
|
||||
|
|
|
@ -90,8 +90,7 @@ const Monitor = require("./model/monitor");
|
|||
const User = require("./model/user");
|
||||
|
||||
log.debug("server", "Importing Settings");
|
||||
const { getSettings, setSettings, setting, initJWTSecret, checkLogin, doubleCheckPassword, shake256, SHAKE256_LENGTH, allowDevAllOrigin,
|
||||
} = require("./util-server");
|
||||
const { initJWTSecret, checkLogin, doubleCheckPassword, shake256, SHAKE256_LENGTH, allowDevAllOrigin } = require("./util-server");
|
||||
|
||||
log.debug("server", "Importing Notification");
|
||||
const { Notification } = require("./notification");
|
||||
|
@ -201,7 +200,7 @@ let needSetup = false;
|
|||
// Entry Page
|
||||
app.get("/", async (request, response) => {
|
||||
let hostname = request.hostname;
|
||||
if (await setting("trustProxy")) {
|
||||
if (await Settings.get("trustProxy")) {
|
||||
const proxy = request.headers["x-forwarded-host"];
|
||||
if (proxy) {
|
||||
hostname = proxy;
|
||||
|
@ -281,7 +280,7 @@ let needSetup = false;
|
|||
// Robots.txt
|
||||
app.get("/robots.txt", async (_request, response) => {
|
||||
let txt = "User-agent: *\nDisallow:";
|
||||
if (!await setting("searchEngineIndex")) {
|
||||
if (!await Settings.get("searchEngineIndex")) {
|
||||
txt += " /";
|
||||
}
|
||||
response.setHeader("Content-Type", "text/plain");
|
||||
|
@ -718,6 +717,8 @@ let needSetup = false;
|
|||
|
||||
monitor.conditions = JSON.stringify(monitor.conditions);
|
||||
|
||||
monitor.rabbitmqNodes = JSON.stringify(monitor.rabbitmqNodes);
|
||||
|
||||
bean.import(monitor);
|
||||
bean.user_id = socket.userID;
|
||||
|
||||
|
@ -868,6 +869,9 @@ let needSetup = false;
|
|||
bean.snmpOid = monitor.snmpOid;
|
||||
bean.jsonPathOperator = monitor.jsonPathOperator;
|
||||
bean.timeout = monitor.timeout;
|
||||
bean.rabbitmqNodes = JSON.stringify(monitor.rabbitmqNodes);
|
||||
bean.rabbitmqUsername = monitor.rabbitmqUsername;
|
||||
bean.rabbitmqPassword = monitor.rabbitmqPassword;
|
||||
bean.conditions = JSON.stringify(monitor.conditions);
|
||||
|
||||
bean.validate();
|
||||
|
@ -1327,7 +1331,7 @@ let needSetup = false;
|
|||
socket.on("getSettings", async (callback) => {
|
||||
try {
|
||||
checkLogin(socket);
|
||||
const data = await getSettings("general");
|
||||
const data = await Settings.getSettings("general");
|
||||
|
||||
if (!data.serverTimezone) {
|
||||
data.serverTimezone = await server.getTimezone();
|
||||
|
@ -1355,7 +1359,7 @@ let needSetup = false;
|
|||
// Disabled Auth + Want to Enable Auth => No Check
|
||||
// Enabled Auth + Want to Disable Auth => Check!!
|
||||
// Enabled Auth + Want to Enable Auth => No Check
|
||||
const currentDisabledAuth = await setting("disableAuth");
|
||||
const currentDisabledAuth = await Settings.get("disableAuth");
|
||||
if (!currentDisabledAuth && data.disableAuth) {
|
||||
await doubleCheckPassword(socket, currentPassword);
|
||||
}
|
||||
|
@ -1369,7 +1373,7 @@ let needSetup = false;
|
|||
const previousChromeExecutable = await Settings.get("chromeExecutable");
|
||||
const previousNSCDStatus = await Settings.get("nscd");
|
||||
|
||||
await setSettings("general", data);
|
||||
await Settings.setSettings("general", data);
|
||||
server.entryPage = data.entryPage;
|
||||
|
||||
// Also need to apply timezone globally
|
||||
|
@ -1465,7 +1469,7 @@ let needSetup = false;
|
|||
});
|
||||
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
log.error("server", e);
|
||||
|
||||
callback({
|
||||
ok: false,
|
||||
|
@ -1578,7 +1582,7 @@ let needSetup = false;
|
|||
// ***************************
|
||||
|
||||
log.debug("auth", "check auto login");
|
||||
if (await setting("disableAuth")) {
|
||||
if (await Settings.get("disableAuth")) {
|
||||
log.info("auth", "Disabled Auth: auto login to admin");
|
||||
await afterLogin(socket, await R.findOne("user"));
|
||||
socket.emit("autoLogin");
|
||||
|
|
|
@ -60,7 +60,7 @@ module.exports.apiKeySocketHandler = (socket) => {
|
|||
ok: true,
|
||||
});
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
log.error("apikeys", e);
|
||||
callback({
|
||||
ok: false,
|
||||
msg: e.message,
|
||||
|
|
|
@ -1,7 +1,8 @@
|
|||
const { checkLogin, setSetting, setting, doubleCheckPassword } = require("../util-server");
|
||||
const { checkLogin, doubleCheckPassword } = require("../util-server");
|
||||
const { CloudflaredTunnel } = require("node-cloudflared-tunnel");
|
||||
const { UptimeKumaServer } = require("../uptime-kuma-server");
|
||||
const { log } = require("../../src/util");
|
||||
const { Settings } = require("../settings");
|
||||
const io = UptimeKumaServer.getInstance().io;
|
||||
|
||||
const prefix = "cloudflared_";
|
||||
|
@ -40,7 +41,7 @@ module.exports.cloudflaredSocketHandler = (socket) => {
|
|||
socket.join("cloudflared");
|
||||
io.to(socket.userID).emit(prefix + "installed", cloudflared.checkInstalled());
|
||||
io.to(socket.userID).emit(prefix + "running", cloudflared.running);
|
||||
io.to(socket.userID).emit(prefix + "token", await setting("cloudflaredTunnelToken"));
|
||||
io.to(socket.userID).emit(prefix + "token", await Settings.get("cloudflaredTunnelToken"));
|
||||
} catch (error) { }
|
||||
});
|
||||
|
||||
|
@ -55,7 +56,7 @@ module.exports.cloudflaredSocketHandler = (socket) => {
|
|||
try {
|
||||
checkLogin(socket);
|
||||
if (token && typeof token === "string") {
|
||||
await setSetting("cloudflaredTunnelToken", token);
|
||||
await Settings.set("cloudflaredTunnelToken", token);
|
||||
cloudflared.token = token;
|
||||
} else {
|
||||
cloudflared.token = null;
|
||||
|
@ -67,7 +68,7 @@ module.exports.cloudflaredSocketHandler = (socket) => {
|
|||
socket.on(prefix + "stop", async (currentPassword, callback) => {
|
||||
try {
|
||||
checkLogin(socket);
|
||||
const disabledAuth = await setting("disableAuth");
|
||||
const disabledAuth = await Settings.get("disableAuth");
|
||||
if (!disabledAuth) {
|
||||
await doubleCheckPassword(socket, currentPassword);
|
||||
}
|
||||
|
@ -83,7 +84,7 @@ module.exports.cloudflaredSocketHandler = (socket) => {
|
|||
socket.on(prefix + "removeToken", async () => {
|
||||
try {
|
||||
checkLogin(socket);
|
||||
await setSetting("cloudflaredTunnelToken", "");
|
||||
await Settings.set("cloudflaredTunnelToken", "");
|
||||
} catch (error) { }
|
||||
});
|
||||
|
||||
|
@ -96,15 +97,15 @@ module.exports.cloudflaredSocketHandler = (socket) => {
|
|||
*/
|
||||
module.exports.autoStart = async (token) => {
|
||||
if (!token) {
|
||||
token = await setting("cloudflaredTunnelToken");
|
||||
token = await Settings.get("cloudflaredTunnelToken");
|
||||
} else {
|
||||
// Override the current token via args or env var
|
||||
await setSetting("cloudflaredTunnelToken", token);
|
||||
console.log("Use cloudflared token from args or env var");
|
||||
await Settings.set("cloudflaredTunnelToken", token);
|
||||
log.info("cloudflare", "Use cloudflared token from args or env var");
|
||||
}
|
||||
|
||||
if (token) {
|
||||
console.log("Start cloudflared");
|
||||
log.info("cloudflare", "Start cloudflared");
|
||||
cloudflared.token = token;
|
||||
cloudflared.start();
|
||||
}
|
||||
|
|
|
@ -67,7 +67,7 @@ module.exports.maintenanceSocketHandler = (socket) => {
|
|||
});
|
||||
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
log.error("maintenance", e);
|
||||
callback({
|
||||
ok: false,
|
||||
msg: e.message,
|
||||
|
@ -177,7 +177,7 @@ module.exports.maintenanceSocketHandler = (socket) => {
|
|||
ok: true,
|
||||
});
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
log.error("maintenance", e);
|
||||
callback({
|
||||
ok: false,
|
||||
msg: e.message,
|
||||
|
@ -201,7 +201,7 @@ module.exports.maintenanceSocketHandler = (socket) => {
|
|||
});
|
||||
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
log.error("maintenance", e);
|
||||
callback({
|
||||
ok: false,
|
||||
msg: e.message,
|
||||
|
@ -225,7 +225,7 @@ module.exports.maintenanceSocketHandler = (socket) => {
|
|||
});
|
||||
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
log.error("maintenance", e);
|
||||
callback({
|
||||
ok: false,
|
||||
msg: e.message,
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
const { R } = require("redbean-node");
|
||||
const { checkLogin, setSetting } = require("../util-server");
|
||||
const { checkLogin } = require("../util-server");
|
||||
const dayjs = require("dayjs");
|
||||
const { log } = require("../../src/util");
|
||||
const ImageDataURI = require("../image-data-uri");
|
||||
|
@ -7,6 +7,7 @@ const Database = require("../database");
|
|||
const apicache = require("../modules/apicache");
|
||||
const StatusPage = require("../model/status_page");
|
||||
const { UptimeKumaServer } = require("../uptime-kuma-server");
|
||||
const { Settings } = require("../settings");
|
||||
|
||||
/**
|
||||
* Socket handlers for status page
|
||||
|
@ -233,7 +234,7 @@ module.exports.statusPageSocketHandler = (socket) => {
|
|||
// Also change entry page to new slug if it is the default one, and slug is changed.
|
||||
if (server.entryPage === "statusPage-" + slug && statusPage.slug !== slug) {
|
||||
server.entryPage = "statusPage-" + statusPage.slug;
|
||||
await setSetting("entryPage", server.entryPage, "general");
|
||||
await Settings.set("entryPage", server.entryPage, "general");
|
||||
}
|
||||
|
||||
apicache.clear();
|
||||
|
@ -291,7 +292,7 @@ module.exports.statusPageSocketHandler = (socket) => {
|
|||
});
|
||||
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
log.error("socket", error);
|
||||
callback({
|
||||
ok: false,
|
||||
msg: error.message,
|
||||
|
@ -313,7 +314,7 @@ module.exports.statusPageSocketHandler = (socket) => {
|
|||
// Reset entry page if it is the default one.
|
||||
if (server.entryPage === "statusPage-" + slug) {
|
||||
server.entryPage = "dashboard";
|
||||
await setSetting("entryPage", server.entryPage, "general");
|
||||
await Settings.set("entryPage", server.entryPage, "general");
|
||||
}
|
||||
|
||||
// No need to delete records from `status_page_cname`, because it has cascade foreign key.
|
||||
|
|
|
@ -115,6 +115,7 @@ class UptimeKumaServer {
|
|||
UptimeKumaServer.monitorTypeList["mqtt"] = new MqttMonitorType();
|
||||
UptimeKumaServer.monitorTypeList["snmp"] = new SNMPMonitorType();
|
||||
UptimeKumaServer.monitorTypeList["mongodb"] = new MongodbMonitorType();
|
||||
UptimeKumaServer.monitorTypeList["rabbitmq"] = new RabbitMqMonitorType();
|
||||
|
||||
// Allow all CORS origins (polling) in development
|
||||
let cors = undefined;
|
||||
|
@ -552,4 +553,5 @@ const { DnsMonitorType } = require("./monitor-types/dns");
|
|||
const { MqttMonitorType } = require("./monitor-types/mqtt");
|
||||
const { SNMPMonitorType } = require("./monitor-types/snmp");
|
||||
const { MongodbMonitorType } = require("./monitor-types/mongodb");
|
||||
const { RabbitMqMonitorType } = require("./monitor-types/rabbitmq");
|
||||
const Monitor = require("./model/monitor");
|
||||
|
|
|
@ -12,7 +12,6 @@ const { Client } = require("pg");
|
|||
const postgresConParse = require("pg-connection-string").parse;
|
||||
const mysql = require("mysql2");
|
||||
const { NtlmClient } = require("./modules/axios-ntlm/lib/ntlmClient.js");
|
||||
const { Settings } = require("./settings");
|
||||
const grpc = require("@grpc/grpc-js");
|
||||
const protojs = require("protobufjs");
|
||||
const radiusClient = require("node-radius-client");
|
||||
|
@ -521,46 +520,6 @@ exports.redisPingAsync = function (dsn, rejectUnauthorized) {
|
|||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Retrieve value of setting based on key
|
||||
* @param {string} key Key of setting to retrieve
|
||||
* @returns {Promise<any>} Value
|
||||
* @deprecated Use await Settings.get(key)
|
||||
*/
|
||||
exports.setting = async function (key) {
|
||||
return await Settings.get(key);
|
||||
};
|
||||
|
||||
/**
|
||||
* Sets the specified setting to specified value
|
||||
* @param {string} key Key of setting to set
|
||||
* @param {any} value Value to set to
|
||||
* @param {?string} type Type of setting
|
||||
* @returns {Promise<void>}
|
||||
*/
|
||||
exports.setSetting = async function (key, value, type = null) {
|
||||
await Settings.set(key, value, type);
|
||||
};
|
||||
|
||||
/**
|
||||
* Get settings based on type
|
||||
* @param {string} type The type of setting
|
||||
* @returns {Promise<Bean>} Settings of requested type
|
||||
*/
|
||||
exports.getSettings = async function (type) {
|
||||
return await Settings.getSettings(type);
|
||||
};
|
||||
|
||||
/**
|
||||
* Set settings based on type
|
||||
* @param {string} type Type of settings to set
|
||||
* @param {object} data Values of settings
|
||||
* @returns {Promise<void>}
|
||||
*/
|
||||
exports.setSettings = async function (type, data) {
|
||||
await Settings.setSettings(type, data);
|
||||
};
|
||||
|
||||
// ssl-checker by @dyaa
|
||||
//https://github.com/dyaa/ssl-checker/blob/master/src/index.ts
|
||||
|
||||
|
|
|
@ -4,11 +4,17 @@
|
|||
<div
|
||||
v-for="(beat, index) in shortBeatList"
|
||||
:key="index"
|
||||
class="beat"
|
||||
:class="{ 'empty': (beat === 0), 'down': (beat.status === 0), 'pending': (beat.status === 2), 'maintenance': (beat.status === 3) }"
|
||||
:style="beatStyle"
|
||||
class="beat-hover-area"
|
||||
:class="{ 'empty': (beat === 0) }"
|
||||
:style="beatHoverAreaStyle"
|
||||
:title="getBeatTitle(beat)"
|
||||
/>
|
||||
>
|
||||
<div
|
||||
class="beat"
|
||||
:class="{ 'empty': (beat === 0), 'down': (beat.status === 0), 'pending': (beat.status === 2), 'maintenance': (beat.status === 3) }"
|
||||
:style="beatStyle"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
v-if="!$root.isMobile && size !== 'small' && beatList.length > 4 && $root.styleElapsedTime !== 'none'"
|
||||
|
@ -47,7 +53,7 @@ export default {
|
|||
beatWidth: 10,
|
||||
beatHeight: 30,
|
||||
hoverScale: 1.5,
|
||||
beatMargin: 4,
|
||||
beatHoverAreaPadding: 4,
|
||||
move: false,
|
||||
maxBeat: -1,
|
||||
};
|
||||
|
@ -123,7 +129,7 @@ export default {
|
|||
|
||||
barStyle() {
|
||||
if (this.move && this.shortBeatList.length > this.maxBeat) {
|
||||
let width = -(this.beatWidth + this.beatMargin * 2);
|
||||
let width = -(this.beatWidth + this.beatHoverAreaPadding * 2);
|
||||
|
||||
return {
|
||||
transition: "all ease-in-out 0.25s",
|
||||
|
@ -137,12 +143,17 @@ export default {
|
|||
|
||||
},
|
||||
|
||||
beatHoverAreaStyle() {
|
||||
return {
|
||||
padding: this.beatHoverAreaPadding + "px",
|
||||
"--hover-scale": this.hoverScale,
|
||||
};
|
||||
},
|
||||
|
||||
beatStyle() {
|
||||
return {
|
||||
width: this.beatWidth + "px",
|
||||
height: this.beatHeight + "px",
|
||||
margin: this.beatMargin + "px",
|
||||
"--hover-scale": this.hoverScale,
|
||||
};
|
||||
},
|
||||
|
||||
|
@ -152,7 +163,7 @@ export default {
|
|||
*/
|
||||
timeStyle() {
|
||||
return {
|
||||
"margin-left": this.numPadding * (this.beatWidth + this.beatMargin * 2) + "px",
|
||||
"margin-left": this.numPadding * (this.beatWidth + this.beatHoverAreaPadding * 2) + "px",
|
||||
};
|
||||
},
|
||||
|
||||
|
@ -219,20 +230,20 @@ export default {
|
|||
if (this.size !== "big") {
|
||||
this.beatWidth = 5;
|
||||
this.beatHeight = 16;
|
||||
this.beatMargin = 2;
|
||||
this.beatHoverAreaPadding = 2;
|
||||
}
|
||||
|
||||
// Suddenly, have an idea how to handle it universally.
|
||||
// If the pixel * ratio != Integer, then it causes render issue, round it to solve it!!
|
||||
const actualWidth = this.beatWidth * window.devicePixelRatio;
|
||||
const actualMargin = this.beatMargin * window.devicePixelRatio;
|
||||
const actualHoverAreaPadding = this.beatHoverAreaPadding * window.devicePixelRatio;
|
||||
|
||||
if (!Number.isInteger(actualWidth)) {
|
||||
this.beatWidth = Math.round(actualWidth) / window.devicePixelRatio;
|
||||
}
|
||||
|
||||
if (!Number.isInteger(actualMargin)) {
|
||||
this.beatMargin = Math.round(actualMargin) / window.devicePixelRatio;
|
||||
if (!Number.isInteger(actualHoverAreaPadding)) {
|
||||
this.beatHoverAreaPadding = Math.round(actualHoverAreaPadding) / window.devicePixelRatio;
|
||||
}
|
||||
|
||||
window.addEventListener("resize", this.resize);
|
||||
|
@ -245,7 +256,7 @@ export default {
|
|||
*/
|
||||
resize() {
|
||||
if (this.$refs.wrap) {
|
||||
this.maxBeat = Math.floor(this.$refs.wrap.clientWidth / (this.beatWidth + this.beatMargin * 2));
|
||||
this.maxBeat = Math.floor(this.$refs.wrap.clientWidth / (this.beatWidth + this.beatHoverAreaPadding * 2));
|
||||
}
|
||||
},
|
||||
|
||||
|
@ -273,32 +284,41 @@ export default {
|
|||
}
|
||||
|
||||
.hp-bar-big {
|
||||
.beat {
|
||||
.beat-hover-area {
|
||||
display: inline-block;
|
||||
background-color: $primary;
|
||||
border-radius: $border-radius;
|
||||
|
||||
&.empty {
|
||||
background-color: aliceblue;
|
||||
}
|
||||
|
||||
&.down {
|
||||
background-color: $danger;
|
||||
}
|
||||
|
||||
&.pending {
|
||||
background-color: $warning;
|
||||
}
|
||||
|
||||
&.maintenance {
|
||||
background-color: $maintenance;
|
||||
}
|
||||
|
||||
&:not(.empty):hover {
|
||||
transition: all ease-in-out 0.15s;
|
||||
opacity: 0.8;
|
||||
transform: scale(var(--hover-scale));
|
||||
}
|
||||
|
||||
.beat {
|
||||
background-color: $primary;
|
||||
border-radius: $border-radius;
|
||||
|
||||
/*
|
||||
pointer-events needs to be changed because
|
||||
tooltip momentarily disappears when crossing between .beat-hover-area and .beat
|
||||
*/
|
||||
pointer-events: none;
|
||||
|
||||
&.empty {
|
||||
background-color: aliceblue;
|
||||
}
|
||||
|
||||
&.down {
|
||||
background-color: $danger;
|
||||
}
|
||||
|
||||
&.pending {
|
||||
background-color: $warning;
|
||||
}
|
||||
|
||||
&.maintenance {
|
||||
background-color: $maintenance;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1052,6 +1052,13 @@
|
|||
"Can be found on:": "Can be found on: {0}",
|
||||
"The phone number of the recipient in E.164 format.": "The phone number of the recipient in E.164 format.",
|
||||
"Either a text sender ID or a phone number in E.164 format if you want to be able to receive replies.":"Either a text sender ID or a phone number in E.164 format if you want to be able to receive replies.",
|
||||
"RabbitMQ Nodes": "RabbitMQ Management Nodes",
|
||||
"rabbitmqNodesDescription": "Enter the URL for the RabbitMQ management nodes including protocol and port. Example: {0}",
|
||||
"rabbitmqNodesRequired": "Please set the nodes for this monitor.",
|
||||
"rabbitmqNodesInvalid": "Please use a fully qualified (starting with 'http') URL for RabbitMQ nodes.",
|
||||
"RabbitMQ Username": "RabbitMQ Username",
|
||||
"RabbitMQ Password": "RabbitMQ Password",
|
||||
"rabbitmqHelpText": "To use the monitor, you will need to enable the Management Plugin in your RabbitMQ setup. For more information, please consult the {rabitmq_documentation}.",
|
||||
"SendGrid API Key": "SendGrid API Key",
|
||||
"Separate multiple email addresses with commas": "Separate multiple email addresses with commas"
|
||||
}
|
||||
|
|
|
@ -64,6 +64,9 @@
|
|||
<option value="mqtt">
|
||||
MQTT
|
||||
</option>
|
||||
<option value="rabbitmq">
|
||||
RabbitMQ
|
||||
</option>
|
||||
<option value="kafka-producer">
|
||||
Kafka Producer
|
||||
</option>
|
||||
|
@ -90,6 +93,13 @@
|
|||
</option>
|
||||
</optgroup>
|
||||
</select>
|
||||
<i18n-t v-if="monitor.type === 'rabbitmq'" keypath="rabbitmqHelpText" tag="div" class="form-text">
|
||||
<template #rabitmq_documentation>
|
||||
<a href="https://www.rabbitmq.com/management" target="_blank" rel="noopener noreferrer">
|
||||
RabbitMQ documentation
|
||||
</a>
|
||||
</template>
|
||||
</i18n-t>
|
||||
</div>
|
||||
|
||||
<div v-if="monitor.type === 'tailscale-ping'" class="alert alert-warning" role="alert">
|
||||
|
@ -233,6 +243,43 @@
|
|||
</div>
|
||||
</template>
|
||||
|
||||
<template v-if="monitor.type === 'rabbitmq'">
|
||||
<!-- RabbitMQ Nodes List -->
|
||||
<div class="my-3">
|
||||
<label for="rabbitmqNodes" class="form-label">{{ $t("RabbitMQ Nodes") }}</label>
|
||||
<VueMultiselect
|
||||
id="rabbitmqNodes"
|
||||
v-model="monitor.rabbitmqNodes"
|
||||
:required="true"
|
||||
:multiple="true"
|
||||
:options="[]"
|
||||
:placeholder="$t('Enter the list of nodes')"
|
||||
:tag-placeholder="$t('Press Enter to add node')"
|
||||
:max-height="500"
|
||||
:taggable="true"
|
||||
:show-no-options="false"
|
||||
:close-on-select="false"
|
||||
:clear-on-select="false"
|
||||
:preserve-search="false"
|
||||
:preselect-first="false"
|
||||
@tag="addRabbitmqNode"
|
||||
></VueMultiselect>
|
||||
<div class="form-text">
|
||||
{{ $t("rabbitmqNodesDescription", ["https://node1.rabbitmq.com:15672"]) }}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="my-3">
|
||||
<label for="rabbitmqUsername" class="form-label">RabbitMQ {{ $t("RabbitMQ Username") }}</label>
|
||||
<input id="rabbitmqUsername" v-model="monitor.rabbitmqUsername" type="text" required class="form-control">
|
||||
</div>
|
||||
|
||||
<div class="my-3">
|
||||
<label for="rabbitmqPassword" class="form-label">{{ $t("RabbitMQ Password") }}</label>
|
||||
<HiddenInput id="rabbitmqPassword" v-model="monitor.rabbitmqPassword" autocomplete="false" required="true"></HiddenInput>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<!-- Hostname -->
|
||||
<!-- TCP Port / Ping / DNS / Steam / MQTT / Radius / Tailscale Ping / SNMP only -->
|
||||
<div v-if="monitor.type === 'port' || monitor.type === 'ping' || monitor.type === 'dns' || monitor.type === 'steam' || monitor.type === 'gamedig' || monitor.type === 'mqtt' || monitor.type === 'radius' || monitor.type === 'tailscale-ping' || monitor.type === 'snmp'" class="my-3">
|
||||
|
@ -549,7 +596,7 @@
|
|||
</div>
|
||||
|
||||
<!-- Timeout: HTTP / Keyword / SNMP only -->
|
||||
<div v-if="monitor.type === 'http' || monitor.type === 'keyword' || monitor.type === 'json-query' || monitor.type === 'snmp'" class="my-3">
|
||||
<div v-if="monitor.type === 'http' || monitor.type === 'keyword' || monitor.type === 'json-query' || monitor.type === 'snmp' || monitor.type === 'rabbitmq'" class="my-3">
|
||||
<label for="timeout" class="form-label">{{ $t("Request Timeout") }} ({{ $t("timeoutAfter", [ monitor.timeout || clampTimeout(monitor.interval) ]) }})</label>
|
||||
<input id="timeout" v-model="monitor.timeout" type="number" class="form-control" required min="0" step="0.1">
|
||||
</div>
|
||||
|
@ -1122,6 +1169,9 @@ const monitorDefaults = {
|
|||
kafkaProducerAllowAutoTopicCreation: false,
|
||||
gamedigGivenPortOnly: true,
|
||||
remote_browser: null,
|
||||
rabbitmqNodes: [],
|
||||
rabbitmqUsername: "",
|
||||
rabbitmqPassword: "",
|
||||
conditions: []
|
||||
};
|
||||
|
||||
|
@ -1709,6 +1759,10 @@ message HealthCheckResponse {
|
|||
this.monitor.kafkaProducerBrokers.push(newBroker);
|
||||
},
|
||||
|
||||
addRabbitmqNode(newNode) {
|
||||
this.monitor.rabbitmqNodes.push(newNode);
|
||||
},
|
||||
|
||||
/**
|
||||
* Validate form input
|
||||
* @returns {boolean} Is the form input valid?
|
||||
|
@ -1736,6 +1790,17 @@ message HealthCheckResponse {
|
|||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (this.monitor.type === "rabbitmq") {
|
||||
if (this.monitor.rabbitmqNodes.length === 0) {
|
||||
toast.error(this.$t("rabbitmqNodesRequired"));
|
||||
return false;
|
||||
}
|
||||
if (!this.monitor.rabbitmqNodes.every(node => node.startsWith("http://") || node.startsWith("https://"))) {
|
||||
toast.error(this.$t("rabbitmqNodesInvalid"));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
},
|
||||
|
||||
|
|
75
src/util.js
75
src/util.js
|
@ -8,17 +8,34 @@
|
|||
// Backend uses the compiled file util.js
|
||||
// Frontend uses util.ts
|
||||
*/
|
||||
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
||||
if (k2 === undefined) k2 = k;
|
||||
Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } });
|
||||
}) : (function(o, m, k, k2) {
|
||||
if (k2 === undefined) k2 = k;
|
||||
o[k2] = m[k];
|
||||
}));
|
||||
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
||||
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
||||
}) : function(o, v) {
|
||||
o["default"] = v;
|
||||
});
|
||||
var __importStar = (this && this.__importStar) || function (mod) {
|
||||
if (mod && mod.__esModule) return mod;
|
||||
var result = {};
|
||||
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
|
||||
__setModuleDefault(result, mod);
|
||||
return result;
|
||||
};
|
||||
var __importDefault = (this && this.__importDefault) || function (mod) {
|
||||
return (mod && mod.__esModule) ? mod : { "default": mod };
|
||||
};
|
||||
var _a;
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.sleep = exports.flipStatus = exports.badgeConstants = exports.CONSOLE_STYLE_BgGray = exports.CONSOLE_STYLE_BgWhite = exports.CONSOLE_STYLE_BgCyan = exports.CONSOLE_STYLE_BgMagenta = exports.CONSOLE_STYLE_BgBlue = exports.CONSOLE_STYLE_BgYellow = exports.CONSOLE_STYLE_BgGreen = exports.CONSOLE_STYLE_BgRed = exports.CONSOLE_STYLE_BgBlack = exports.CONSOLE_STYLE_FgPink = exports.CONSOLE_STYLE_FgBrown = exports.CONSOLE_STYLE_FgViolet = exports.CONSOLE_STYLE_FgLightBlue = exports.CONSOLE_STYLE_FgLightGreen = exports.CONSOLE_STYLE_FgOrange = exports.CONSOLE_STYLE_FgGray = exports.CONSOLE_STYLE_FgWhite = exports.CONSOLE_STYLE_FgCyan = exports.CONSOLE_STYLE_FgMagenta = exports.CONSOLE_STYLE_FgBlue = exports.CONSOLE_STYLE_FgYellow = exports.CONSOLE_STYLE_FgGreen = exports.CONSOLE_STYLE_FgRed = exports.CONSOLE_STYLE_FgBlack = exports.CONSOLE_STYLE_Hidden = exports.CONSOLE_STYLE_Reverse = exports.CONSOLE_STYLE_Blink = exports.CONSOLE_STYLE_Underscore = exports.CONSOLE_STYLE_Dim = exports.CONSOLE_STYLE_Bright = exports.CONSOLE_STYLE_Reset = exports.MIN_INTERVAL_SECOND = exports.MAX_INTERVAL_SECOND = exports.SQL_DATETIME_FORMAT_WITHOUT_SECOND = exports.SQL_DATETIME_FORMAT = exports.SQL_DATE_FORMAT = exports.STATUS_PAGE_MAINTENANCE = exports.STATUS_PAGE_PARTIAL_DOWN = exports.STATUS_PAGE_ALL_UP = exports.STATUS_PAGE_ALL_DOWN = exports.MAINTENANCE = exports.PENDING = exports.UP = exports.DOWN = exports.appName = exports.isNode = exports.isDev = void 0;
|
||||
exports.evaluateJsonQuery = exports.intHash = exports.localToUTC = exports.utcToLocal = exports.utcToISODateTime = exports.isoToUTCDateTime = exports.parseTimeFromTimeObject = exports.parseTimeObject = exports.getMaintenanceRelativeURL = exports.getMonitorRelativeURL = exports.genSecret = exports.getCryptoRandomInt = exports.getRandomInt = exports.getRandomArbitrary = exports.TimeLogger = exports.polyfill = exports.log = exports.debug = exports.ucfirst = void 0;
|
||||
exports.intHash = exports.localToUTC = exports.utcToLocal = exports.utcToISODateTime = exports.isoToUTCDateTime = exports.parseTimeFromTimeObject = exports.parseTimeObject = exports.getMaintenanceRelativeURL = exports.getMonitorRelativeURL = exports.genSecret = exports.getCryptoRandomInt = exports.getRandomInt = exports.getRandomArbitrary = exports.TimeLogger = exports.polyfill = exports.log = exports.debug = exports.ucfirst = void 0;
|
||||
exports.evaluateJsonQuery = exports.intHash = exports.localToUTC = exports.utcToLocal = exports.utcToISODateTime = exports.isoToUTCDateTime = exports.parseTimeFromTimeObject = exports.parseTimeObject = exports.getMaintenanceRelativeURL = exports.getMonitorRelativeURL = exports.genSecret = exports.getCryptoRandomInt = exports.getRandomInt = exports.getRandomArbitrary = exports.TimeLogger = exports.polyfill = exports.log = exports.ucfirst = void 0;
|
||||
const dayjs_1 = __importDefault(require("dayjs"));
|
||||
const dayjs = require("dayjs");
|
||||
const jsonata = require("jsonata");
|
||||
const jsonata = __importStar(require("jsonata"));
|
||||
exports.isDev = process.env.NODE_ENV === "development";
|
||||
exports.isNode = typeof process !== "undefined" && ((_a = process === null || process === void 0 ? void 0 : process.versions) === null || _a === void 0 ? void 0 : _a.node);
|
||||
exports.appName = "Uptime Kuma";
|
||||
|
@ -66,7 +83,6 @@ exports.CONSOLE_STYLE_BgMagenta = "\x1b[45m";
|
|||
exports.CONSOLE_STYLE_BgCyan = "\x1b[46m";
|
||||
exports.CONSOLE_STYLE_BgWhite = "\x1b[47m";
|
||||
exports.CONSOLE_STYLE_BgGray = "\x1b[100m";
|
||||
|
||||
const consoleModuleColors = [
|
||||
exports.CONSOLE_STYLE_FgCyan,
|
||||
exports.CONSOLE_STYLE_FgGreen,
|
||||
|
@ -125,10 +141,6 @@ function ucfirst(str) {
|
|||
return firstLetter.toUpperCase() + str.substr(1);
|
||||
}
|
||||
exports.ucfirst = ucfirst;
|
||||
function debug(msg) {
|
||||
exports.log.log("", msg, "debug");
|
||||
}
|
||||
exports.debug = debug;
|
||||
class Logger {
|
||||
constructor() {
|
||||
this.hideLog = {
|
||||
|
@ -153,11 +165,9 @@ class Logger {
|
|||
if (level === "DEBUG" && !exports.isDev) {
|
||||
return;
|
||||
}
|
||||
if (this.hideLog[level] && this.hideLog[level].includes(module.toLowerCase())) {
|
||||
if (this.hideLog[level.toLowerCase()] && this.hideLog[level.toLowerCase()].includes(module.toLowerCase())) {
|
||||
return;
|
||||
}
|
||||
module = module.toUpperCase();
|
||||
level = level.toUpperCase();
|
||||
let now;
|
||||
if (dayjs_1.default.tz) {
|
||||
now = dayjs_1.default.tz(new Date()).format();
|
||||
|
@ -167,10 +177,20 @@ class Logger {
|
|||
}
|
||||
const levelColor = consoleLevelColors[level];
|
||||
const moduleColor = consoleModuleColors[intHash(module, consoleModuleColors.length)];
|
||||
let timePart;
|
||||
let modulePart;
|
||||
let levelPart;
|
||||
let msgPart;
|
||||
let timePart = now;
|
||||
let modulePart = module;
|
||||
let levelPart = level;
|
||||
let msgPart = msg;
|
||||
if (process.env.UPTIME_KUMA_LOG_FORMAT === "json") {
|
||||
console.log(JSON.stringify({
|
||||
time: timePart,
|
||||
module: modulePart,
|
||||
level: levelPart,
|
||||
msg: typeof msg === "string" ? msg : JSON.stringify(msg),
|
||||
}));
|
||||
return;
|
||||
}
|
||||
module = module.toUpperCase();
|
||||
if (exports.isNode) {
|
||||
switch (level) {
|
||||
case "DEBUG":
|
||||
|
@ -187,28 +207,17 @@ class Logger {
|
|||
if (typeof msg === "string") {
|
||||
msgPart = exports.CONSOLE_STYLE_FgRed + msg + exports.CONSOLE_STYLE_Reset;
|
||||
}
|
||||
else {
|
||||
msgPart = msg;
|
||||
}
|
||||
break;
|
||||
case "DEBUG":
|
||||
if (typeof msg === "string") {
|
||||
msgPart = exports.CONSOLE_STYLE_FgGray + msg + exports.CONSOLE_STYLE_Reset;
|
||||
}
|
||||
else {
|
||||
msgPart = msg;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
msgPart = msg;
|
||||
break;
|
||||
}
|
||||
}
|
||||
else {
|
||||
timePart = now;
|
||||
modulePart = `[${module}]`;
|
||||
levelPart = `${level}:`;
|
||||
msgPart = msg;
|
||||
}
|
||||
switch (level) {
|
||||
case "ERROR":
|
||||
|
@ -231,23 +240,23 @@ class Logger {
|
|||
}
|
||||
}
|
||||
info(module, msg) {
|
||||
this.log(module, msg, "info");
|
||||
this.log(module, msg, "INFO");
|
||||
}
|
||||
warn(module, msg) {
|
||||
this.log(module, msg, "warn");
|
||||
this.log(module, msg, "WARN");
|
||||
}
|
||||
error(module, msg) {
|
||||
this.log(module, msg, "error");
|
||||
this.log(module, msg, "ERROR");
|
||||
}
|
||||
debug(module, msg) {
|
||||
this.log(module, msg, "debug");
|
||||
this.log(module, msg, "DEBUG");
|
||||
}
|
||||
exception(module, exception, msg) {
|
||||
let finalMessage = exception;
|
||||
if (msg) {
|
||||
finalMessage = `${msg}: ${exception}`;
|
||||
}
|
||||
this.log(module, finalMessage, "error");
|
||||
this.log(module, finalMessage, "ERROR");
|
||||
}
|
||||
}
|
||||
exports.log = new Logger();
|
||||
|
@ -458,4 +467,4 @@ async function evaluateJsonQuery(data, jsonPath, jsonPathOperator, expectedValue
|
|||
throw new Error(`Error evaluating JSON query: ${err.message}. Response from server was: ${response}`);
|
||||
}
|
||||
}
|
||||
exports.evaluateJsonQuery = evaluateJsonQuery;
|
||||
exports.evaluateJsonQuery = evaluateJsonQuery;
|
||||
|
|
69
src/util.ts
69
src/util.ts
|
@ -160,15 +160,6 @@ export function ucfirst(str: string) {
|
|||
return firstLetter.toUpperCase() + str.substr(1);
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated Use log.debug (https://github.com/louislam/uptime-kuma/pull/910)
|
||||
* @param msg Message to write
|
||||
* @returns {void}
|
||||
*/
|
||||
export function debug(msg: unknown) {
|
||||
log.log("", msg, "debug");
|
||||
}
|
||||
|
||||
class Logger {
|
||||
|
||||
/**
|
||||
|
@ -210,23 +201,21 @@ class Logger {
|
|||
|
||||
/**
|
||||
* Write a message to the log
|
||||
* @private
|
||||
* @param module The module the log comes from
|
||||
* @param msg Message to write
|
||||
* @param level Log level. One of INFO, WARN, ERROR, DEBUG or can be customized.
|
||||
* @param level {"INFO"|"WARN"|"ERROR"|"DEBUG"} Log level
|
||||
* @returns {void}
|
||||
*/
|
||||
log(module: string, msg: any, level: string) {
|
||||
log(module: string, msg: unknown, level: "INFO"|"WARN"|"ERROR"|"DEBUG"): void {
|
||||
if (level === "DEBUG" && !isDev) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.hideLog[level] && this.hideLog[level].includes(module.toLowerCase())) {
|
||||
if (this.hideLog[level.toLowerCase()] && this.hideLog[level.toLowerCase()].includes(module.toLowerCase())) {
|
||||
return;
|
||||
}
|
||||
|
||||
module = module.toUpperCase();
|
||||
level = level.toUpperCase();
|
||||
|
||||
let now;
|
||||
if (dayjs.tz) {
|
||||
now = dayjs.tz(new Date()).format();
|
||||
|
@ -237,10 +226,23 @@ class Logger {
|
|||
const levelColor = consoleLevelColors[level];
|
||||
const moduleColor = consoleModuleColors[intHash(module, consoleModuleColors.length)];
|
||||
|
||||
let timePart: string;
|
||||
let modulePart: string;
|
||||
let levelPart: string;
|
||||
let msgPart: string;
|
||||
let timePart: string = now;
|
||||
let modulePart: string = module;
|
||||
let levelPart: string = level;
|
||||
let msgPart: unknown = msg;
|
||||
|
||||
if (process.env.UPTIME_KUMA_LOG_FORMAT === "json") {
|
||||
console.log(JSON.stringify({
|
||||
time: timePart,
|
||||
module: modulePart,
|
||||
level: levelPart,
|
||||
msg: typeof msg === "string" ? msg : JSON.stringify(msg),
|
||||
}));
|
||||
return;
|
||||
}
|
||||
|
||||
// Console rendering:
|
||||
module = module.toUpperCase();
|
||||
|
||||
if (isNode) {
|
||||
// Add console colors
|
||||
|
@ -261,27 +263,18 @@ class Logger {
|
|||
case "ERROR":
|
||||
if (typeof msg === "string") {
|
||||
msgPart = CONSOLE_STYLE_FgRed + msg + CONSOLE_STYLE_Reset;
|
||||
} else {
|
||||
msgPart = msg;
|
||||
}
|
||||
break;
|
||||
case "DEBUG":
|
||||
if (typeof msg === "string") {
|
||||
msgPart = CONSOLE_STYLE_FgGray + msg + CONSOLE_STYLE_Reset;
|
||||
} else {
|
||||
msgPart = msg;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
msgPart = msg;
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
// No console colors
|
||||
timePart = now;
|
||||
modulePart = `[${module}]`;
|
||||
levelPart = `${level}:`;
|
||||
msgPart = msg;
|
||||
}
|
||||
|
||||
// Write to console
|
||||
|
@ -312,8 +305,8 @@ class Logger {
|
|||
* @param msg Message to write
|
||||
* @returns {void}
|
||||
*/
|
||||
info(module: string, msg: unknown) {
|
||||
this.log(module, msg, "info");
|
||||
info(module: string, msg: string): void {
|
||||
this.log(module, msg, "INFO");
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -322,8 +315,8 @@ class Logger {
|
|||
* @param msg Message to write
|
||||
* @returns {void}
|
||||
*/
|
||||
warn(module: string, msg: unknown) {
|
||||
this.log(module, msg, "warn");
|
||||
warn(module: string, msg: string): void {
|
||||
this.log(module, msg, "WARN");
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -332,8 +325,8 @@ class Logger {
|
|||
* @param msg Message to write
|
||||
* @returns {void}
|
||||
*/
|
||||
error(module: string, msg: unknown) {
|
||||
this.log(module, msg, "error");
|
||||
error(module: string, msg: string): void {
|
||||
this.log(module, msg, "ERROR");
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -342,8 +335,8 @@ class Logger {
|
|||
* @param msg Message to write
|
||||
* @returns {void}
|
||||
*/
|
||||
debug(module: string, msg: unknown) {
|
||||
this.log(module, msg, "debug");
|
||||
debug(module: string, msg: string): void {
|
||||
this.log(module, msg, "DEBUG");
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -360,7 +353,7 @@ class Logger {
|
|||
finalMessage = `${msg}: ${exception}`;
|
||||
}
|
||||
|
||||
this.log(module, finalMessage, "error");
|
||||
this.log(module, finalMessage, "ERROR");
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -404,7 +397,7 @@ export class TimeLogger {
|
|||
* @param name Name of monitor
|
||||
* @returns {void}
|
||||
*/
|
||||
print(name: string) {
|
||||
print(name: string): void {
|
||||
if (isDev && process.env.TIMELOGGER === "1") {
|
||||
console.log(name + ": " + (dayjs().valueOf() - this.startTime) + "ms");
|
||||
}
|
||||
|
|
53
test/backend-test/test-rabbitmq.js
Normal file
53
test/backend-test/test-rabbitmq.js
Normal file
|
@ -0,0 +1,53 @@
|
|||
const { describe, test } = require("node:test");
|
||||
const assert = require("node:assert");
|
||||
const { RabbitMQContainer } = require("@testcontainers/rabbitmq");
|
||||
const { RabbitMqMonitorType } = require("../../server/monitor-types/rabbitmq");
|
||||
const { UP, DOWN, PENDING } = require("../../src/util");
|
||||
|
||||
describe("RabbitMQ Single Node", {
|
||||
skip: !!process.env.CI && (process.platform !== "linux" || process.arch !== "x64"),
|
||||
}, () => {
|
||||
test("RabbitMQ is running", async () => {
|
||||
// The default timeout of 30 seconds might not be enough for the container to start
|
||||
const rabbitMQContainer = await new RabbitMQContainer().withStartupTimeout(60000).start();
|
||||
const rabbitMQMonitor = new RabbitMqMonitorType();
|
||||
const connectionString = `http://${rabbitMQContainer.getHost()}:${rabbitMQContainer.getMappedPort(15672)}`;
|
||||
|
||||
const monitor = {
|
||||
rabbitmqNodes: JSON.stringify([ connectionString ]),
|
||||
rabbitmqUsername: "guest",
|
||||
rabbitmqPassword: "guest",
|
||||
};
|
||||
|
||||
const heartbeat = {
|
||||
msg: "",
|
||||
status: PENDING,
|
||||
};
|
||||
|
||||
try {
|
||||
await rabbitMQMonitor.check(monitor, heartbeat, {});
|
||||
assert.strictEqual(heartbeat.status, UP);
|
||||
assert.strictEqual(heartbeat.msg, "OK");
|
||||
} finally {
|
||||
rabbitMQContainer.stop();
|
||||
}
|
||||
});
|
||||
|
||||
test("RabbitMQ is not running", async () => {
|
||||
const rabbitMQMonitor = new RabbitMqMonitorType();
|
||||
const monitor = {
|
||||
rabbitmqNodes: JSON.stringify([ "http://localhost:15672" ]),
|
||||
rabbitmqUsername: "rabbitmqUser",
|
||||
rabbitmqPassword: "rabbitmqPass",
|
||||
};
|
||||
|
||||
const heartbeat = {
|
||||
msg: "",
|
||||
status: PENDING,
|
||||
};
|
||||
|
||||
await rabbitMQMonitor.check(monitor, heartbeat, {});
|
||||
assert.strictEqual(heartbeat.status, DOWN);
|
||||
});
|
||||
|
||||
});
|
Loading…
Reference in a new issue