环境:
go version go1.18.2
1、runtime.Caller
函数func runtime.Caller(skip int) (pc uintptr, file string, line int, ok bool)
作用
获取函数Caller
的调用信息
参数
skip
:=0
时,返回调用Caller
的函数A
的pc(program counter)、所在文件名以及Caller
在函数A
中的行数;=1
时, 返回调用函数A
的函数B
的pc、所在文件名以及函数A
在函数B
中的行数;以此类推pc
: 程序计数器,指向下一条将要取指的指令地址file
: pc对应的函数所在文件line
: 被调用方在pc对应的函数中的行数
e.g.
项目结构如下:
tool.tool.go
package tool
import (
"bytes"
"fmt"
"runtime"
)
func CallerTest() {
for i := 0; i <= 4; i++ {
pc, file, line, ok := runtime.Caller(i)
if ok {
fmt.Printf("当i:=%d时:\n调用者的pc:%v\n调用者的函数名:%s\n"+
"调用者所在file:%s\n被调用者在调用者中的line:%d\n", i, pc, runtime.FuncForPC(pc).Name(), file, line)
fmt.Println(string(bytes.Repeat([]byte("*"), 10)))
}
}
}
main.go
package main
import "caller/tool"
func main() {
tool.CallerTest()
}
运行结果如下:
PS E:\goland-workspace\GolangLearning\Common\caller> go run .\main.go
当i:=0时:
调用者的pc:15191590
调用者的函数名:caller/tool.CallerTest
调用者所在file:E:/goland-workspace/GolangLearning/Common/caller/tool/tool.go
被调用者在调用者中的line:11
**********
当i:=1时:
调用者的pc:15192214
调用者的函数名:main.main
调用者所在file:E:/goland-workspace/GolangLearning/Common/caller/main.go
被调用者在调用者中的line:6
**********
当i:=2时:
调用者的pc:14832765
调用者的函数名:runtime.main
调用者所在file:D:/golang/install/src/runtime/proc.go
被调用者在调用者中的line:250
**********
当i:=3时:
调用者的pc:14990688
调用者的函数名:runtime.goexit
调用者所在file:D:/golang/install/src/runtime/asm_amd64.s
被调用者在调用者中的line:1571
**********
2. runtime.Callers
函数func runtime.Callers(skip int, pc []uintptr) int
作用
类似函数Caller
,可以在入参pc
中填充Callers
所有的调用信息(前提是pc切片空间足够)
参数
skip
:区别于Caller
,skip=0时,代表Callers
函数本身,skip=1时,代表调用Callers
的函数pc
:存储Callers
所有的调用方pc
e.g.
项目结构如下:
tool.tool.go
package tool
import (
"fmt"
"runtime"
)
func CallersTest() {
pc := make([]uintptr, 32)
n := runtime.Callers(0, pc)
cf := runtime.CallersFrames(pc[:n])
for {
frame, more := cf.Next()
if !more {
break
} else {
fmt.Println(frame)
}
}
}
main.go
package main
import "callers/tool"
func main() {
tool.CallersTest()
}
运行结果如下:
PS E:\goland-workspace\GolangLearning\Common\callers> go run .\main.go
{11711796 <nil> runtime.Callers D:/golang/install/src/runtime/extern.go 235 11711712 {0xbc2550 0xbc8a00}}
{11711778 0xbc2550 callers/tool.CallersTest E:/goland-workspace/GolangLearning/Common/callers/tool/tool.go 10 11711712 {0xbc2550 0xbc8a00}}
{11712246 0xbc2598 main.main E:/goland-workspace/GolangLearning/Common/callers/main.go 6 11712224 {0xbc2598 0xbc8a00}}
{11359357 0xbb2370 runtime.main D:/golang/install/src/runtime/proc.go 250 11358848 {0xbb2370 0xbc8a00}}
注:
- 需要借助函数
runtime.CallersFrames
来获取Callers
的调用关系,不能直接根据runtime.Callers(0, pc)
中pc的值来获取,否则获取的调用顺序可能不正确 - 可以看到当
skip=0
时,pc[0]指向Callers
函数本身,pc[1]指向调用Callers
的函数callers/tool.CallersTest
,以此类推