如何转储goroutine的堆栈跟踪?

huangapple go评论128阅读模式
英文:

How to dump goroutine stacktraces?

问题

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

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

英文:

I have Java background, and I love to use signal QUIT to inspect Java thread dump.

How to let Golang print out all goroutines stack trace?

答案1

得分: 161

要打印当前goroutine的堆栈跟踪,请使用runtime/debug中的PrintStack()函数。

>>PrintStack函数将标准错误输出中的堆栈跟踪打印出来。

例如:

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

要打印所有goroutine的堆栈跟踪,请使用runtime/pprof中的LookupWriteTo函数。

func Lookup(name string) *Profile
// Lookup函数返回给定名称的profile,
// 如果没有该profile,则返回nil。

func (p *Profile) WriteTo(w io.Writer, debug int) error
// WriteTo函数将profile以pprof格式写入w。
// 如果写入w时发生错误,WriteTo函数将返回该错误。
// 否则,WriteTo函数返回nil。

>每个Profile都有一个唯一的名称。一些预定义的profile有:
>
goroutine - 所有当前goroutine的堆栈跟踪
heap - 所有堆分配的采样
threadcreate - 导致创建新的操作系统线程的堆栈跟踪
block - 导致在同步原语上阻塞的堆栈跟踪

例如:

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

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)

答案2

得分: 50

在Intermernet的回答中提到了runtime/pprof包的HTTP前端。导入net/http/pprof包以注册/debug/pprof的HTTP处理程序:

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

英文:

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

答案3

得分: 46

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

这种方法无需对现有程序进行任何代码更改即可打印所有goroutine的堆栈跟踪。

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

堆栈跟踪的打印是由意外的运行时条件(未处理的信号)触发的,最初在此提交中记录(https://github.com/golang/go/commit/5146a93e72e870b06150c5419e1b83056ecc697b),至少从Go 1.1版本开始可用。


另外,如果修改源代码是一个选项,请参考其他答案。


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

英文:

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 <kbd>Ctrl</kbd>+<kbd>&lt;/kbd>.

答案4

得分: 43

为了模仿Java在SIGQUIT信号上的堆栈转储行为,但仍然保持程序运行:

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("=== 收到 SIGQUIT 信号 ===\n*** goroutine 转储...\n%s\n*** 结束\n", buf[:stacklen])
    }
}()

请注意,这是一个使用Go语言编写的代码示例,用于在接收到SIGQUIT信号时打印出当前的goroutine堆栈信息。

英文:

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

<!-- language: lang-golang -->

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

答案5

得分: 30

你可以使用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的字节数。如果all为true,则Stack在当前goroutine的跟踪之后,将所有其他goroutine的堆栈跟踪格式化到buf中。

英文:

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

buf := make([]byte, 1&lt;&lt;16)
runtime.Stack(buf, true)
fmt.Printf(&quot;%s&quot;, 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.

答案6

得分: 29

按下 CTRL+\

(如果你在终端中运行程序,只想终止程序并转储go routines等)

我在寻找这个键序列时找到了这个问题。只是想要一个快速简单的方法来判断我的程序是否泄漏了go routines 如何转储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 如何转储goroutine的堆栈跟踪?

答案7

得分: 14

在*NIX系统(包括OSX)上发送一个中止信号SIGABRT

pkill -SIGABRT program_name

英文:

On *NIX systems (including OSX) send a signal abort SIGABRT:

pkill -SIGABRT program_name

答案8

得分: 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")
}()

然后,像这样运行程序:

# 按下 ^\ 来转储所有用户创建的 goroutine 的堆栈跟踪
$ GOTRACEBACK=all go run main.go

如果您还想打印 Go 运行时的 goroutine:

$ 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 程序由于无法恢复的 panic 或意外的运行时条件而失败时生成的输出量。

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

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

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

英文:

By default, press ^\ keys ( CTRL+\ ) to dump the stack traces of all goroutines.


Otherwise, for more granular control, you can use panic. The simple way as of Go 1.6+:

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

Then, run your program like so:

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

If you also want to print go runtime goroutines:

$ GOTRACEBACK=system go run main.go

Here are all the GOTRACEBACK options:

  • GOTRACEBACK=none omits the goroutine stack traces entirely.
  • GOTRACEBACK=single (the default) behaves as described above.
  • GOTRACEBACK=all adds stack traces for all user-created goroutines.
  • GOTRACEBACK=system is like all but adds stack frames for run-time functions and shows goroutines created internally by the run-time.
  • GOTRACEBACK=crash is like system but crashes in an operating system-specific manner instead of exiting. For example, on Unix systems, the crash raises SIGABRT to trigger a core dump.

Here is the documentation

> The GOTRACEBACK variable controls the amount of output generated when a Go program fails due to an unrecovered panic or an unexpected runtime condition.
>
> By default, a failure prints a stack trace for the current goroutine, eliding functions internal to the run-time system, and then exits with exit code 2. The failure prints stack traces for all goroutines if there is no current goroutine or the failure is internal to the run-time.
>
> For historical reasons, the GOTRACEBACK settings 0, 1, and 2 are synonyms for none, all, and system, respectively.
>
> The runtime/debug package's SetTraceback function allows increasing the amount of output at run time, but it cannot reduce the amount below that specified by the environment variable. See https://golang.org/pkg/runtime/debug/#SetTraceback.

答案9

得分: 5

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

if r := recover(); r != nil {
    log.Printf("内部错误:%v", r))
    buf := make([]byte, 1<<16)
    stackSize := runtime.Stack(buf, true)
    log.Printf("%s\n", string(buf[0:stackSize]))
}
英文:

It's necessary to use the length returned by runtime.Stack() to avoid printing a bunch of empty lines after your stack trace. The following recovery function prints a nicely formatted trace:

if r := recover(); r != nil {
    log.Printf(&quot;Internal error: %v&quot;, r))
    buf := make([]byte, 1&lt;&lt;16)
    stackSize := runtime.Stack(buf, true)
    log.Printf(&quot;%s\n&quot;, string(buf[0:stackSize]))
}

答案10

得分: 1

你可以使用以下命令:

kill -3 YOUR_PROCESS_PID_ID
英文:

You can use this:

kill -3 YOUR_PROCESS_PID_ID

huangapple
  • 本文由 发表于 2013年9月30日 20:17:48
  • 转载请务必保留本文链接:https://go.coder-hub.com/19094099.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定