Your expectation is incorrect.
Let me paste your code here for ease of explanation:
package main
import (
"fmt"
"path/filepath"
"runtime"
"time"
)
func main() {
getFileName(1)
time.Sleep(time.Hour)
}
func getFileName(shift int) {
go func() {
_, file, line, ok := runtime.Caller(shift)
if !ok {
file = "???"
line = 0
} else {
file = filepath.Base(file)
}
fmt.Printf("%s:%d", file, line)
}()
}
Your anonymous function is running in a goroutine spawned by getFileName
.
Each goroutine executes using its own call stack, even the goroutine spawned by getFileName
starts with a fresh stack.
By invoking runtime.Caller(skip int)
with a skip value greater than zero, you can walk through the stack frames of the current goroutine.
In your example:
runtime.Caller(0)
prints main.go:17 because this is the line where runtime.Caller()
is actually called,
runtime.Caller(1)
prints asm_amd64p32.s:1014 because it is the top of the stack of the current goroutine,
runtime.Caller(x)
for any x > 1 returns with the boolean ok
set to false
because you're trying to access memory above the top of the stack.
If you're wondering what asm_amd64p32.s:1014 represents, actually it corresponds to the goexit assembly function of Go 1.8 (the Go Playground runs with the latest stable release of Go). Despite its name, the goexit
function is always at the top of a goroutine stack: it invokes the goroutine entry point function and then clean up the stack after the function returns. The goexit
implementation is architecture-specific, as it is most of the code that handles the details of the goroutines stack.
Back to your question, you cannot expect to see main.go:11 mentioned in the stacktrace of the goroutine spawned by getFileName
, because the main function is not in the stack at all. Don't spawn a goroutine, if you really need to print the stacktrace of the main function.
Having said that, there is something more to mention. The Go runtime actually stores additional information about where a goroutine has been spawned. The debug.PrintStack() function (which is in turn based on runtime.Stack()) is able to print it out in a nicely formatted stacktrace:
package main
import (
"time"
"runtime/debug"
)
func main() {
getFileName(1)
time.Sleep(time.Hour)
}
func getFileName(shift int) {
go func() {
debug.PrintStack()
}()
}
Output:
goroutine 5 [running]:
runtime/debug.Stack(0x0, 0x0, 0x0, 0x0)
/usr/local/go/src/runtime/debug/stack.go:24 +0x80
runtime/debug.PrintStack()
/usr/local/go/src/runtime/debug/stack.go:16 +0x20
main.getFileName.func1()
/tmp/sandbox085104368/main.go:15 +0x20
created by main.getFileName
/tmp/sandbox085104368/main.go:16 +0x40
Being all these details implementation-dependent and subject to change between different Go releases, there is - by design - no easy way to access them via the standard library. They're provided for debugging purposes and you, as a developer, should not rely on these information.