113

我有 Java 背景,我喜欢使用信号 QUIT 来检查 Java 线程转储。

如何让 Golang 打印出所有 goroutines 堆栈跟踪?

4

10 回答 10

133

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)
于 2013-09-30T12:40:11.947 回答
47

runtime/pprofIntermernet 的答案中提到的包有一个 HTTP 前端。导入net/http/pprof包以注册 HTTP 处理程序/debug/pprof

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

如果您还没有 HTTP 侦听器,请启动一个:

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

然后将浏览器指向http://localhost:6060/debug/pprof菜单或http://localhost:6060/debug/pprof/goroutine?debug=2完整的 goroutine 堆栈转储。

通过这种方式,您还可以了解有关正在运行的代码的其他有趣的事情。查看博客文章以获取示例和更多详细信息:http: //blog.golang.org/profiling-go-programs

于 2013-10-02T20:13:38.897 回答
41

为了模仿 SIGQUIT 上堆栈转储的 Java 行为,但仍让程序运行:

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])
    }
}()
于 2014-12-10T10:01:45.677 回答
38

与 Java 类似,SIGQUIT 可用于打印 Go 程序及其 goroutines 的堆栈跟踪。
然而,一个关键的区别是,默认情况下,向 Java 程序发送 SIGQUIT 不会终止它们,而 Go 程序会退出。

这种方法不需要更改代码即可打印现有程序的所有 goroutine 的堆栈跟踪。

环境变量 GOTRACEBACK(参见运行时包的文档)控制生成的输出量。例如,要包含所有 goroutine,设置 GOTRACEBACK=all。

堆栈跟踪的打印是由意外的运行时条件(未处理的信号)触发的,最初记录在这个 commit中,至少从 Go 1.1 开始就可以使用。


或者,如果可以选择修改源代码,请参阅其他答案。


请注意,在 Linux 终端中,可以使用组合键Ctrl+方便地发送 SIGQUIT \

于 2016-02-09T10:55:06.443 回答
28

您可以使用runtime.Stack获取所有 goroutine 的堆栈跟踪:

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

从文档中:

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

Stack 将调用 goroutine 的堆栈跟踪格式化为 buf 并返回写入 buf 的字节数。如果一切为真,Stack 会将所有其他 goroutine 的堆栈跟踪格式化为当前 goroutine 的跟踪之后的 buf。

于 2013-10-31T17:11:52.183 回答
24

CTRL+\

(如果您在终端中运行它并且只想杀死您的程序并转储 go 例程等)

我发现这个问题正在寻找关键序列。只是想要一种快速简便的方法来判断我的程序是否泄漏了 goroutine :)

于 2017-05-03T08:57:03.337 回答
13

在 *NIX 系统(包括 OSX)上发送信号 abort SIGABRT

pkill -SIGABRT program_name

于 2015-08-26T17:46:41.993 回答
10

默认情况下,^\按键(CTRL+\)转储所有 goroutine 的堆栈跟踪。


否则,要进行更精细的控制,您可以使用panic. Go 1.6+的简单方法:

go func() {
    s := make(chan os.Signal, 1)
    signal.Notify(s, syscall.SIGQUIT)
    <-s
    panic("give me the stack")
}()

然后,像这样运行你的程序:

# Press ^\ to dump the stack traces of all the user-created goroutines
$ GOTRACEBACK=all go run main.go

如果你还想打印 go runtime goroutines:

$ GOTRACEBACK=system go run main.go

以下是所有 GOTRACEBACK 选项:

  • GOTRACEBACK=none完全省略 goroutine 堆栈跟踪。
  • GOTRACEBACK=single (默认值)的行为如上所述。
  • GOTRACEBACK=all为所有用户创建的 goroutine 添加堆栈跟踪。
  • GOTRACEBACK=system类似all,但为运行时函数添加了堆栈帧,并显示了运行时内部创建的 goroutine。
  • GOTRACEBACK=crash就像system但以特定于操作系统的方式崩溃而不是退出。例如,在 Unix 系统上,崩溃引发SIGABRT以触发核心转储。

这是文档

GOTRACEBACK 变量控制当 Go 程序由于未恢复的恐慌或意外的运行时条件而失败时生成的输出量。

默认情况下,失败打印当前 goroutine 的堆栈跟踪,省略运行时系统内部的函数,然后以退出代码 2 退出。如果没有当前 goroutine 或失败是失败,则失败打印所有 goroutine 的堆栈跟踪运行时的内部。

由于历史原因,GOTRACEBACK 设置 0、1 和 2 分别是 none、all 和 system 的同义词。

runtime/debug 包的 SetTraceback 函数允许在运行时增加输出量,但它不能减少低于环境变量指定的量。请参阅https://golang.org/pkg/runtime/debug/#SetTraceback

于 2019-04-19T12:26:27.650 回答
5

有必要使用返回的长度runtime.Stack()来避免在堆栈跟踪之后打印一堆空行。以下恢复函数打印出格式良好的跟踪:

if r := recover(); r != nil {
    log.Printf("Internal error: %v", r))
    buf := make([]byte, 1<<16)
    stackSize := runtime.Stack(buf, true)
    log.Printf("%s\n", string(buf[0:stackSize]))
}
于 2015-06-19T17:28:45.410 回答
0

你可以使用这个:

kill -3 YOUR_PROCESS_PID_ID
于 2021-11-11T05:59:58.390 回答