mirror of
https://github.com/louislam/uptime-kuma.git
synced 2026-05-17 08:26:56 +03:00
feat: structured logging (JSON) (#5179)
Co-authored-by: Frank Elsinga <frank@elsinga.de> Co-authored-by: Louis Lam <louislam@users.noreply.github.com>
This commit is contained in:
@@ -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");
|
||||
@@ -137,7 +136,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);
|
||||
|
||||
@@ -598,12 +598,12 @@ class Database {
|
||||
let title = await setting("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;
|
||||
}
|
||||
|
||||
@@ -645,7 +645,7 @@ class Database {
|
||||
await setSetting("entryPage", "statusPage-default", "general");
|
||||
}
|
||||
|
||||
console.log("Migrating Status Page - Done");
|
||||
log.info("database", "Migrating Status Page - Done");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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 {
|
||||
@@ -93,7 +93,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";
|
||||
@@ -91,7 +91,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 {
|
||||
@@ -79,7 +79,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";
|
||||
@@ -50,7 +50,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,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 {
|
||||
@@ -94,7 +94,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)}`;
|
||||
}
|
||||
|
||||
@@ -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"];
|
||||
}
|
||||
|
||||
|
||||
@@ -1584,7 +1584,7 @@ let needSetup = false;
|
||||
msg,
|
||||
});
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
log.error("server", e);
|
||||
|
||||
callback({
|
||||
ok: false,
|
||||
|
||||
@@ -59,7 +59,7 @@ module.exports.apiKeySocketHandler = (socket) => {
|
||||
ok: true,
|
||||
});
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
log.error("apikeys", e);
|
||||
callback({
|
||||
ok: false,
|
||||
msg: e.message,
|
||||
|
||||
@@ -106,11 +106,11 @@ module.exports.autoStart = async (token) => {
|
||||
} else {
|
||||
// Override the current token via args or env var
|
||||
await setSetting("cloudflaredTunnelToken", token);
|
||||
console.log("Use cloudflared token from args or env var");
|
||||
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();
|
||||
}
|
||||
|
||||
@@ -65,7 +65,7 @@ module.exports.maintenanceSocketHandler = (socket) => {
|
||||
maintenanceID: bean.id,
|
||||
});
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
log.error("maintenance", e);
|
||||
callback({
|
||||
ok: false,
|
||||
msg: e.message,
|
||||
@@ -165,7 +165,7 @@ module.exports.maintenanceSocketHandler = (socket) => {
|
||||
ok: true,
|
||||
});
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
log.error("maintenance", e);
|
||||
callback({
|
||||
ok: false,
|
||||
msg: e.message,
|
||||
@@ -189,7 +189,7 @@ module.exports.maintenanceSocketHandler = (socket) => {
|
||||
monitors,
|
||||
});
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
log.error("maintenance", e);
|
||||
callback({
|
||||
ok: false,
|
||||
msg: e.message,
|
||||
@@ -213,7 +213,7 @@ module.exports.maintenanceSocketHandler = (socket) => {
|
||||
statusPages,
|
||||
});
|
||||
} 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");
|
||||
|
||||
/**
|
||||
* Validates incident data
|
||||
@@ -412,7 +413,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();
|
||||
@@ -469,7 +470,7 @@ module.exports.statusPageSocketHandler = (socket) => {
|
||||
slug: slug,
|
||||
});
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
log.error("socket", error);
|
||||
callback({
|
||||
ok: false,
|
||||
msg: error.message,
|
||||
@@ -490,7 +491,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.
|
||||
|
||||
37
src/util.js
37
src/util.js
@@ -136,7 +136,7 @@ function ucfirst(str) {
|
||||
}
|
||||
exports.ucfirst = ucfirst;
|
||||
function debug(msg) {
|
||||
exports.log.log("", "debug", msg);
|
||||
exports.log.log("", "DEBUG", msg);
|
||||
}
|
||||
exports.debug = debug;
|
||||
class Logger {
|
||||
@@ -167,7 +167,6 @@ class Logger {
|
||||
return;
|
||||
}
|
||||
module = module.toUpperCase();
|
||||
level = level.toUpperCase();
|
||||
let now;
|
||||
if (dayjs.tz) {
|
||||
now = dayjs.tz(new Date()).format();
|
||||
@@ -175,6 +174,30 @@ class Logger {
|
||||
else {
|
||||
now = dayjs().format();
|
||||
}
|
||||
if (process.env.UPTIME_KUMA_LOG_FORMAT === "json") {
|
||||
const msgString = msg
|
||||
.map((m) => {
|
||||
if (typeof m === "string") {
|
||||
return m;
|
||||
}
|
||||
else {
|
||||
try {
|
||||
return JSON.stringify(m);
|
||||
}
|
||||
catch (_a) {
|
||||
return String(m);
|
||||
}
|
||||
}
|
||||
})
|
||||
.join(" ");
|
||||
console.log(JSON.stringify({
|
||||
time: now,
|
||||
module: module,
|
||||
level: level,
|
||||
msg: msgString,
|
||||
}));
|
||||
return;
|
||||
}
|
||||
const levelColor = consoleLevelColors[level];
|
||||
const moduleColor = consoleModuleColors[intHash(module, consoleModuleColors.length)];
|
||||
let timePart;
|
||||
@@ -218,19 +241,19 @@ class Logger {
|
||||
}
|
||||
}
|
||||
info(module, ...msg) {
|
||||
this.log(module, "info", ...msg);
|
||||
this.log(module, "INFO", ...msg);
|
||||
}
|
||||
warn(module, ...msg) {
|
||||
this.log(module, "warn", ...msg);
|
||||
this.log(module, "WARN", ...msg);
|
||||
}
|
||||
error(module, ...msg) {
|
||||
this.log(module, "error", ...msg);
|
||||
this.log(module, "ERROR", ...msg);
|
||||
}
|
||||
debug(module, ...msg) {
|
||||
this.log(module, "debug", ...msg);
|
||||
this.log(module, "DEBUG", ...msg);
|
||||
}
|
||||
exception(module, exception, ...msg) {
|
||||
this.log(module, "error", ...msg, exception);
|
||||
this.log(module, "ERROR", ...msg, exception);
|
||||
}
|
||||
}
|
||||
exports.log = new Logger();
|
||||
|
||||
43
src/util.ts
43
src/util.ts
@@ -206,7 +206,7 @@ export function ucfirst(str: string) {
|
||||
* @returns {void}
|
||||
*/
|
||||
export function debug(msg: unknown) {
|
||||
log.log("", "debug", msg);
|
||||
log.log("", "DEBUG", msg);
|
||||
}
|
||||
|
||||
class Logger {
|
||||
@@ -254,7 +254,7 @@ class Logger {
|
||||
* @param msg Message to write
|
||||
* @returns {void}
|
||||
*/
|
||||
log(module: string, level: string, ...msg: unknown[]) {
|
||||
log(module: string, level: "INFO" | "WARN" | "ERROR" | "DEBUG", ...msg: unknown[]) {
|
||||
if (level === "DEBUG" && !isDev) {
|
||||
return;
|
||||
}
|
||||
@@ -264,7 +264,6 @@ class Logger {
|
||||
}
|
||||
|
||||
module = module.toUpperCase();
|
||||
level = level.toUpperCase();
|
||||
|
||||
let now;
|
||||
if (dayjs.tz) {
|
||||
@@ -273,6 +272,32 @@ class Logger {
|
||||
now = dayjs().format();
|
||||
}
|
||||
|
||||
if (process.env.UPTIME_KUMA_LOG_FORMAT === "json") {
|
||||
const msgString = msg
|
||||
.map((m) => {
|
||||
if (typeof m === "string") {
|
||||
return m;
|
||||
} else {
|
||||
try {
|
||||
return JSON.stringify(m);
|
||||
} catch {
|
||||
return String(m);
|
||||
}
|
||||
}
|
||||
})
|
||||
.join(" ");
|
||||
|
||||
console.log(
|
||||
JSON.stringify({
|
||||
time: now,
|
||||
module: module,
|
||||
level: level,
|
||||
msg: msgString,
|
||||
})
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
const levelColor = consoleLevelColors[level];
|
||||
const moduleColor = consoleModuleColors[intHash(module, consoleModuleColors.length)];
|
||||
|
||||
@@ -329,7 +354,7 @@ class Logger {
|
||||
* @returns {void}
|
||||
*/
|
||||
info(module: string, ...msg: unknown[]) {
|
||||
this.log(module, "info", ...msg);
|
||||
this.log(module, "INFO", ...msg);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -339,7 +364,7 @@ class Logger {
|
||||
* @returns {void}
|
||||
*/
|
||||
warn(module: string, ...msg: unknown[]) {
|
||||
this.log(module, "warn", ...msg);
|
||||
this.log(module, "WARN", ...msg);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -349,7 +374,7 @@ class Logger {
|
||||
* @returns {void}
|
||||
*/
|
||||
error(module: string, ...msg: unknown[]) {
|
||||
this.log(module, "error", ...msg);
|
||||
this.log(module, "ERROR", ...msg);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -359,7 +384,7 @@ class Logger {
|
||||
* @returns {void}
|
||||
*/
|
||||
debug(module: string, ...msg: unknown[]) {
|
||||
this.log(module, "debug", ...msg);
|
||||
this.log(module, "DEBUG", ...msg);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -370,7 +395,7 @@ class Logger {
|
||||
* @returns {void}
|
||||
*/
|
||||
exception(module: string, exception: unknown, ...msg: unknown[]) {
|
||||
this.log(module, "error", ...msg, exception);
|
||||
this.log(module, "ERROR", ...msg, exception);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -418,7 +443,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");
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user