英文:
How can I dump all a Go process's stacks without killing it?
问题
一个Go进程正在运行。我想要:
- 对每个goroutine进行堆栈跟踪
- 从外部进行操作,而不依赖于我添加到源代码中的任何内容
- 不杀死该进程。
我该如何做到这一点?
这应该很简单 - 这个功能已经被请求:https://code.google.com/p/go/issues/detail?id=2516 并且根据该线程的结论,已经实现了。那是两年多以前的事了。但是无论是问题线程还是提交中都没有提到如何调用这个功能的任何提示。
该功能请求中提到了SIGQUIT作为JVM接受的信号来调用相应的功能。但SIGQUIT不是答案;至少在go1.2中,SIGQUIT会执行#1和#2,但也会终止进程。
有人在这里之前问过一个相关的问题:https://stackoverflow.com/questions/19094099/how-to-dump-goroutine-stacktrace
但他们没有明确要求#2或#3,所有答案都不符合#2,并且他们接受了一个不符合#2的答案。所以这是一个不同的问题。
英文:
A Go process is running. I want to
- dump a stack trace for each of its goroutines
- from the outside, without depending on anything I add to its source code
- 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: https://stackoverflow.com/questions/19094099/how-to-dump-goroutine-stacktrace
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.
答案1
得分: 14
你可以使用类似以下代码来设置一个处理程序:
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)
// ...
}
现在,SIGQUIT
信号将被捕获并发送到指定的通道。然后,runtime.Stack
函数用于将堆栈跟踪格式化为预先准备好的缓冲区(如果它大于缓冲区,则会被截断),然后打印出来。
英文:
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.
答案2
得分: 6
如果你正在使用net/http,你可以通过调试处理程序访问goroutines。如果你查看以下源代码:
http://golang.org/src/pkg/runtime/pprof/pprof.go
你会在第62行看到一个名为goroutineProfile
的profile。这个profile通过writeGoroutine
进行输出。如果以debug >= 2的方式调用writeGoroutine,它将输出所有的goroutines。
你可以使用curl http://localhost:<port>/debug/pprof/goroutine?debug=2
来获取所有的goroutines。不幸的是,我没有看到任何调用该代码的信号处理程序的引用,但你可以查看上述源代码中pprof如何使用runtime.Stack
来自己实现这个功能。
英文:
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.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论