96 lines
2.9 KiB
JavaScript
Executable File
96 lines
2.9 KiB
JavaScript
Executable File
const path = require('path');
|
|
const chalk = require('chalk');
|
|
|
|
const levels = {
|
|
error: 0,
|
|
warn: 1,
|
|
info: 2,
|
|
debug: 3,
|
|
};
|
|
|
|
// Color mapping
|
|
const colors = {
|
|
error: chalk.red,
|
|
warn: chalk.yellow,
|
|
info: chalk.blue,
|
|
debug: chalk.gray,
|
|
};
|
|
|
|
// Get the set of active modules from the ACTIVELOG environment variable
|
|
const activeLogModules = new Set((process.env.ACTIVELOG || '').split(',').map(m => m.trim()).filter(Boolean));
|
|
// The filter is active only if the environment variable is explicitly defined.
|
|
const isModuleFilteringActive = process.env.ACTIVELOG !== undefined;
|
|
|
|
const getCallingInfo = () => {
|
|
const originalFunc = Error.prepareStackTrace;
|
|
let callerfile;
|
|
let callerlinenumber;
|
|
try {
|
|
const err = new Error();
|
|
Error.prepareStackTrace = (err, stack) => stack;
|
|
// The first call site is this file, the second is the logger function, the third is the actual caller.
|
|
const currentfile = err.stack[0].getFileName();
|
|
let i = 1;
|
|
while (i < err.stack.length) {
|
|
callerfile = err.stack[i].getFileName();
|
|
callerlinenumber = err.stack[i].getLineNumber();
|
|
if (callerfile !== currentfile) {
|
|
break;
|
|
}
|
|
i++;
|
|
}
|
|
} catch (e) {
|
|
// Fallback
|
|
}
|
|
Error.prepareStackTrace = originalFunc;
|
|
|
|
return {
|
|
fileName: callerfile ? path.relative(process.cwd(), callerfile) : 'unknown',
|
|
lineNumber: callerlinenumber || '?'
|
|
};
|
|
};
|
|
|
|
|
|
const logLevel = process.env.LOG_LEVEL || 'info';
|
|
const currentLevel = levels[logLevel.toLowerCase()] ?? levels.info;
|
|
|
|
const log = (level, message, ...args) => {
|
|
// 1. Check log level first
|
|
if (levels[level] > currentLevel) {
|
|
return;
|
|
}
|
|
|
|
const { fileName, lineNumber } = getCallingInfo();
|
|
const moduleFilterName = path.basename(fileName, '.js');
|
|
|
|
// 2. For 'info' and 'debug', check if the module is in the ACTIVELOG allow-list.
|
|
// 'error' and 'warn' messages will always be displayed regardless of the filter.
|
|
if (level === 'info' || level === 'debug') {
|
|
if (isModuleFilteringActive && !activeLogModules.has(moduleFilterName)) {
|
|
return;
|
|
}
|
|
}
|
|
|
|
// 3. Format and print the log message
|
|
const timestamp = new Date().toISOString();
|
|
const colorizer = colors[level] || (text => text); // Fallback to no color
|
|
const formattedMessage = colorizer(`${timestamp} [${level.toUpperCase()}] [${fileName}:${lineNumber}] - ${message}`);
|
|
|
|
if (level === 'error') {
|
|
console.error(formattedMessage, ...args.map(arg => colorizer(arg)));
|
|
} else if (level === 'warn') {
|
|
console.warn(formattedMessage, ...args.map(arg => colorizer(arg)));
|
|
} else {
|
|
console.log(formattedMessage, ...args);
|
|
}
|
|
};
|
|
|
|
const logger = {
|
|
error: (message, ...args) => log('error', message, ...args),
|
|
warn: (message, ...args) => log('warn', message, ...args),
|
|
info: (message, ...args) => log('info', message, ...args),
|
|
debug: (message, ...args) => log('debug', message, ...args),
|
|
};
|
|
|
|
module.exports = logger;
|