golang运行时库runtime:Caller()方法

1. runtime.Caller()方法介绍

runtime.Caller()函数的签名如下:

func Caller(skip int) (pc uintptr, file string, line int, ok bool)

 

可以看到其有一个传入参数skip

  • skip=0Caller()会报告Caller()的调用者的信息
  • skip=1Caller()回报告Caller()的调用者的调用者的信息
  • skip=2:...

 

有四个返回值:

  • pc:调用栈标识符
  • file:带路径的完整文件名
  • line:该调用在文件中的行号
  • ok:是否可以获得信息

 

runtime.Caller()返回值中第一个返回值是一个调用栈标识,通过它我们能拿到调用栈的函数信息*runtime.Func,再进一步获取到调用者的函数名字,这里面会用到的函数和方法如下:

func FuncForPC(pc uintptr) *Func
func (*Func) Name()

 

runtime.FuncForPC()函数返回一个表示调用栈标识符pc对应的调用栈的*Func

如果该调用栈标识符没有对应的调用栈,函数会返回nil

 

Name()方法返回该调用栈所调用的函数的名字,上面说了runtime.FuncForPC()有可能会返回nil,不过Name()方法在实现的时候做了这种情况的判断,避免出现panic:

func (f *Func) Name() string {
if f == nil {
return ""
}
fn := f.raw()
if fn.isInlined() { // inlined version
fi := (*funcinl)(unsafe.Pointer(fn))
return fi.name
}
return funcname(f.funcInfo())
}

2. runtime.Caller()方法构建日志信息

下面使用一个例子来获取调用者的信息:

func getCallerInfo(skip int) (info string) {
pc, file, lineNo, ok := runtime.Caller(skip)
if !ok {
info = "runtime.Caller() failed"
}
funcName := runtime.FuncForPC(pc).Name()
fileName := path.Base(file) // Base函数返回路径的最后一个元素
return fmt.Sprintf("FuncName:%s, file:%s, line:%d", funcName, fileName, lineNo)
}
func main() {
// 打印getCallerInfo函数自身的信息
fmt.Println(getCallerInfo(0))
// 打印getCallerInfo函数的调用者的信息
fmt.Println(getCallerInfo(1))
}

 

函数执行结果为:

$ go run main.go
FuncName:main.getCallerInfo, file:main.go, line:10
FuncName:main.main, file:main.go, line:25

 

posted @   aganippe  阅读(1992)  评论(0编辑  收藏  举报
(评论功能已被禁用)
相关博文:
阅读排行:
· Manus爆火,是硬核还是营销?
· 终于写完轮子一部分:tcp代理 了,记录一下
· 别再用vector<bool>了!Google高级工程师:这可能是STL最大的设计失误
· 单元测试从入门到精通
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
点击右上角即可分享
微信分享提示