Nodejs: get filename of caller function
Failing to restore the prepareStackTrace function can cause issues. Here's an example that removes side-effects
function _getCallerFile() {
var originalFunc = Error.prepareStackTrace;
var callerfile;
try {
var err = new Error();
var currentfile;
Error.prepareStackTrace = function (err, stack) { return stack; };
currentfile = err.stack.shift().getFileName();
while (err.stack.length) {
callerfile = err.stack.shift().getFileName();
if(currentfile !== callerfile) break;
}
} catch (e) {}
Error.prepareStackTrace = originalFunc;
return callerfile;
}
This is an example how to use stacktrace to find caller file in node
function _getCallerFile() {
var filename;
var _pst = Error.prepareStackTrace
Error.prepareStackTrace = function (err, stack) { return stack; };
try {
var err = new Error();
var callerfile;
var currentfile;
currentfile = err.stack.shift().getFileName();
while (err.stack.length) {
callerfile = err.stack.shift().getFileName();
if(currentfile !== callerfile) {
filename = callerfile;
break;
}
}
} catch (err) {}
Error.prepareStackTrace = _pst;
return filename;
}
Not exactly answering the question here but some might appreciate this information.
With NodeJS & Forever(-monitor), the following contains a filename from which the process was started:
process.mainModule.filename
Haven't tried many uses™ though.
This seems to be a pretty decent explanation: https://code.google.com/p/v8/wiki/JavaScriptStackTraceApi.
Use https://github.com/sindresorhus/callsites
If you use the first answer you could mess up with other libraries trying to do the same thing. See for example: https://github.com/facebook/jest/issues/5303
In case the function you need the caller file of is not called in the file where it is implemented – as is the case in the OP's scenario – you can just write:
function _getCallerFile()
{
const prepareStackTraceOrg = Error.prepareStackTrace;
const err = new Error();
Error.prepareStackTrace = (_, stack) => stack;
const stack = err.stack;
Error.prepareStackTrace = prepareStackTraceOrg;
return stack[1].getFileName();
}
The try...catch
is unnecessary since the Error
will not be thrown if you assign it to a variable.
Furthermore, you might want to put _getCallerFile
in its own file if you want to use it in multiple projects, but then, you will get the name of the file where _getCallerFile
has been called.
In this case, just write return stack[2].getFileName();
, i. e. go one more step back in the call stack.
If you are using TypeScript, you must write const stack = err.stack as unknown as NodeJS.CallSite[];
because Error.stack
's declared type is string
, but our prepareStackTrace
function returns an array of NodeJS.CallSite
objects.
And just FYI: NodeJS.CallSite
has further interesting methods, e. g. getFunctionName
.
Update
I noticed that Error.prepareStackTrace === undefined
before assigning the lambda. If you don't trust me, just add console.log('prepareStackTraceOrg:', prepareStackTraceOrg);
to the function.
Thus, we can simplify the function:
function _getCallerFile()
{
const err = new Error();
Error.prepareStackTrace = (_, stack) => stack;
const stack = err.stack;
Error.prepareStackTrace = undefined;
return stack[1].getFileName();
}