@underpostnet/underpost
Version:
Underpost Platform — end-to-end CI/CD and application-delivery toolchain CLI. Covers bare metal, Kubernetes, K3s, kubeadm, LXD, container/image orchestration, secrets, databases, cron jobs, monitoring, SSH, runners, PWA + Workbox delivery, and release orc
230 lines (210 loc) • 9.37 kB
JavaScript
/**
* Module for managing logger control and configuration
* @module src/server/logger.js
* @namespace Logger
*/
;
import winston from 'winston';
import morgan from 'morgan';
import { colorize, color } from 'json-colorizer';
import colors from 'colors';
import v8 from 'v8';
import { clearTerminalStringColor, formatBytes } from '../client/components/core/CommonJs.js';
colors.enable();
// Define your severity levels.
// With them, You can create log files,
// see or hide levels based on the running ENV.
const levels = {
error: 0,
warn: 1,
info: 2,
http: 3,
debug: 4,
};
/**
* The `level` function determines the logging level based on the provided `logLevel` parameter or defaults to 'info'.
* @param {string} logLevel - The logging level to be used. If not provided, it defaults to 'info'.
* @returns {string} The logging level to be used for the logger.
* @memberof Logger
*/
const level = (logLevel = '') => logLevel || 'info';
// Define different colors for each level.
// Colors make the log message more visible,
// adding the ability to focus or ignore messages.
// Tell winston that you want to link the colors
// defined above to the severity levels.
winston.addColors({
error: 'red',
warn: 'yellow',
info: 'green',
http: 'magenta',
debug: 'white',
});
// Chose the aspect of your log customizing the log format.
const format = (meta) =>
winston.format.combine(
// winston.format.errors({ stack: true }),
// Add the message timestamp with the preferred format
winston.format.timestamp({ format: 'YYYY-MM-DD HH:mm:ss:ms' }),
// Tell Winston that the logs must be colored
winston.format.colorize({ all: true }),
// Define the format of the message showing the timestamp, the level and the message
winston.format.printf((info) => {
const splatKey = Symbol.for('splat');
const splat = info[splatKey];
const hasSplat = Array.isArray(splat) && splat.length > 0 && splat[0] !== undefined;
let splatStr = '';
if (hasSplat) {
const seen = new WeakSet();
splatStr = JSON.stringify(
splat[0],
(key, value) => {
if (typeof value === 'function') return `[Function: ${value.name || 'anonymous'}]`;
if (typeof value === 'object' && value !== null) {
if (seen.has(value)) return '[Circular]';
seen.add(value);
}
return value;
},
4,
);
}
return `${`[${meta}]`.green} ${info.timestamp} ${info.level} ${
hasSplat
? `${clearTerminalStringColor(info.message)}: ${colorize(splatStr, {
colors: {
StringKey: color.green,
StringLiteral: color.magenta,
NumberLiteral: color.red,
BooleanLiteral: color.cyan,
NullLiteral: color.white,
},
})}`
: info.message
}`;
}),
);
/**
* Logs information about the current process environment to the console.
*
* This function is used to log details about
* the execution context, such as command-line arguments,
* environment variables, and the maximum available heap space size.
*
* @param {winston.Logger} logger - A pre-configured Winston logger object.
* @memberof Logger
*/
const setUpInfo = async (logger = new winston.Logger()) => {
logger.info('argv', process.argv);
logger.info('cwd', process.cwd());
logger.info('platform', process.platform);
logger.info('env', process.env.NODE_ENV);
logger.info('--max-old-space-size', {
total_available_size: formatBytes(v8.getHeapStatistics().total_available_size),
});
};
/**
* The function `loggerFactory` creates a logger instance with specified transports for printing out
* messages.
* @param meta - The `meta` parameter in the `loggerFactory` function is used to extract the last part
* of a URL and use it to create log files in a specific directory.
* @param logLevel - Specify the logging level for the logger instance. e.g., 'error', 'warn', 'info', 'debug'.
* @param enableFileLogs - Whether to write logs to files. Defaults to the value of the `ENABLE_FILE_LOGS` environment variable.
* @returns {underpostLogger} The `loggerFactory` function returns a logger instance created using Winston logger
* library. The logger instance is configured with various transports for printing out messages to
* different destinations such as the terminal, error.log file, and all.log file. The logger instance
* also has a method `setUpInfo` attached to it for setting up additional information.
* @memberof Logger
*/
const loggerFactory = (
meta = { url: '' },
logLevel = '',
enableFileLogs = process.env.ENABLE_FILE_LOGS === 'true' || process.env.ENABLE_FILE_LOGS === true,
) => {
meta = meta.url.split('/').pop();
// Define which transports the logger must use to print out messages.
// In this example, we are using three different transports
const transports = [
// Allow the use the terminal to print the messages
new winston.transports.Console(),
// Optionally write log files when enableFileLogs is true
...(enableFileLogs
? [
// Allow to print all the error level messages inside the error.log file
new winston.transports.File({
filename: `logs/${meta}/error.log`,
level: 'error',
}),
// Allow to print all the error messages inside the all.log file
// (also includes error logs that are also printed inside error.log)
new winston.transports.File({ filename: `logs/${meta}/all.log` }),
]
: []),
];
// Create the logger instance that has to be exported
// and used to log messages.
const logger = winston.createLogger({
defaultMeta: meta,
level: level(logLevel),
levels,
format: format(meta),
transports,
// exceptionHandlers: [new winston.transports.File({ filename: 'exceptions.log' })],
// rejectionHandlers: [new winston.transports.File({ filename: 'rejections.log' })],
// exitOnError: false,
});
/**
* The returned logger is a real Winston logger instance with an extra `setUpInfo` method.
*
* @memberof Logger
* @typedef {winston.Logger & {
* setUpInfo: (logger?: winston.Logger) => Promise<void>
* }} underpostLogger
*/
logger.setUpInfo = () => setUpInfo(logger);
return logger;
};
/**
* The `loggerMiddleware` function is an Express middleware that uses the Morgan library to log HTTP requests.
* @param {Object} meta - An object containing metadata, such as the URL, to be used in the logger.
* @param {string} logLevel - The logging level to be used for the logger (e.g., 'error', 'warn', 'info', 'debug').
* @param {Function} skip - A function to determine whether to skip logging for a particular request.
* @param {boolean} enableFileLogs - Whether to write logs to files. Defaults to false.
* @returns {Function} A middleware function that can be used in an Express application to log HTTP requests.
* @memberof Logger
*/
const loggerMiddleware = (
meta = { url: '' },
logLevel = 'info',
skip = (req, res) => process.env.NODE_ENV === 'production',
enableFileLogs = process.env.ENABLE_FILE_LOGS === 'true' || process.env.ENABLE_FILE_LOGS === true,
) => {
const stream = {
// Use the http severity
write: (message) => loggerFactory(meta, logLevel, enableFileLogs).http(message),
};
morgan.token('host', function (req, res) {
return req.headers['host'];
});
return morgan(
// Define message format string
`:remote-addr :method :host:url :status :res[content-length] - :response-time ms`,
{ stream, skip },
);
};
const underpostASCII = () => `
██╗░░░██╗███╗░░██╗██████╗░███████╗██████╗░██████╗░░█████╗░░██████╗████████╗
██║░░░██║████╗░██║██╔══██╗██╔════╝██╔══██╗██╔══██╗██╔══██╗██╔════╝╚══██╔══╝
██║░░░██║██╔██╗██║██║░░██║█████╗░░██████╔╝██████╔╝██║░░██║╚█████╗░░░░██║░░░
██║░░░██║██║╚████║██║░░██║██╔══╝░░██╔══██╗██╔═══╝░██║░░██║░╚═══██╗░░░██║░░░
╚██████╔╝██║░╚███║██████╔╝███████╗██║░░██║██║░░░░░╚█████╔╝██████╔╝░░░██║░░░
░╚═════╝░╚═╝░░╚══╝╚═════╝░╚══════╝╚═╝░░╚═╝╚═╝░░░░░░╚════╝░╚═════╝░░░░╚═╝░░░
`;
const actionInitLog = () =>
console.log(
underpostASCII() +
`
https://www.nexodev.org/docs
`,
);
export { loggerFactory, loggerMiddleware, setUpInfo, underpostASCII, actionInitLog };