出于跟踪目的,我想打印出当前函数名称,例如gcc中的__FUNCTION__宏。

这样当我有一个功能时

1
2
3
func foo () {
   trace()
}

它将自动打印出Entering foo()...或类似的内容。

  • 复制?

[注意:Go1.7建议使用runtime.CallersFrames代替runtime.FuncForPC;另一个答案有一个更新的示例]。

打包运行时是您的朋友:

1
2
3
4
5
6
7
8
func trace() {
    pc := make([]uintptr, 10)  // at least 1 entry needed
    runtime.Callers(2, pc)
    f := runtime.FuncForPC(pc[0])
    file, line := f.FileLine(pc[0])
    fmt.Printf("%s:%d %s\
", file, line, f.Name())
}
  • 仅供参考-文档确实说明了这一点,但这似乎是不准确的。我将这3个方法称为deep,它在源文件的第22行时报告了源文件中的第24行。然后,我尝试了一个方法调用deep,并且关闭了一行-不足以满足我的要求: ..但我不确定应该如何解释,似乎不如从堆栈跟踪中提取文件和行号那样准确。
  • 从Google偶然发现,但是上面的函数报告了下一个执行的函数的行号,请在此处play.golang.org/p/hpOXSUb8sD尝试。但是,这实际上是正确的行为,并在godoc.org/runtime#Callers中进行了记录。
  • 呼叫者功能的Golang文档在1.9永久链接中更改为github repo 1.6文档:github.com/golang/go/blob/release-branch.go1.6/src/runtime/…

Go1.7添加了一些运行时功能来改善对堆栈帧信息的访问。

摘自Go 1.7发行说明:

The new function CallersFrames translates a PC slice obtained from Callers into a sequence of frames corresponding to the call stack. This new API should be preferred instead of direct use of FuncForPC, because the frame sequence can more accurately describe call stacks with inlined function calls.

一个改进的示例:

1
2
3
4
5
6
7
8
func trace2() {
    pc := make([]uintptr, 15)
    n := runtime.Callers(2, pc)
    frames := runtime.CallersFrames(pc[:n])
    frame, _ := frames.Next()
    fmt.Printf("%s:%d %s\
", frame.File, frame.Line, frame.Function)
}

游乐场:https://play.golang.org/p/YkEN5mmbRld


这是一个更简单的版本,不需要分配数组。

1
2
3
4
5
6
7
8
9
func trace() (string, int, string) {
    pc, file, line, ok := runtime.Caller(1)
    if !ok { return"?", 0,"?" }

    fn := runtime.FuncForPC(pc)
    if fn == nil { return file, line,"?" }

    return file, line, fn.Name()
}
  • 不确定是否涵盖内联函数,请参见。 stackoverflow.com/questions/35212985/…