在日志库中通常可以看到runtime.Caller
。它被用来提供当前日志操作的源文件信息。
func Caller(skip int) (pc uintptr, file string, line int, ok bool)
Caller当前调用的goroutine栈的文件和行号信息。参数skip
由当前向上层的stack frame的号码,用0来表示当前调用,1表示调用当前函数的上层函数,如此递推。(需要注意的是,由于历史原因Caller和Callers中的skip的含义是不同的)。
返回值为对应调用的程序的计数器,文件名以及行号。如果无法获取这些信息,那么ok的值就会是false。
package rt
import (
"runtime"
"testing"
)
func TestRuntimeCaller(t *testing.T) {
pc, file, line, ok := runtime.Caller(0)
if ok {
pcName := runtime.FuncForPC(pc).Name()
t.Log("pc:", pc, "pcName:", pcName, "file:", file, "line:", line)
}
}
输出的结果为
pc: 5175028 pcName: learning-go/basic/runtime.TestRuntimeCaller file: /home/daomin/projects/learning-go/basic/runtime/caller_test.go line: 9
这是一个开销很大的函数,golang自带的log里,在使用这个函数的时候,专门做了特殊处理来优化性能。
go/src/log/log.go
func (l *Logger) Output(calldepth int, s string) error {
now := time.Now() // get this early.
var file string
var line int
l.mu.Lock()
defer l.mu.Unlock()
if l.flag&(Lshortfile|Llongfile) != 0 {
// Release lock while getting caller info - it's expensive.
l.mu.Unlock()
var ok bool
_, file, line, ok = runtime.Caller(calldepth)
if !ok {
file = "???"
line = 0
}
l.mu.Lock()
}
...
return er
}
推荐使用runtime.CallersFrames() TODO
Be First to Comment