如何转储goroutine stacktraces?

时间:2013-09-30 12:17:49

标签: go

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

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

9 个答案:

答案 0 :(得分:84)

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

  
    

PrintStack将Stack返回的堆栈跟踪打印到标准错误。

  

例如:

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

要打印所有 goroutines的堆栈跟踪,请使用Lookup中的WriteToruntime/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.
  

每个个人资料都有一个唯一的名称。预定义了一些配置文件:

     

goroutine - 所有当前goroutine的堆栈痕迹
  heap - 所有堆分配的采样
  threadcreate - 导致创建新OS线程的堆栈跟踪
  块 - 导致阻塞同步原语的堆栈跟踪

例如:

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

答案 1 :(得分:34)

在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

答案 2 :(得分:31)

模仿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])
    }
}()

答案 3 :(得分:24)

根据docs of the runtime package,默认情况下,将SIGQUIT发送到Go程序将为每个现有的goroutine打印堆栈跟踪,删除运行时系统内部的函数,然后退出,退出代码为2

环境变量GOTRACEBACK控制生成的输出量。要包含所有goroutine,不进行过滤,请设置GOTRACEBACK = 2。要另外生成核心转储(在Unix系统上),请设置GOTRACEBACK = crash。

this commit中添加了生成核心转储的文档和能力,并且自Go 1.1以来一直是AFAICT。

因此,这种方法不需要代码来打印所有goroutine的堆栈跟踪。与Java的区别在于Java将继续运行程序,而Go将退出。

答案 4 :(得分:23)

您可以使用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的堆栈跟踪格式化为buf   目前的goroutine。

答案 5 :(得分:13)

CTRL + \

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

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

答案 6 :(得分:8)

On * NIX系统(包括OSX)发送信号中止SIGABRT

pkill -SIGABRT program_name

答案 7 :(得分:4)

有必要使用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]))
}

答案 8 :(得分:0)

默认情况下,按^\键( 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
$ GOTRACE=all go run main.go

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

$ GOTRACE=system go run main.go

以下是所有的GOTRACE选项:

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

Here is the documentation

  

GOTRACEBACK变量控制在Go程序由于无法恢复的紧急情况或意外的运行时条件而失败时生成的输出量。

     

默认情况下,故障将打印当前goroutine的堆栈跟踪,清除运行时系统内部的函数,然后以退出代码2退出。如果没有当前goroutine或Windows XP,则故障将打印所有goroutine的堆栈跟踪。故障是运行时内部的。

     

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

     

运行时/调试程序包的SetTraceback函数允许在运行时增加输出量,但是不能将其减少到环境变量指定的量以下。参见https://golang.org/pkg/runtime/debug/#SetTraceback