如何转储goroutine stacktraces?

77 go

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

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

Int*_*net 90

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

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

例如:

import(
   "runtime/debug"
)
...    
debug.PrintStack()
Run Code Online (Sandbox Code Playgroud)

要打印所有 goroutines 的堆栈跟踪使用LookupWriteTo来自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.
Run Code Online (Sandbox Code Playgroud)

每个配置文件都有唯一的名称.预定义了一些配置文件:

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

例如:

pprof.Lookup("goroutine").WriteTo(os.Stdout, 1)
Run Code Online (Sandbox Code Playgroud)

  • @HowardGuo我添加了一个使用runtime/pprof来转储所有堆栈跟踪的示例. (4认同)
  • 我认为这只会输出每个线程当前正在运行的 goroutine,而不是 *all* goroutines,例如:http://play.golang.org/p/0hVB0_LMdm (2认同)

lnm*_*nmx 38

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

import _ "net/http/pprof"
import _ "net/http"
Run Code Online (Sandbox Code Playgroud)

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

go func() {
    log.Println(http.ListenAndServe("localhost:6060", nil))
}()
Run Code Online (Sandbox Code Playgroud)

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

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

  • 这也非常有用,谢谢 (2认同)

Bry*_*yan 34

要模仿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])
    }
}()
Run Code Online (Sandbox Code Playgroud)

  • 我认为这是作者真正想要的 - 模仿Java发送kill -QUIT时的作用.我必须做的一个小改动是将for()循环的第一行更改为:"< - sigs".换句话说,只需等待它就丢弃信号.Go的最新版本不允许您在不使用它的情况下声明变量. (3认同)

Rod*_*lho 30

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

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

此提交中添加了生成核心转储的文档和能力,自Go 1.1起,它就是AFAICT.

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

  • 在查看文档时,我没有找到任何SIGQUIT,而是SIGABRT.根据我自己的测试(使用go 1.7),后者也对前者起作用. (5认同)
  • 这应该是最佳答案。 (3认同)

Rob*_*jic 24

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

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

从文档:

func Stack(buf []byte, all bool) int
Run Code Online (Sandbox Code Playgroud)

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

  • 不要忘记添加字符串(buf),否则您将在其中打印原始字节。 (2认同)
  • 也许我做错了什么,或者功能已经改变,但是除了一个空的字节片之外,这并没有为我检索任何东西? (2认同)

Øyv*_*aar 14

CTRL + \

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

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

  • @user1766438 Ctrl+\ 是 SIGQUIT 的默认终端键序列,与 golang 无关 (3认同)
  • @phuclv 是的,但是 C++ 编译的程序在接收 SIGQUIT 时不会打印堆栈跟踪 (2认同)

Kyl*_*per 11

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

pkill -SIGABRT program_name


Dav*_*ill 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]))
}
Run Code Online (Sandbox Code Playgroud)


Ina*_*mus 5

默认情况下,按下^\键 ( 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")
}()
Run Code Online (Sandbox Code Playgroud)

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

# Press ^\ to dump the stack traces of all the user-created goroutines
$ GOTRACEBACK=all go run main.go
Run Code Online (Sandbox Code Playgroud)

如果您还想打印 go runtime goroutines:

$ GOTRACEBACK=system go run main.go
Run Code Online (Sandbox Code Playgroud)

以下是所有 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 的同义词。

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