【Golang】Go之runtime.Caller/Callers/CallersFrames/FuncForPC使用
作者:互联网
skip如果是0,返回当前调用Caller函数的函数名、文件、程序指针PC,1是上一层函数,以此类推:
func Caller(skip int) (pc uintptr, file string, line int, ok bool)
例子
package main
import (
"log"
"runtime"
)
func main() {
test()
}
func test() {
test2()
}
func test2() {
// 上2层函数信息
pc, file, line, ok := runtime.Caller(2)
// 是否获取成功
log.Println(ok)
// 函数指针
log.Println(pc)
// 所属文件
log.Println(file)
// 所属行
log.Println(line)
// 获取函数信息
f := runtime.FuncForPC(pc)
// 函数名
log.Println(f.Name())
// 当前函数信息
pc, file, line, ok = runtime.Caller(0)
log.Println(pc)
log.Println(file)
log.Println(line)
log.Println(ok)
f = runtime.FuncForPC(pc)
log.Println(f.Name())
// 上一层函数信息
pc, file, line, ok = runtime.Caller(1)
log.Println(pc)
log.Println(file)
log.Println(line)
log.Println(ok)
f = runtime.FuncForPC(pc)
log.Println(f.Name())
}
输出结果为:
2020/04/04 03:54:48 true
2020/04/04 03:54:48 17410619
2020/04/04 03:54:48 /Users/lurongming/main.go
2020/04/04 03:54:48 9
2020/04/04 03:54:48 main.main
2020/04/04 03:54:48 17411178
2020/04/04 03:54:48 /Users/lurongming/main.go
2020/04/04 03:54:48 34
2020/04/04 03:54:48 true
2020/04/04 03:54:48 main.test2
2020/04/04 03:54:48 17410624
2020/04/04 03:54:48 /Users/lurongming/main.go
2020/04/04 03:54:48 13
2020/04/04 03:54:48 true
2020/04/04 03:54:48 main.test
直接从函数指针获取函数名称所属文件:
package main
import (
"log"
"reflect"
"runtime"
)
type Demo struct {
}
func (this *Demo) Hello() {
}
func main() {
demo := new(Demo)
pc := reflect.ValueOf(demo.Hello).Pointer()
f := runtime.FuncForPC(pc)
log.Println(f.Name())
log.Println(f.FileLine(pc))
}
输出结果为:
2020/04/04 03:55:47 main.(*Demo).Hello-fm
2020/04/04 03:55:47 /Users/lurongming/main.go 12
func Callers(skip int, pc []uintptr) int
Callers用来返回调用站的程序计数器, 放到一个uintptr中。
0 代表 Callers 本身,这和上面的Caller的参数的意义不一样,历史原因造成的。 1 才对应这上面的 0。
package main
import (
"fmt"
"runtime"
)
func printMyName() string {
pc, _, _, _ := runtime.Caller(1)
return runtime.FuncForPC(pc).Name()
}
func printCallerName() string {
pc, _, _, _ := runtime.Caller(2)
return runtime.FuncForPC(pc).Name()
}
func Foo() {
fmt.Printf("我是 %s, %s 在调用我!\n", printMyName(), printCallerName())
Bar()
}
func Bar() {
fmt.Printf("我是 %s, %s 又在调用我!\n", printMyName(), printCallerName())
trace()
}
func trace() {
pc := make([]uintptr, 10) // at least 1 entry needed
n := runtime.Callers(0, pc)
for i := 0; i < n; i++ {
f := runtime.FuncForPC(pc[i])
file, line := f.FileLine(pc[i])
fmt.Printf("%s:%d %s\n", file, line, f.Name())
}
}
func main() {
Foo()
}
输出结果为:
我是 main.Foo, main.main 在调用我!
我是 main.Bar, main.Foo 又在调用我!
/usr/local/go/src/runtime/extern.go:211 runtime.Callers
/Users/lurongming/main.go:27 main.trace
/Users/lurongming/main.go:24 main.Bar
/Users/lurongming/main.go:20 main.Foo
/Users/lurongming/main.go:37 main.main
/usr/local/go/src/runtime/proc.go:212 runtime.main
/usr/local/go/src/runtime/asm_amd64.s:1358 runtime.goexit
CallersFrames(callers []uintptr) *Frames
上面的Callers只是或者栈的程序计数器,如果想获得整个栈的信息,可以使用CallersFrames函数,省去遍历调用FuncForPC。
上面的trace函数可以更改为下面的方式,输出结果是一样的:
func trace() {
pc := make([]uintptr, 10) // at least 1 entry needed
n := runtime.Callers(0, pc)
frames := runtime.CallersFrames(pc[:n])
for {
frame, more := frames.Next()
fmt.Printf("%s:%d %s\n", frame.File, frame.Line, frame.Function)
if !more {
break
}
}
}
获取程序堆栈
在程序panic的时候,一般会自动把堆栈打出来,如果你想在程序中获取堆栈信息,可以通过debug.PrintStack()打印出来。比如你在程序中遇到一个Error,但是不期望程序panic,只是想把堆栈信息打印出来以便跟踪调试,你可以使用debug.PrintStack()。
抑或,你自己读取堆栈信息,自己处理和打印:
func DumpStacks() {
buf := make([]byte, 16384)
buf = buf[:runtime.Stack(buf, true)]
fmt.Printf("=== BEGIN goroutine stack dump ===\n%s\n=== END goroutine stack dump ===", buf)
}
参考 调试利器:dump goroutine 的 stacktrace。
利用堆栈信息还可以获取goroutine的id, 参考: 再谈谈获取 goroutine id 的方法。
func GoID() int {
var buf [64]byte
n := runtime.Stack(buf[:], false)
idField := strings.Fields(strings.TrimPrefix(string(buf[:n]), "goroutine "))[0]
id, err := strconv.Atoi(idField)
if err != nil {
panic(fmt.Sprintf("cannot get goroutine id: %v", err))
}
return id
}
参考
golang日志组件使用runtime.Caller性能问题分析
标签:03,runtime,log,04,CallersFrames,Caller,Golang,pc,main 来源: https://blog.csdn.net/LU_ZHAO/article/details/105305141