@noxfly/noxus
Version:
Simulate lightweight HTTP-like requests between renderer and main process in Electron applications with MessagePort, with structured and modular design.
252 lines (215 loc) • 9.06 kB
text/typescript
/**
* @copyright 2025 NoxFly
* @license MIT
* @author NoxFly
*/
/**
* Logger is a utility class for logging messages to the console.
*/
export type LogLevel = 'log' | 'info' | 'warn' | 'error' | 'debug' | 'comment';
/**
* Returns a formatted timestamp for logging.
*/
function getPrettyTimestamp(): string {
const now = new Date();
return `${now.getDate().toString().padStart(2, '0')}/${(now.getMonth() + 1).toString().padStart(2, '0')}/${now.getFullYear()}`
+ ` ${now.getHours().toString().padStart(2, '0')}:${now.getMinutes().toString().padStart(2, '0')}:${now.getSeconds().toString().padStart(2, '0')}`;
}
/**
* Generates a log prefix for the console output.
* @param callee - The name of the function or class that is logging the message.
* @param messageType - The type of message being logged (e.g., 'log', 'info', 'warn', 'error', 'debug').
* @param color - The color to use for the log message.
* @returns A formatted string that includes the timestamp, process ID, message type, and callee name.
*/
function getLogPrefix(callee: string, messageType: string, color: string): string {
const timestamp = getPrettyTimestamp();
const spaces = ' '.repeat(10 - messageType.length);
return `${color}[APP] ${process.pid} - ${Logger.colors.initial}`
+ `${timestamp}${spaces}`
+ `${color}${messageType.toUpperCase()}${Logger.colors.initial} `
+ `${Logger.colors.yellow}[${callee}]${Logger.colors.initial}`;
}
/**
* Formats an object into a string representation for logging.
* It converts the object to JSON and adds indentation for readability.
* @param prefix - The prefix to use for the formatted object.
* @param arg - The object to format.
* @returns A formatted string representation of the object, with each line prefixed by the specified prefix.
*/
function formatObject(prefix: string, arg: object): string {
const json = JSON.stringify(arg, null, 2);
const prefixedJson = json
.split('\n')
.map((line, idx) => idx === 0 ? `${Logger.colors.darkGrey}${line}` : `${prefix} ${Logger.colors.grey}${line}`)
.join('\n') + Logger.colors.initial;
return prefixedJson;
}
/**
* Formats the arguments for logging.
* It colors strings and formats objects with indentation.
* This function is used to prepare the arguments for console output.
* @param prefix - The prefix to use for the formatted arguments.
* @param args - The arguments to format.
* @param color - The color to use for the formatted arguments.
* @returns An array of formatted arguments, where strings are colored and objects are formatted with indentation.
*/
function formattedArgs(prefix: string, args: any[], color: string): any[] {
return args.map(arg => {
if(typeof arg === 'string') {
return `${color}${arg}${Logger.colors.initial}`;
}
else if(typeof arg === 'object') {
return formatObject(prefix, arg);
}
return arg;
});
}
/**
* Gets the name of the caller function or class from the stack trace.
* This function is used to determine the context of the log message.
* @returns The name of the caller function or class.
*/
function getCallee(): string {
const stack = new Error().stack?.split('\n') ?? [];
const caller = stack[3]
?.trim()
.match(/at (.+?)(?:\..+)? .+$/)
?.[1]
?.replace('Object', '')
.replace(/^_/, '')
|| "App";
return caller;
}
/**
* Checks if the current log level allows logging the specified level.
* This function compares the current log level with the specified level to determine if logging should occur.
* @param level - The log level to check.
* @returns A boolean indicating whether the log level is enabled.
*/
function canLog(level: LogLevel): boolean {
return logLevelRank[level] >= logLevelRank[logLevel];
}
let logLevel: LogLevel = 'debug';
const logLevelRank: Record<LogLevel, number> = {
debug: 0,
comment: 1,
log: 2,
info: 3,
warn: 4,
error: 5,
};
export namespace Logger {
/**
* Sets the log level for the logger.
* This function allows you to change the log level dynamically at runtime.
* This won't affect the startup logs.
* @param level Sets the log level for the logger.
*/
export function setLogLevel(level: LogLevel): void {
logLevel = level;
}
/**
* Logs a message to the console with log level LOG.
* This function formats the message with a timestamp, process ID, and the name of the caller function or class.
* It uses different colors for different log levels to enhance readability.
* @param args The arguments to log.
*/
export function log(...args: any[]): void {
if(!canLog('log'))
return;
const callee = getCallee();
const prefix = getLogPrefix(callee, "log", colors.green);
console.log(prefix, ...formattedArgs(prefix, args, colors.green));
}
/**
* Logs a message to the console with log level INFO.
* This function formats the message with a timestamp, process ID, and the name of the caller function or class.
* It uses different colors for different log levels to enhance readability.
* @param args The arguments to log.
*/
export function info(...args: any[]): void {
if(!canLog('info'))
return;
const callee = getCallee();
const prefix = getLogPrefix(callee, "info", colors.blue);
console.info(prefix, ...formattedArgs(prefix, args, colors.blue));
}
/**
* Logs a message to the console with log level WARN.
* This function formats the message with a timestamp, process ID, and the name of the caller function or class.
* It uses different colors for different log levels to enhance readability.
* @param args The arguments to log.
*/
export function warn(...args: any[]): void {
if(!canLog('warn'))
return;
const callee = getCallee();
const prefix = getLogPrefix(callee, "warn", colors.brown);
console.warn(prefix, ...formattedArgs(prefix, args, colors.brown));
}
/**
* Logs a message to the console with log level ERROR.
* This function formats the message with a timestamp, process ID, and the name of the caller function or class.
* It uses different colors for different log levels to enhance readability.
* @param args The arguments to log.
*/
export function error(...args: any[]): void {
if(!canLog('error'))
return;
const callee = getCallee();
const prefix = getLogPrefix(callee, "error", colors.red);
console.error(prefix, ...formattedArgs(prefix, args, colors.red));
}
export function errorStack(...args: any[]): void {
if(!canLog('error'))
return;
const callee = getCallee();
const prefix = getLogPrefix(callee, "error", colors.grey);
console.error(prefix, ...formattedArgs(prefix, args, colors.grey));
}
/**
* Logs a message to the console with log level DEBUG.
* This function formats the message with a timestamp, process ID, and the name of the caller function or class.
* It uses different colors for different log levels to enhance readability.
* @param args The arguments to log.
*/
export function debug(...args: any[]): void {
if(!canLog('debug'))
return;
const callee = getCallee();
const prefix = getLogPrefix(callee, "debug", colors.purple);
console.debug(prefix, ...formattedArgs(prefix, args, colors.purple));
}
/**
* Logs a message to the console with log level COMMENT.
* This function formats the message with a timestamp, process ID, and the name of the caller function or class.
* It uses different colors for different log levels to enhance readability.
* @param args The arguments to log.
*/
export function comment(...args: any[]): void {
if(!canLog('comment'))
return;
const callee = getCallee();
const prefix = getLogPrefix(callee, "comment", colors.grey);
console.debug(prefix, ...formattedArgs(prefix, args, colors.grey));
}
export const colors = {
black: '\x1b[0;30m',
grey: '\x1b[0;37m',
red: '\x1b[0;31m',
green: '\x1b[0;32m',
brown: '\x1b[0;33m',
blue: '\x1b[0;34m',
purple: '\x1b[0;35m',
darkGrey: '\x1b[1;30m',
lightRed: '\x1b[1;31m',
lightGreen: '\x1b[1;32m',
yellow: '\x1b[1;33m',
lightBlue: '\x1b[1;34m',
magenta: '\x1b[1;35m',
cyan: '\x1b[1;36m',
white: '\x1b[1;37m',
initial: '\x1b[0m'
};
}