Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to dump goroutine stacktraces?

Tags:

go

To print the stack trace for the current goroutine, use PrintStack() from runtime/debug.

PrintStack prints to standard error the stack trace returned by Stack.

For example:

import(
   "runtime/debug"
)
...    
debug.PrintStack()

To print the stack trace for all goroutines use Lookup and WriteTo from runtime/pprof.

func Lookup(name string) *Profile
// Lookup returns the profile with the given name,
// or nil if no such profile exists.

func (p *Profile) WriteTo(w io.Writer, debug int) error
// WriteTo writes a pprof-formatted snapshot of the profile to w.
// If a write to w returns an error, WriteTo returns that error.
// Otherwise, WriteTo returns nil.

Each Profile has a unique name. A few profiles are predefined:

goroutine - stack traces of all current goroutines
heap - a sampling of all heap allocations
threadcreate - stack traces that led to the creation of new OS threads
block - stack traces that led to blocking on synchronization primitives

For example:

pprof.Lookup("goroutine").WriteTo(os.Stdout, 1)

There is an HTTP frontend for the runtime/pprof package mentioned in Intermernet's answer. Import the net/http/pprof package to register an HTTP handler for /debug/pprof:

import _ "net/http/pprof"
import _ "net/http"

Start an HTTP listener if you do not have one already:

go func() {
    log.Println(http.ListenAndServe("localhost:6060", nil))
}()

Then point a browser to http://localhost:6060/debug/pprof for a menu, or http://localhost:6060/debug/pprof/goroutine?debug=2 for a full goroutine stack dump.

There are other fun things you can learn about your running code this way too. Check out the blog post for examples and more details: http://blog.golang.org/profiling-go-programs


To mimic the Java behaviour of stack-dump on SIGQUIT but still leaving the program running:

go func() {
    sigs := make(chan os.Signal, 1)
    signal.Notify(sigs, syscall.SIGQUIT)
    buf := make([]byte, 1<<20)
    for {
        <-sigs
        stacklen := runtime.Stack(buf, true)
        log.Printf("=== received SIGQUIT ===\n*** goroutine dump...\n%s\n*** end\n", buf[:stacklen])
    }
}()

Similar to Java, SIGQUIT can be used to print a stack trace of a Go program and its goroutines.
A key difference, however, is that by default sending SIGQUIT to Java programs do not terminate them, while Go programs do exit.

This approach requires no code change to print a stack trace of all goroutines of existing programs.

The environment variable GOTRACEBACK (see documentation of the runtime package) controls the amount of output generated. For example, to include all goroutines, set GOTRACEBACK=all.

The printing of the stack trace is triggered by an unexpected runtime condition (unhandled signal), originally documented in this commit, making it available since at least Go 1.1.


Alternatively, if modifying source code is an option, see other answers.


Note that in a Linux terminal, SIGQUIT can be conveniently sent with the key combination Ctrl+\.


You can use runtime.Stack to get the stack trace of all goroutines:

buf := make([]byte, 1<<16)
runtime.Stack(buf, true)
fmt.Printf("%s", buf)

From the documentation:

func Stack(buf []byte, all bool) int

Stack formats a stack trace of the calling goroutine into buf and returns the number of bytes written to buf. If all is true, Stack formats stack traces of all other goroutines into buf after the trace for the current goroutine.


Press CTRL+\

(If you run it in a terminal and just want to kill your program and dump the go routines etc)

I found this question looking for the key sequence. Just wanted a quick and easy way to tell if my program is leaking go routines :)