Reputation: 12220
For every logger statement with any level, I need to display the file name from where the log statement executed, below is the illustration I given below:
Example : Below is the line executed from JobWork.js
logger.info("getInCompleteJobs in job works");
Actual :
2012-11-05T06:07:19.158Z - info: getInCompleteJobs in job works
Required :
2012-11-05T06:07:19.158Z - info JobWork.js : getInCompleteJobs in job works
Without passing the fileName as a parameter from the log statement it should give the filename.
Upvotes: 26
Views: 22858
Reputation: 13542
You can use the stack trace information attached to v8's Error
object to find out what file/line your code was called from. This approach works well, but it does not perform well; so you will want to disable it in production.
So you could do something like this:
var logger_info_old = logger.info;
logger.info = function(msg) {
var fileAndLine = traceCaller(1);
return logger_info_old.call(this, fileAndLine + ":" + msg);
}
/**
* examines the call stack and returns a string indicating
* the file and line number of the n'th previous ancestor call.
* this works in chrome, and should work in nodejs as well.
*
* @param n : int (default: n=1) - the number of calls to trace up the
* stack from the current call. `n=0` gives you your current file/line.
* `n=1` gives the file/line that called you.
*/
function traceCaller(n) {
if (isNaN(n) || n<0) n=1;
n+=1;
var s = (new Error()).stack,
a = s.indexOf('\n', 5);
while (n--) {
a = s.indexOf('\n', a+1);
if (a<0) {
a = s.lastIndexOf('\n', s.length);
break;
}
}
var b = s.indexOf('\n', a+1);
if( b<0 ) b = s.length;
a = Math.max(
s.lastIndexOf(' ', b),
s.lastIndexOf('/', b));
b = s.lastIndexOf(':', b);
s = s.substring(a+1, b);
return s;
}
Upvotes: 19
Reputation: 834
solutions with "consola" package (ES module only):
import { createLogger } from '@nitra/consola'
consola = createLogger(import.meta.url)
consola.debug('TEST')
output:
[my-file.js] › TEST
Upvotes: 1
Reputation: 4463
Looks like you're using Winston here - I typically pass module
into my logger module and then set Winston's label
property to a parsed version of module.filename
. Something like:
logger.js:
const path = require('path');
// Return the last folder name in the path and the calling
// module's filename.
const getLabel = function(callingModule) {
const parts = callingModule.filename.split(path.sep);
return path.join(parts[parts.length - 2], parts.pop());
};
module.exports = function (callingModule) {
return new winston.Logger({
transports: [new winston.transports.Console({
label: getLabel(callingModule)
})]
});
};
Usage (assume module is controllers/users.js
):
const logger = require('./logger')(module);
logger.info('foo');
Result:
2014-11-25T15:31:12.186Z - info: [controllers/users.js] foo
Upvotes: 47
Reputation: 890
Use this code and it will give you the log with the filename and line number. Paste this code in a new file winston.js
and this requires this file to use it.
var winston = require('winston')
var path = require('path')
var PROJECT_ROOT = path.join(__dirname, '..')
var appRoot = require('app-root-path');
const options = {
file: {
level: 'info',
filename: `${appRoot}/logs/app.log`,
handleExceptions: true,
json: true,
maxsize: 5242880, // 5MB
maxFiles: 5,
colorize: false,
timestamp: true
},
console: {
level: 'debug',
handleExceptions: true,
json: true,
colorize: true,
timestamp: true
}
};
var logger = new winston.Logger({
transports: [
new winston.transports.File(options.file),
new winston.transports.Console(options.console)
],
exitOnError: false // do not exit on handled exceptions
});
logger.stream = {
write: function (message) {
logger.info(message)
}
}
// A custom logger interface that wraps winston, making it easy to instrument
// code and still possible to replace winston in the future.
module.exports.debug = module.exports.log = function () {
logger.debug.apply(logger, formatLogArguments(arguments))
}
module.exports.info = function () {
logger.info.apply(logger, formatLogArguments(arguments))
}
module.exports.warn = function () {
logger.warn.apply(logger, formatLogArguments(arguments))
}
module.exports.error = function () {
logger.error.apply(logger, formatLogArguments(arguments))
}
module.exports.stream = logger.stream
/**
* Attempts to add file and line number info to the given log arguments.
*/
function formatLogArguments (args) {
args = Array.prototype.slice.call(args)
var stackInfo = getStackInfo(1)
if (stackInfo) {
// get file path relative to project root
var calleeStr = '(' + stackInfo.relativePath + ':' + stackInfo.line + ')'
if (typeof (args[0]) === 'string') {
args[0] = calleeStr + ' ' + args[0]
} else {
args.unshift(calleeStr)
}
}
return args
}
/**
* Parses and returns info about the call stack at the given index.
*/
function getStackInfo (stackIndex) {
// get call stack, and analyze it
// get all file, method, and line numbers
var stacklist = (new Error()).stack.split('\n').slice(3)
// stack trace format:
// http://code.google.com/p/v8/wiki/JavaScriptStackTraceApi
// do not remove the regex expresses to outside of this method (due to a BUG in node.js)
var stackReg = /at\s+(.*)\s+\((.*):(\d*):(\d*)\)/gi
var stackReg2 = /at\s+()(.*):(\d*):(\d*)/gi
var s = stacklist[stackIndex] || stacklist[0]
var sp = stackReg.exec(s) || stackReg2.exec(s)
if (sp && sp.length === 5) {
return {
method: sp[1],
relativePath: path.relative(PROJECT_ROOT, sp[2]),
line: sp[3],
pos: sp[4],
file: path.basename(sp[2]),
stack: stacklist.join('\n')
}
}
}
Upvotes: 1
Reputation: 5292
Assuming each file is a separate node process, you could use something like process.argv[1].match(/[\w-]+\.js/gi)[0]
If you are looking for something that will work in modules this might work:
process.mainModule.filename.match(/[\w-]+\.js/gi)[0]
Upvotes: 4