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();
}