diff --git a/src/pages/api/services/proxy.js b/src/pages/api/services/proxy.js index 1cc5a244d..5b1cbd938 100644 --- a/src/pages/api/services/proxy.js +++ b/src/pages/api/services/proxy.js @@ -1,4 +1,4 @@ -import logger from "utils/logger"; +import createLogger from "utils/logger"; import genericProxyHandler from "utils/proxies/generic"; import credentialedProxyHandler from "utils/proxies/credentialed"; import rutorrentProxyHandler from "utils/proxies/rutorrent"; @@ -7,6 +7,8 @@ import npmProxyHandler from "utils/proxies/npm"; import transmissionProxyHandler from "utils/proxies/transmission"; import qbittorrentProxyHandler from "utils/proxies/qbittorrent"; +const logger = createLogger('servicesProxy'); + function asJson(data) { if (data?.length > 0) { const json = JSON.parse(data.toString()); diff --git a/src/pages/index.jsx b/src/pages/index.jsx index db2bba85e..16cb836f6 100644 --- a/src/pages/index.jsx +++ b/src/pages/index.jsx @@ -10,6 +10,7 @@ import ServicesGroup from "components/services/group"; import BookmarksGroup from "components/bookmarks/group"; import Widget from "components/widget"; import Revalidate from "components/revalidate"; +import createLogger from "utils/logger"; import { getSettings } from "utils/config"; import { ColorContext } from "utils/color-context"; import { ThemeContext } from "utils/theme-context"; @@ -26,7 +27,9 @@ const ColorToggle = dynamic(() => import("components/color-toggle"), { const rightAlignedWidgets = ["weatherapi", "openweathermap", "weather", "search", "datetime"]; export function getStaticProps() { + let logger; try { + logger = createLogger('index'); const { providers, ...settings } = getSettings(); return { @@ -35,6 +38,7 @@ export function getStaticProps() { }, }; } catch (e) { + if (logger) { logger.error(e); } return { props: { initialSettings: {}, diff --git a/src/utils/logger.js b/src/utils/logger.js index a4d0f1fea..5bc0ed373 100644 --- a/src/utils/logger.js +++ b/src/utils/logger.js @@ -1,80 +1,88 @@ +/* eslint-disable no-console */ import { join } from "path"; +import { format as utilFormat } from "node:util" import winston from "winston"; -const configPath = join(process.cwd(), "config"); +let winstonLogger; -function messageFormatter(logInfo) { - if (logInfo.stack) { - return `[${logInfo.timestamp}] ${logInfo.level}: ${logInfo.stack}`; - } - return `[${logInfo.timestamp}] ${logInfo.level}: ${logInfo.message}`; -}; - -const consoleFormat = winston.format.combine( - winston.format.errors({ stack: true }), - winston.format.splat(), - winston.format.timestamp(), - winston.format.colorize(), - winston.format.printf(messageFormatter) -); - -const fileFormat = winston.format.combine( - winston.format.errors({ stack: true }), - winston.format.splat(), - winston.format.timestamp(), - winston.format.printf(messageFormatter) -); +function init() { + const configPath = join(process.cwd(), "config"); -const logger = winston.createLogger({ - level: process.env.LOG_LEVEL || 'info', - transports: [ - new winston.transports.Console({ - format: consoleFormat, - handleExceptions: true, - handleRejections: true - }), - - new winston.transports.File({ - format: fileFormat, - filename: `${configPath}/logs/homepage.log`, - handleExceptions: true, - handleRejections: true - }), - ] -}); - -function debug(message, ...args) { - logger.debug(message, ...args); -} + function combineMessageAndSplat() { + return { + // eslint-disable-next-line no-unused-vars + transform: (info, opts) => { + // combine message and args if any + // eslint-disable-next-line no-param-reassign + info.message = utilFormat(info.message, ...info[Symbol.for('splat')] || []); + return info; + } + } + } -function verbose(message, ...args) { - logger.verbose(message, ...args); -} + function messageFormatter(logInfo) { + if (logInfo.label) { + if (logInfo.stack) { + return `[${logInfo.timestamp}] ${logInfo.level}: <${logInfo.label}> ${logInfo.stack}`; + } + return `[${logInfo.timestamp}] ${logInfo.level}: <${logInfo.label}> ${logInfo.message}`; + } -function info(message, ...args) { - logger.info(message, ...args); -} + if (logInfo.stack) { + return `[${logInfo.timestamp}] ${logInfo.level}: ${logInfo.stack}`; + } + return `[${logInfo.timestamp}] ${logInfo.level}: ${logInfo.message}`; + }; -function warn(message, ...args) { - logger.warn(message, ...args); -} + winstonLogger = winston.createLogger({ + level: process.env.LOG_LEVEL || 'info', + transports: [ + new winston.transports.Console({ + format: winston.format.combine( + winston.format.errors({ stack: true}), + combineMessageAndSplat(), + winston.format.timestamp(), + winston.format.colorize(), + winston.format.printf(messageFormatter) + ), + handleExceptions: true, + handleRejections: true + }), -function error(message, ...args) { - logger.error(message, ...args); -} + new winston.transports.File({ + format: winston.format.combine( + winston.format.errors({ stack: true}), + combineMessageAndSplat(), + winston.format.timestamp(), + winston.format.printf(messageFormatter) + ), + filename: `${configPath}/logs/homepage.log`, + handleExceptions: true, + handleRejections: true + }), + ] + }); -function crit(message, ...args) { - logger.crit(message, ...args); + // patch the console log mechanism to use our logger + const consoleMethods = ['log', 'debug', 'info', 'warn', 'error'] + consoleMethods.forEach(method => { + // workaround for https://github.com/winstonjs/winston/issues/1591 + switch (method) { + case 'log': + console[method] = winstonLogger.info.bind(winstonLogger); + break; + default: + console[method] = winstonLogger[method].bind(winstonLogger); + break; + } + }) } -const thisModule = { - debug, - verbose, - info, - warn, - error, - crit -}; +export default function createLogger(label) { + if (!winstonLogger) { + init(); + } -export default thisModule; \ No newline at end of file + return winstonLogger.child({ label }); +} \ No newline at end of file diff --git a/src/utils/proxies/generic.js b/src/utils/proxies/generic.js index 06c6bbf46..70dab4aa1 100644 --- a/src/utils/proxies/generic.js +++ b/src/utils/proxies/generic.js @@ -1,7 +1,9 @@ import getServiceWidget from "utils/service-helpers"; import { formatApiCall } from "utils/api-helpers"; import { httpProxy } from "utils/http"; -import logger from "utils/logger"; +import createLogger from "utils/logger"; + +const logger = createLogger('genericProxyHandler'); export default async function genericProxyHandler(req, res, maps) { const { group, service, endpoint } = req.query;