Rework logging colors (#3350)

- Replacing old package `colors` by drop-in replacement `ansis`
- Rework `console-stamp` config to show all Log outputs in same color
(errors = red, warnings = yellow, debug = blue background (only for the
label), info = blue)
- This also fixes `npm run config:check` (broken since
6097547c103be1bc89c572e5bd2be50b342967fa)

Feel free to let me know if the PR is too big and you want me to do
individual PRs for the changes.

Before:

![before](https://github.com/MagicMirrorOrg/MagicMirror/assets/35647502/88e48ec3-102c-40f3-9e9b-5d14fe446a43)

After:

![after](https://github.com/MagicMirrorOrg/MagicMirror/assets/35647502/4c8c4bad-08c9-46a3-92c9-14b996c13a7d)

---------

Co-authored-by: Veeck <github@veeck.de>
This commit is contained in:
Kristjan ESPERANTO 2024-01-16 21:54:55 +01:00 committed by GitHub
parent 098757f248
commit 6dbacbb773
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
9 changed files with 62 additions and 64 deletions

View File

@ -17,6 +17,7 @@ _This release is scheduled to be released on 2024-04-01._
- Removing lodash dependency by replacing merge by spread operator (#3339) - Removing lodash dependency by replacing merge by spread operator (#3339)
- Use node prefix for build-in modules (#3340) - Use node prefix for build-in modules (#3340)
- Rework logging colors (#3350)
- Update electron to v28 and update other dependencies - Update electron to v28 and update other dependencies
### Fixed ### Fixed

View File

@ -126,11 +126,11 @@ function App () {
return Object.assign(defaults, c); return Object.assign(defaults, c);
} catch (e) { } catch (e) {
if (e.code === "ENOENT") { if (e.code === "ENOENT") {
Log.error(Utils.colors.error("WARNING! Could not find config file. Please create one. Starting with default configuration.")); Log.error("WARNING! Could not find config file. Please create one. Starting with default configuration.");
} else if (e instanceof ReferenceError || e instanceof SyntaxError) { } else if (e instanceof ReferenceError || e instanceof SyntaxError) {
Log.error(Utils.colors.error(`WARNING! Could not validate config file. Starting with default configuration. Please correct syntax errors at or above this line: ${e.stack}`)); Log.error(`WARNING! Could not validate config file. Starting with default configuration. Please correct syntax errors at or above this line: ${e.stack}`);
} else { } else {
Log.error(Utils.colors.error(`WARNING! Could not load config file. Starting with default configuration. Error found: ${e}`)); Log.error(`WARNING! Could not load config file. Starting with default configuration. Error found: ${e}`);
} }
} }
@ -148,7 +148,7 @@ function App () {
const usedDeprecated = deprecatedOptions.filter((option) => userConfig.hasOwnProperty(option)); const usedDeprecated = deprecatedOptions.filter((option) => userConfig.hasOwnProperty(option));
if (usedDeprecated.length > 0) { if (usedDeprecated.length > 0) {
Log.warn(Utils.colors.warn(`WARNING! Your config is using deprecated options: ${usedDeprecated.join(", ")}. Check README and CHANGELOG for more up-to-date ways of getting the same functionality.`)); Log.warn(`WARNING! Your config is using deprecated options: ${usedDeprecated.join(", ")}. Check README and CHANGELOG for more up-to-date ways of getting the same functionality.`);
} }
} }

View File

@ -7,13 +7,13 @@
*/ */
const path = require("node:path"); const path = require("node:path");
const fs = require("node:fs"); const fs = require("node:fs");
const colors = require("ansis");
const { Linter } = require("eslint"); const { Linter } = require("eslint");
const linter = new Linter(); const linter = new Linter();
const rootPath = path.resolve(`${__dirname}/../`); const rootPath = path.resolve(`${__dirname}/../`);
const Log = require(`${rootPath}/js/logger.js`); const Log = require(`${rootPath}/js/logger.js`);
const Utils = require(`${rootPath}/js/utils.js`);
/** /**
* Returns a string with path of configuration file. * Returns a string with path of configuration file.
@ -33,7 +33,7 @@ function checkConfigFile () {
// Check if file is present // Check if file is present
if (fs.existsSync(configFileName) === false) { if (fs.existsSync(configFileName) === false) {
Log.error(Utils.colors.error("File not found: "), configFileName); Log.error(`File not found: ${configFileName}`);
throw new Error("No config file present!"); throw new Error("No config file present!");
} }
@ -41,12 +41,12 @@ function checkConfigFile () {
try { try {
fs.accessSync(configFileName, fs.F_OK); fs.accessSync(configFileName, fs.F_OK);
} catch (e) { } catch (e) {
Log.error(Utils.colors.error(e)); Log.error(e);
throw new Error("No permission to access config file!"); throw new Error("No permission to access config file!");
} }
// Validate syntax of the configuration file. // Validate syntax of the configuration file.
Log.info(Utils.colors.info("Checking file... "), configFileName); Log.info("Checking file... ", configFileName);
// I'm not sure if all ever is utf-8 // I'm not sure if all ever is utf-8
const configFile = fs.readFileSync(configFileName, "utf-8"); const configFile = fs.readFileSync(configFileName, "utf-8");
@ -59,9 +59,9 @@ function checkConfigFile () {
}); });
if (errors.length === 0) { if (errors.length === 0) {
Log.info(Utils.colors.pass("Your configuration file doesn't contain syntax errors :)")); Log.info(colors.green("Your configuration file doesn't contain syntax errors :)"));
} else { } else {
Log.error(Utils.colors.error("Your configuration file contains syntax errors :(")); Log.error(colors.red("Your configuration file contains syntax errors :("));
for (const error of errors) { for (const error of errors) {
Log.error(`Line ${error.line} column ${error.column}: ${error.message}`); Log.error(`Line ${error.line} column ${error.column}: ${error.message}`);

View File

@ -10,10 +10,39 @@
(function (root, factory) { (function (root, factory) {
if (typeof exports === "object") { if (typeof exports === "object") {
if (process.env.JEST_WORKER_ID === undefined) { if (process.env.JEST_WORKER_ID === undefined) {
const colors = require("ansis");
// add timestamps in front of log messages // add timestamps in front of log messages
require("console-stamp")(console, { require("console-stamp")(console, {
pattern: "yyyy-mm-dd HH:MM:ss.l", format: ":date(yyyy-mm-dd HH:MM:ss.l) :label(7) :msg",
include: ["debug", "log", "info", "warn", "error"] tokens: {
label: (arg) => {
const { method, defaultTokens } = arg;
let label = defaultTokens.label(arg);
if (method === "error") {
label = colors.red(label);
} else if (method === "warn") {
label = colors.yellow(label);
} else if (method === "debug") {
label = colors.bgBlue(label);
} else if (method === "info") {
label = colors.blue(label);
}
return label;
},
msg: (arg) => {
const { method, defaultTokens } = arg;
let msg = defaultTokens.msg(arg);
if (method === "error") {
msg = colors.red(msg);
} else if (method === "warn") {
msg = colors.yellow(msg);
} else if (method === "info") {
msg = colors.blue(msg);
}
return msg;
}
}
}); });
} }
// Node, CommonJS-like // Node, CommonJS-like

View File

@ -62,7 +62,7 @@ function Server (config) {
server.listen(port, config.address || "localhost"); server.listen(port, config.address || "localhost");
if (config.ipWhitelist instanceof Array && config.ipWhitelist.length === 0) { if (config.ipWhitelist instanceof Array && config.ipWhitelist.length === 0) {
Log.warn(Utils.colors.warn("You're using a full whitelist configuration to allow for all IPs")); Log.warn("You're using a full whitelist configuration to allow for all IPs");
} }
app.use(function (req, res, next) { app.use(function (req, res, next) {

View File

@ -1,21 +1,13 @@
/* MagicMirror² /* MagicMirror²
* Utils * Utils
* *
* By Rodrigo Ramírez Norambuena https://rodrigoramirez.com
* MIT Licensed. * MIT Licensed.
*/ */
const execSync = require("node:child_process").execSync; const execSync = require("node:child_process").execSync;
const colors = require("colors/safe");
const Log = require("logger"); const Log = require("logger");
const si = require("systeminformation"); const si = require("systeminformation");
module.exports = { module.exports = {
colors: {
warn: colors.yellow,
error: colors.red,
info: colors.blue,
pass: colors.green
},
async logSystemInformation () { async logSystemInformation () {
try { try {
@ -32,6 +24,9 @@ module.exports = {
systemDataString += `\n### VERSIONS: electron: ${process.versions.electron}; used node: ${staticData["versions"]["node"]}; installed node: ${installedNodeVersion}; npm: ${staticData["versions"]["npm"]}; pm2: ${staticData["versions"]["pm2"]}`; systemDataString += `\n### VERSIONS: electron: ${process.versions.electron}; used node: ${staticData["versions"]["node"]}; installed node: ${installedNodeVersion}; npm: ${staticData["versions"]["npm"]}; pm2: ${staticData["versions"]["pm2"]}`;
systemDataString += `\n### OTHER: timeZone: ${Intl.DateTimeFormat().resolvedOptions().timeZone}; ELECTRON_ENABLE_GPU: ${process.env.ELECTRON_ENABLE_GPU}`; systemDataString += `\n### OTHER: timeZone: ${Intl.DateTimeFormat().resolvedOptions().timeZone}; ELECTRON_ENABLE_GPU: ${process.env.ELECTRON_ENABLE_GPU}`;
Log.info(systemDataString); Log.info(systemDataString);
// Return is currently only for jest
return systemDataString;
} catch (e) { } catch (e) {
Log.error(e); Log.error(e);
} }

22
package-lock.json generated
View File

@ -10,7 +10,7 @@
"hasInstallScript": true, "hasInstallScript": true,
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"colors": "^1.4.0", "ansis": "^2.0.3",
"command-exists": "^1.2.9", "command-exists": "^1.2.9",
"console-stamp": "^3.1.2", "console-stamp": "^3.1.2",
"envsub": "^4.1.0", "envsub": "^4.1.0",
@ -2159,6 +2159,18 @@
"url": "https://github.com/chalk/ansi-styles?sponsor=1" "url": "https://github.com/chalk/ansi-styles?sponsor=1"
} }
}, },
"node_modules/ansis": {
"version": "2.0.3",
"resolved": "https://registry.npmjs.org/ansis/-/ansis-2.0.3.tgz",
"integrity": "sha512-tcSGX0mhuDFHsgRrT56xnZ9v2X+TOeKhJ75YopI5OBgyT7tGaG5m6BmeC+6KHjiucfBvUHehQMecHbULIAkFPA==",
"engines": {
"node": ">=12.13"
},
"funding": {
"type": "patreon",
"url": "https://patreon.com/biodiscus"
}
},
"node_modules/anymatch": { "node_modules/anymatch": {
"version": "3.1.3", "version": "3.1.3",
"resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz",
@ -2952,14 +2964,6 @@
"integrity": "sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w==", "integrity": "sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w==",
"dev": true "dev": true
}, },
"node_modules/colors": {
"version": "1.4.0",
"resolved": "https://registry.npmjs.org/colors/-/colors-1.4.0.tgz",
"integrity": "sha512-a+UqTh4kgZg/SlGvfbzDHpgRu7AAQOmmqRHJnxhRZICKFUT91brVhNNt58CMWU9PsBbv3PDCZUHbVxuDiH2mtA==",
"engines": {
"node": ">=0.1.90"
}
},
"node_modules/combined-stream": { "node_modules/combined-stream": {
"version": "1.0.8", "version": "1.0.8",
"resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz",

View File

@ -71,7 +71,7 @@
"electron": "^28.1.3" "electron": "^28.1.3"
}, },
"dependencies": { "dependencies": {
"colors": "^1.4.0", "ansis": "^2.0.3",
"command-exists": "^1.2.9", "command-exists": "^1.2.9",
"console-stamp": "^3.1.2", "console-stamp": "^3.1.2",
"envsub": "^4.1.0", "envsub": "^4.1.0",

View File

@ -1,38 +1,7 @@
const colors = require("colors/safe");
const Utils = require("../../../js/utils"); const Utils = require("../../../js/utils");
describe("Utils", () => { describe("Utils", () => {
describe("colors", () => { it("should output system information", async () => {
const colorsEnabled = colors.enabled; await expect(Utils.logSystemInformation()).resolves.toContain("platform: linux");
afterEach(() => {
colors.enabled = colorsEnabled;
});
it("should have info, warn and error properties", () => {
expect(Utils.colors).toHaveProperty("info");
expect(Utils.colors).toHaveProperty("warn");
expect(Utils.colors).toHaveProperty("error");
});
it("properties should be functions", () => {
expect(typeof Utils.colors.info).toBe("function");
expect(typeof Utils.colors.warn).toBe("function");
expect(typeof Utils.colors.error).toBe("function");
});
it("should print colored message in supported consoles", () => {
colors.enabled = true;
expect(Utils.colors.info("some informations")).toBe("\u001b[34msome informations\u001b[39m");
expect(Utils.colors.warn("a warning")).toBe("\u001b[33ma warning\u001b[39m");
expect(Utils.colors.error("ERROR!")).toBe("\u001b[31mERROR!\u001b[39m");
});
it("should print message in unsupported consoles", () => {
colors.enabled = false;
expect(Utils.colors.info("some informations")).toBe("some informations");
expect(Utils.colors.warn("a warning")).toBe("a warning");
expect(Utils.colors.error("ERROR!")).toBe("ERROR!");
});
}); });
}); });