@underpostnet/underpost
Version:
198 lines (178 loc) • 8.38 kB
JavaScript
/**
* Module for managing logger control and configuration
* @module src/server/logger.js
* @namespace Logger
*/
;
import dotenv from 'dotenv';
import winston from 'winston';
import morgan from 'morgan';
import colorize from 'json-colorizer';
import colors from 'colors';
import v8 from 'v8';
import { clearTerminalStringColor, formatBytes } from '../client/components/core/CommonJs.js';
colors.enable();
dotenv.config();
// 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,
};
// This method set the current severity based on
// the current NODE_ENV: show all the log levels
// if the server was run in development mode; otherwise,
// if it was run in production, show only warn and error messages.
const level = () => 'info'; // (process.env.NODE_ENV || 'development' ? 'debug' : 'warn');
// 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 symbols = Object.getOwnPropertySymbols(info);
return `${`[${meta}]`.green} ${info.timestamp} ${info.level} ${
symbols[1]
? `${clearTerminalStringColor(info.message)}: ${colorize(JSON.stringify(info[symbols[1]][0], null, 4), {
colors: {
STRING_KEY: 'green',
STRING_LITERAL: 'magenta.bold',
NUMBER_LITERAL: '#FF0000',
},
})}`
: 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.
* @returns {winston.Logger} 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: '' }) => {
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(),
// 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 message inside the all.log file
// (also the error log that are also printed inside the 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(),
levels,
format: format(meta),
transports,
// exceptionHandlers: [new winston.transports.File({ filename: 'exceptions.log' })],
// rejectionHandlers: [new winston.transports.File({ filename: 'rejections.log' })],
// exitOnError: false,
});
logger.setUpInfo = async () => {
await setUpInfo(logger);
};
return logger;
};
/**
* The `loggerMiddleware` function creates a middleware for logging HTTP requests using Morgan with
* custom message format and options.
* @param meta - The `meta` parameter in the `loggerMiddleware` function is an object that contains
* information about the request URL. It has a default value of an empty object `{ url: '' }`. This
* object is used to provide additional metadata for logging purposes.
* @returns {Handler<any, any>} The `loggerMiddleware` function returns a middleware function that uses the Morgan library
* to log HTTP request information. The middleware function formats the log message using predefined
* tokens provided by Morgan and custom tokens like `:host` to include specific request details. The
* log message format includes information such as remote address, HTTP method, host, URL, status code,
* content length, and response time in milliseconds. The middleware
* @memberof Logger
*/
const loggerMiddleware = (meta = { url: '' }) => {
const stream = {
// Use the http severity
write: (message) => loggerFactory(meta).http(message),
};
const skip = (req, res) => process.env.NODE_ENV === 'production';
morgan.token('host', function (req, res) {
return req.headers['host'];
});
return morgan(
// Define message format string (this is the default one).
// The message format is made from tokens, and each token is
// defined inside the Morgan library.
// You can create your custom token to show what do you want from a request.
`:remote-addr :method :host:url :status :res[content-length] - :response-time ms`,
// Options: in this case, I overwrote the stream and the skip logic.
// See the methods above.
{ stream, skip },
);
};
const underpostASCII = () => `
██╗░░░██╗███╗░░██╗██████╗░███████╗██████╗░██████╗░░█████╗░░██████╗████████╗
██║░░░██║████╗░██║██╔══██╗██╔════╝██╔══██╗██╔══██╗██╔══██╗██╔════╝╚══██╔══╝
██║░░░██║██╔██╗██║██║░░██║█████╗░░██████╔╝██████╔╝██║░░██║╚█████╗░░░░██║░░░
██║░░░██║██║╚████║██║░░██║██╔══╝░░██╔══██╗██╔═══╝░██║░░██║░╚═══██╗░░░██║░░░
╚██████╔╝██║░╚███║██████╔╝███████╗██║░░██║██║░░░░░╚█████╔╝██████╔╝░░░██║░░░
░╚═════╝░╚═╝░░╚══╝╚═════╝░╚══════╝╚═╝░░╚═╝╚═╝░░░░░░╚════╝░╚═════╝░░░░╚═╝░░░
`;
const actionInitLog = () =>
console.log(
underpostASCII() +
`
https://www.nexodev.org/docs
`,
);
export { loggerFactory, loggerMiddleware, setUpInfo, underpostASCII, actionInitLog };