Golang
看golang 的runtime包的时候发现可以直接使用runtime.caller看到函数调用关系:
编辑切换为居中
添加图片注释,不超过 140 字(可选)
package main
import (
"fmt"
"runtime"
)
func main() {
for i:=0; i < 4; i++ {
test(i)
}
}
func test(skip int) {
call(skip)
}
func call(skip int) {
pc,file,line,ok := runtime.Caller(skip)
pcName := runtime.FuncForPC(pc).Name() //获取函数名
fmt.Println(fmt.Sprintf("%v %s %d %t %s",pc,file,line,ok,pcName))
}
编辑切换为居中
添加图片注释,不超过 140 字(可选)
分析结果可以看到0-3分别上当前函数,当前函数的上一个caller,….
Javascript / Nodejs
这样我就思维打开了,我们用过 C 等语言的 JavaScript 开发人员经常错过使用某些类型的自省的能力,例如 记录行号 ,以及 当前方法是从哪个方法调用 的。 好吧,如果您使用的是 V8(Chrome、Node.js),有哪些方法呢?
node.js通过Error.prepareStackTrace获取上层调用函数的文件名地址和行数位置
/**
* Use CallSite to extract filename and number, for more info read: #customizing-stack-traces
* @returns {string} filename and line number separated by a colon
*/
const getFileNameAndLineNumber = () => {
const oldStackTrace = Error.prepareStackTrace;
try {
// eslint-disable-next-line handle-callback-err
Error.prepareStackTrace = (err, structuredStackTrace) => structuredStackTrace;
Error.captureStackTrace(this);
// in this example I needed to "peel" the first CallSites in order to get to the caller we're looking for
// in your code, the number of stacks depends on the levels of abstractions you're using
// in my code I'm stripping frames that come from logger module and winston (node_module)
const callSite = this.stack.find(line => line.getFileName().indexOf('/logger/') < 0 && line.getFileName().indexOf('/node_modules/') < 0);
return callSite.getFileName() + ':' + callSite.getLineNumber();
} finally {
Error.prepareStackTrace = oldStackTrace;
}
};
或者
您可以添加一些原型以提供从 V8 访问此信息的权限:
Object.defineProperty(global, '__stack', {
get: function() {
var orig = Error.prepareStackTrace;
Error.prepareStackTrace = function(_, stack) {
return stack;
};
var err = new Error;
Error.captureStackTrace(err, arguments.callee);
var stack = err.stack;
Error.prepareStackTrace = orig;
return stack;
}
});
Object.defineProperty(global, '__line', {
get: function() {
return __stack[1].getLineNumber();
}
});
Object.defineProperty(global, '__function', {
get: function() {
return __stack[1].getFunctionName();
}
});
function foo() {
console.log(__line);
console.log(__function);
}
foo()
与 arguments.callee.caller 结合使用,您可以更接近通过宏在 C 中获得的有用日志类型
Python
那么我们在python中怎么办呢? 如何在被调用的方法中获取调用者的方法名?
inspect.getframeinfo 和 inspect 中的其他相关函数可以帮助:
>>> import inspect
>>> def f1(): f2()
...
>>> def f2():
... curframe = inspect.currentframe()
... calframe = inspect.getouterframes(curframe, 2)
... print('caller name:', calframe[1][3])
...
>>> f1()
caller name: f1
注意! 这种自省旨在帮助调试和开发;不建议将其用于生产功能目的。
参考