/ log.go:67 上溯栈帧数skip = 1 logger.Println(v) } func setPrefix(level Level) { _, file, line, ok := runtime.Caller...包里的log.go文件封装了Info()、Debug()、Warn()、....函数,其他地方调用的都是这种封装好的函数,所以如果我们打印日志的时候,想要获取使用了logging.Info()的位置,runtime.Caller
背景 runtime.Caller能够拿到当前执行的文件名和行号,这个方法几乎所有的日志组件里都有使用。...(1) return line } 在同一需求场景下,FILE和LINE分别调用了一次能耗较高的runtime.Caller,这个其实一次就行。...另外一方面,在调用性能比较差的runtime.Caller之前,把锁释放,执行完毕后再把锁加上,继续处理自己后续的业务。这个可以避免锁的时间过长,影响其他业务。...而这里提升性能的一种解决方案是使用资源池entryPool sync.Pool,当然这里的资源池不是说runtime.Caller之类的可以复用,而是空的entry实例。...如果logger实例使用了mutex锁,那么在调用runtime.Caller或者runtimr.Frame之前先将锁释放,调用完毕后再锁上。
本文主要介绍 runtime.Caller 的使用,上面说了那么多只是为了铺垫一下,学会它,在哪些地方可以应用上。...runtime.Caller runtime.Caller 的函数签名如下: func Caller(skip int) (pc uintptr, file string, line int, ok bool...是不是有点晕,这里举个例子 func CallerA() { //获取的是 CallerA 这个函数的调用栈 pc, file, lineNo, ok := runtime.Caller(0)...//获取的是 CallerA函数的调用者的调用栈 pc1, file1, lineNo1, ok1 := runtime.Caller(1) } 函数的返回值为调用栈标识符、带路径的完整文件名...总结 今天介绍了通过 runtime.Caller 回溯调用栈获取调用者的信息的方法,虽然强大,不过频繁获取这个信息也是会对程序性能有影响。
return path } var lastFile string for i := 1; i < 10000; i++ { if pc, file, _, ok := runtime.Caller...package main,找到此文件的路径 如果此文件存在, 然后返回该文件的路径 至于获取当前源码所在文件路径,行号这些很多语言都提供这个功能, 比如PHP和C语言中的__FILE__, 而Go中通过runtime.Caller...我们来看一下runtime.Caller func Caller(skip int) (pc uintptr, file string, line int, ok bool) { rpc :=...1 才对应这runtime.Caller的 0。
Go语言 runtime 包的 runtime.Caller / runtime.Callers / runtime.FuncForPC 等几个函数提供了获取函数调用者信息的方法....其输入参数 skip 为要跳过的栈帧数, 若为 0 则表示 runtime.Caller 的调用者....这个例子比前一个例子多输出了一个栈帧, 就是因为多了一个runtime.Callers栈帧的信息(前一个例子是没有runtime.Caller信息的(注意:没有s后缀))....那么 runtime.Callers 和 runtime.Caller 有哪些关联和差异?...不过在实践中, 一般会用 runtime.Caller 获取文件名和行号信息, runtime.Func.FileLine 很少用到(如何独立获取pc参数?).
\n", printMyName()) 15} 16func printMyName() string { 17 pc, _, _, _ := runtime.Caller(1) 18 return...\n", printMyName(), printCallerName()) 10} 11func printMyName() string { 12 pc, _, _, _ := runtime.Caller...13 return runtime.FuncForPC(pc).Name() 14} 15func printCallerName() string { 16 pc, _, _, _ := runtime.Caller...(2) 17 return runtime.FuncForPC(pc).Name() 18} 相关函数介绍 你可以通过runtime.Caller、runtime.Callers、runtime.FuncForPC...0 代表当前函数,也是调用runtime.Caller的函数。1 代表上一层调用者,以此类推。
l.mu.Unlock() var ok bool _, file, line, ok = runtime.Caller(calldepth) if !...err := l.out.Write(l.buf) return err } 通过阅读 Output() 函数的源码,可以发现使用互斥锁来保证多个 goroutine 写日志的安全,并且在调用 runtime.Caller...函数 Output() 的源码也比较简单,其中最值得注意的是 runtime.Caller() 函数,源码如下: func Caller(skip int) (pc uintptr, file string...= 0 } 通过阅读 runtime.Caller() 函数的源码,可以发现它接收一个 int 类型的参数 skip,该参数表示跳过栈帧数,log 包中的输出功能的函数,使用的默认值都是 2,原因是什么...举例说明,比如在 main 函数中调用 log.Print,方法调用栈为 main->log.Print->*Logger.Output->runtime.Caller,所以此时参数 skip 的值为
l.mu.Unlock() var ok bool _, file, line, ok = runtime.Caller(calldepth) if !...l.buf, '\n') } _, err := l.out.Write(l.buf) return err } 如果设置了Lshortfile或Llongfile,Ouput方法中会调用runtime.Caller...runtime.Caller的参数calldepth表示获取调用栈向上多少层的信息,当前层为 0。...calldepth传入 0 表示Output方法内调用runtime.Caller的那一行信息,传入 1 表示log.Printf内调用std.Output那一行的信息, 传入 2 表示程序中调用log.Printf...这里有两个优化技巧: 由于runtime.Caller调用比较耗时,先释放锁,避免等待时间过长; 为了避免频繁的内存分配,logger中保存了一个类型为[]byte的buf,可重复使用。
在网上搜索怎么获取 Go 项目的根目录,一般有三种,分别依赖 Go 的以下三个底层函数实现: os.Getwd() os.Args[0] runtime.Caller 虽然这三种方式都能获取到Go项目的根目录...runtime.Caller 想获取到程序的根目录,如果能拿到当前正在执行的代码的文件路径,我们也就能推断出程序的根目录了。怎么能拿到当前正在执行的代码的文件路径呢?...当时看了源码后我们发现用的是 runtime.Caller() func Caller(skip int) (pc uintptr, file string, line int, ok bool) 所以我们在...config.go中,能这样获取当前文件的路径: // 获取当前文件的路径 _, filename, _, _ := runtime.Caller(0) runtime.Caller 这里不在详细介绍
= 0 { //因为runtime.Caller代价比较大,先不加锁 l.mu.Unlock() var ok bool _, file, line, ok = runtime.Caller...这里稍微简单介绍下runtime.Caller,它可以获取运行时方法的调用信息。...func Caller(skip int) (pc uintptr, file string, line int, ok bool) 参数skip表示跳过栈帧数,0表示不跳过,也就是runtime.Caller...以main函数调用log.Println为例,是main->log.Println->*Logger.Output->runtime.Caller这么一个方法调用栈,所以这时候,skip的值分别代表:...0表示*Logger.Output中调用runtime.Caller的源代码文件和行号 1表示log.Println中调用*Logger.Output的源代码文件和行号 2表示main中调用log.Println
. _, filename, _, _ := runtime.Caller(1) datapath := path.Join(path.Dir(filename), dataFile) golog.Info
line int, ok bool) package main import ( "runtime" "fmt" ) func main() { pc,file,line,ok := runtime.Caller...fmt.Println(file) fmt.Println(line) fmt.Println(ok) } [image.png] pc = 17380971 不是main函数自己的标识 runtime.Caller...13 标识它在main方法中的第13行被调用 package main import ( "runtime" "fmt" ) func main() { pc,_,line,_ := runtime.Caller...(2) fmt.Printf("show的上层函数的pc:%d\n",pc) fmt.Printf("show的上层函数被调用的行数:%d\n",line) pc,_,_,_ = runtime.Caller...(3) fmt.Println(pc) pc,_,_,_ = runtime.Caller(4) fmt.Println(pc) } [image.png] 通过上面的例子我演示了如何追踪一个方法被调用的顺序
image.png pc = 17380971 不是main函数自己的标识 runtime.Caller 方法的标识,line = 13 标识它在main方法中的第13行被调用 package main...import ( "runtime" "fmt" ) func main() { pc,_,line,_ := runtime.Caller(1) fmt.Printf("main...函数的pc:%d\n",pc) fmt.Printf("main函数被调用的行数:%d\n",line) show() } func show(){ pc,_,line,_ := runtime.Caller...(2) fmt.Printf("show的上层函数的pc:%d\n",pc) fmt.Printf("show的上层函数被调用的行数:%d\n",line) pc,_,_,_ = runtime.Caller...(3) fmt.Println(pc) pc,_,_,_ = runtime.Caller(4) fmt.Println(pc) } ?
pc = 17380971 不是main函数自己的标识 runtime.Caller 方法的标识,line = 13 标识它在main方法中的第13行被调用 package main import (..."runtime" "fmt" ) func main() { pc,_,line,_ := runtime.Caller(1) fmt.Printf("main函数的pc:%d\n...",pc) fmt.Printf("main函数被调用的行数:%d\n",line) show() } func show(){ pc,_,line,_ := runtime.Caller(...(2) fmt.Printf("show的上层函数的pc:%d\n",pc) fmt.Printf("show的上层函数被调用的行数:%d\n",line) pc,_,_,_ = runtime.Caller...(3) fmt.Println(pc) pc,_,_,_ = runtime.Caller(4) fmt.Println(pc) } ?
pc, fileName, line, ok := runtime.Caller(2) if ok { functionName = runtime.FuncForPC(pc).Name...读取 文件名、 方法名、 行号 使用的是 runtime.Caller()。 我们还知道,Go 有 panic 和 recover,它们是干什么的呢,接下来咱们就说说。...需要调整 runtime.Caller(2),这个代码在 alarm.go的alarm 方法中。...在这里,有必要说下 runtime.Caller(skip) 了。 skip 指的调用的深度。 为 0 时,打印当前调用文件及行数。 为 1 时,打印上级调用的文件及行数。 依次类推...
=nil) { _,file,line,_:=runtime.Caller(1) fmt.Fprintf(os.Stderr,"File: %s\nLine: %d\nErr: %v\n",file,line
func InitConf(dataFile string) { // 解决相对路经下获取不了配置文件问题 _, filename, _, _ := runtime.Caller(0) filePath...= &c.Svc Database = &c.DB Redis = &c.RedisConfig } 如果使用相对路经读取不到文件的,可以加入一下代码 _, filename, _, _ := runtime.Caller
通过runtime.Caller(2),runtime.FuncForPC(pc).Name()获取。...skip = false break } } if skip { return } // Determine caller func pc, _, lineno, ok := runtime.Caller...skip = false break } } if skip { return } // Determine caller func pc, _, lineno, ok := runtime.Caller...skip = false break } } if skip { return } // Determine caller func pc, _, lineno, ok := runtime.Caller
l.mu.Unlock() var ok bool _, file, line, ok = runtime.Caller(calldepth) if !
) var logType = Console var projectPath = "" // Init 在main.go中调用 func Init() { _, file, _, _ := runtime.Caller...string, level string) { now := time.Now().Format("2006-01-02 15:04:05") _, mFilepath, line, _ := runtime.Caller...github.com/gin-gonic/gin" "runtime" "time" ) func mCaller(skip int) string { pc, file, line, ok := runtime.Caller
领取专属 10元无门槛券
手把手带您无忧上云