I would like my node.js project to generate log files that are a bit similar to log4j format in that I would like each log line to commence with the file name and the js function name that the log request originated from.
e.g: If my js file is called aNiceFile.js and my js function is called doImportantStuff() and I invoke a log statement with something like:
log.info('About to start on the important stuff')
I would like my log file to look a bit like:
2018-03-14 06:33:26:619 INFO aNiceFile.js doImportantStuff() About to start on the important stuff.
I want to do a lot of logging, so I don't mind one off, upfront effort to set this up, but I am after minimal additional effort per file / function that I add to my code.
I am using Winston today, I am happy to switch to something else if that is necessary, with Winston this does not seem to be possible without some effort on my part: https://github.com/winstonjs/winston/issues/200
For completeness, I don't need the line numbers, but they would be nice to have too.
My current clumsy work around is to:
1) Start each file with this to get the current file name:
const sn = path.basename(__filename) // this script file name, used for logging purposes
I am ok with this step, it is not onerous, a single identical line pasted at the top of each file, I can accept this.
2) Start each function with this to get the current function name:
const fn = '<I copy/paste the function name into this string constant :( >'
I don't like this step, I have to copy the function name into the string constant, and it could get out of sync later if I rename the function.
If I could turn this into the version below that would be better, not sure how to do that:
const fn = getCurrentFunctionName()
3) I do each log statement like this:
log.info(`${sn}:${fn} Starting important stuff`)
I don't like this step because all my log statements start with this (${sn}:${fn}) noise.
As you can see this is primitive, but it does work. What should I really be doing here?
I am interested in performance so solutions that require the generation of an Error object to harvest a stack trace from are probably not acceptable.
Edit adding all stuff.
This is a basic example of filename, lines, columns and caller function. Maybe you need to adapt somethings. But this is the idea.
let log = {
info: function info(message) {
const callerInfo = getFileName(info.caller.name);
console.log(
new Date() +
' ' +
arguments.callee.name.toUpperCase() +
' ' +
callerInfo.filename +
':' +
callerInfo.line +
':' +
callerInfo.column +
' ' +
info.caller.name +
'() ' +
message
);
},
};
function getFileName(caller) {
const STACK_FUNC_NAME = new RegExp(/at\s+((\S+)\s)?\((\S+):(\d+):(\d+)\)/);
let err = new Error();
Error.captureStackTrace(err);
let stacks = err.stack.split('\n').slice(1);
let callerInfo = null;
for (let i = 0; i < stacks.length; i++) {
callerInfo = STACK_FUNC_NAME.exec(stacks[i]);
if (callerInfo[2] === caller) {
return {
filename: callerInfo[3],
line: callerInfo[4],
column: callerInfo[5],
};
}
}
return null;
}
function iWantToLog() {
log.info('Testing my log');
}
iWantToLog();
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With