Generating Stack Traces in Go
The ability to generate a stack trace can prove to be very useful, especially when writing log files. The Go language's runtime
package provides a helper for generating a stack trace. Here's how to use it.
Simply put, you can grab a stack trace from just about anywhere in a Go program. Import the runtime
package, create a []byte
to use as a buffer, and then call runtime.Stack()
:
import (
"runtime"
"fmt"
)
func main() {
trace := make([]byte, 1024)
count := runtime.Stack(trace, true)
fmt.Printf("Stack of %d bytes: %s", count, trace)
}
The above will print a simple stack trace. Note that the second argument to runtime.Stack()
is a boolean flag. If true
, every running go routine will also dump a stack. If false, only the current go routine will dump a stack trace.
More often, it is useful to print a stack trace as a response to an error or panic. Here's a more complex example that shows not only the stack trace gathering, but how it might be employed in response to a panic()
.
package main
import (
"runtime"
"fmt"
)
func main() {
outer()
}
func outer() {
inner()
}
func inner() {
defer func() {
if err := recover(); err != nil {
trace := make([]byte, 1024)
count := runtime.Stack(trace, true)
fmt.Printf("Recover from panic: %s\n", err)
fmt.Printf("Stack of %d bytes: %s\n", count, trace)
}
}()
panic("Fake error!")
}
To make the trace a little more interesting, I artificially added some empty layers. In a nutshell, main()
calls outer()
, which calls inner()
, which defers an panic handler and then panics.
The panic handler then calls recover()
and, if there is a panic to recover from, prints the panic message along with a stack trace. Here's what it looks like when we run it:
$ go run stack.go
Recover from panic: Fake error!
Stack of 402 bytes: goroutine 1 [running]:
main.func·001()
/Users/mbutcher/Code/Go/src/scratch/stack.go:21 +0xab
runtime.panic(0x80b80, 0x2101fb150)
/usr/local/Cellar/go/1.2/libexec/src/pkg/runtime/panic.c:248 +0x106
main.inner()
/Users/mbutcher/Code/Go/src/scratch/stack.go:27 +0x68
main.outer()
/Users/mbutcher/Code/Go/src/scratch/stack.go:13 +0x1a
main.main()
/Users/mbutcher/Code/Go/src/scratch/stack.go:9 +0x1a