66

For tracing purpose, I'd like to print out current function name, like the __FUNCTION__ macro in gcc.

So that when I have a function

func foo () {
   trace()
}

it will automatically print out Entering foo()... or something like that.

Jonathan Hall
  • 75,165
  • 16
  • 143
  • 189
lang2
  • 11,433
  • 18
  • 83
  • 133
  • [Duplicate?](https://stackoverflow.com/questions/7052693/how-to-get-the-name-of-a-function-in-go) – mekb Aug 10 '19 at 11:26

4 Answers4

71

[Note: Go 1.7+ recommends using runtime.CallersFrames instead of runtime.FuncForPC; another answer has an updated example].

Package runtime is your friend here:

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\n", file, line, f.Name())
}
Dave C
  • 7,729
  • 4
  • 49
  • 65
Volker
  • 40,468
  • 7
  • 81
  • 87
  • Just an FYI - the documentation does state this, but this seems inaccurate. I called this 3 methods deep and it reports line 24 in the source file when its line 22. I then tried a single method call deep and it is one line off - not good enough for my requirements :( The documentation does state `The result will not be accurate if pc is not a program counter within f` .. but I'm not sure how I should be interpreting that. Doesn't seem as accurate as extracting the file and line number from a stack trace. – Simon Whitehead Sep 21 '14 at 12:35
  • 1
    Stumbled upon this from google, but the above function reports the line number of the next function that is executed, try it here https://play.golang.org/p/hpOXSUb8sD. However, this is actually correct behavior and is documented here https://godoc.org/runtime#Callers. – ksrb Apr 04 '17 at 20:45
  • 1
    Golang documentation for the Callers function changed in 1.9 permalink to github repo 1.6 documentation: https://github.com/golang/go/blob/release-branch.go1.6/src/runtime/extern.go#L186-L199 – ksrb Sep 18 '17 at 18:21
52

Go 1.7 added some runtime functions to improve accessing stack frame information.

From the Go 1.7 Release Notes:

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.

An improved example:

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

Playground: https://play.golang.org/p/YkEN5mmbRld

Dave C
  • 7,729
  • 4
  • 49
  • 65
ksrb
  • 1,797
  • 12
  • 22
10

Here's a simpler version that doesn't need to allocate an array.

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()
}
  • 2
    Not sure this covers inline functions, cf. https://stackoverflow.com/questions/35212985/is-it-possible-get-information-about-caller-function-in-golang/38551362#comment105339231_38551362 – Benjamin Toueg Mar 26 '20 at 11:29
2

pc, _, _, _ := runtime. Caller(0)
log.Println(runtime.FuncForPC(pc).Name())

  • 6
    While this code may solve the question, [including an explanation](//meta.stackexchange.com/q/114762) of how and why this solves the problem would really help to improve the quality of your post, and probably result in more up-votes. Remember that you are answering the question for readers in the future, not just the person asking now. Please [edit] your answer to add explanations and give an indication of what limitations and assumptions apply. – Yunnosch Jan 17 '23 at 07:20