Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I dump all a Go process's stacks without killing it?

Tags:

go

A Go process is running. I want to

  1. dump a stack trace for each of its goroutines
  2. from the outside, without depending on anything I add to its source code
  3. without killing it.

How can I do that?

This should be easy -- the feature was requested: https://code.google.com/p/go/issues/detail?id=2516 and, according to the conclusion of that thread, implemented. That was over two years ago. But neither the issue thread nor the commit contains any hint as to how to invoke this feature.

The feature request mentioned SIGQUIT as the signal the JVM accepts to invoke the corresponding feature there. But SIGQUIT isn't the answer; on go1.2 at least, SIGQUIT does #1 and #2 but also kills the process.

Someone asked a related question here a while ago: How to dump goroutine stacktraces? but they didn't clearly ask for #2 or #3, none of the answers meet #2, and they accepted an answer that doesn't meet #2. So this is a different question.

like image 950
Greg Price Avatar asked Apr 29 '14 03:04

Greg Price


Video Answer


2 Answers

You can set up a handler like that using code something like this:

import (
    "fmt"
    "os"
    "os/signal"
    "runtime"
    "syscall"
)

func main() {
    sigChan := make(chan os.Signal)
    go func() {
        stacktrace := make([]byte, 8192)
        for _ = range sigChan {
            length := runtime.Stack(stacktrace, true)
            fmt.Println(string(stacktrace[:length]))
        }
    }()
    signal.Notify(sigChan, syscall.SIGQUIT)


    ...
}

The SIGQUIT signal will now be caught and sent to the given channel. The runtime.Stack function is then used to format the stack trace into a prepared buffer (if it is larger than the buffer, it will be truncated), and then printed.

like image 63
James Henstridge Avatar answered Oct 06 '22 09:10

James Henstridge


If you are using net/http you can access the goroutines via the debug handlers. If you look at the following source

http://golang.org/src/pkg/runtime/pprof/pprof.go

You will see the profile, goroutineProfile, on line 62. This profile writes out via writeGoroutine. If writeGoroutine is called with debug >= 2 then it will write out all goroutines.

You should be able to curl http://localhost:<port>/debug/pprof/goroutine?debug=2 to get all goroutines dumped. Unfortunately I didn't see any references to signal handlers that would call that code but you can look at references to how pprof makes use of runtime.Stack in the source above to implement this yourself pretty easily.

like image 6
Gary M Josack Avatar answered Oct 06 '22 09:10

Gary M Josack