How can one get the file path of the caller function in node.js?
You need to fiddle with the inner workings of v8
. See: the wiki entry about the JavaScript Stack Trace API.
I've based a little test on some code in a proposed commit and it seems to work. You end up with an absolute path.
// omfg.js
module.exports = omfg
function omfg() {
var caller = getCaller()
console.log(caller.filename)
}
// private
function getCaller() {
var stack = getStack()
// Remove superfluous function calls on stack
stack.shift() // getCaller --> getStack
stack.shift() // omfg --> getCaller
// Return caller's caller
return stack[1].receiver
}
function getStack() {
// Save original Error.prepareStackTrace
var origPrepareStackTrace = Error.prepareStackTrace
// Override with function that just returns `stack`
Error.prepareStackTrace = function (_, stack) {
return stack
}
// Create a new `Error`, which automatically gets `stack`
var err = new Error()
// Evaluate `err.stack`, which calls our new `Error.prepareStackTrace`
var stack = err.stack
// Restore original `Error.prepareStackTrace`
Error.prepareStackTrace = origPrepareStackTrace
// Remove superfluous function call on stack
stack.shift() // getStack --> Error
return stack
}
And a test that includes omfg
module:
#!/usr/bin/env node
// test.js
var omfg = require("./omfg")
omfg()
And you will get on the console the absolute path of test.js
.
EXPLANATION
This is not so much a "node.js" issue as it is a "v8" issue.
See: Stack Trace Collection for Custom Exceptions
Error.captureStackTrace(error, constructorOpt)
adds to the error
parameter a stack
property, which evaluates by default to a String
(by way of FormatStackTrace
). If Error.prepareStackTrace(error, structuredStackTrace)
is a Function
, then it is called instead of FormatStackTrace
.
So, we can override Error.prepareStackTrace
with our own function that will return whatever we want--in this case, just the structuredStackTrace
parameter.
Then, structuredStackTrace[1].receiver
is an object representing the caller.
Or instead of fiddling with inner workings of the V8 engine, you use module.parent.filename
to get absolute path to the module that required your module. As demonstrated here: https://gist.github.com/capaj/a9ba9d313b79f1dcd9a2
Just keep in mind that modules are cached, so if any other file requires it and calls it, it will always be the path to the first importer.