如何转储goroutine stacktraces?


Answers:


107

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

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

例如:

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

要打印所有goroutine的堆栈跟踪,请使用LookupWriteToruntime/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
堆的堆栈跟踪-所有堆分配的采样
threadcreate-导致创建新OS线程
块的堆栈跟踪-导致对同步原语进行阻塞的堆栈跟踪

例如:

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

1
是否打印所有goroutine的堆栈跟踪?

它应该调用Stack。“堆栈返回调用它的goroutine的格式化堆栈跟踪。对于每个例程,它包括源行信息和PC值,然后尝试为Go函数发现调用函数或方法以及包含该行的文本。调用。”
Intermernet 2013年

1
抱歉,它仅显示当前goroutine堆栈跟踪。

4
@HowardGuo我添加了一个使用runtime / pprof来转储所有堆栈跟踪的示例。
Intermernet

1
我认为这只会输出每个线程当前正在运行的goroutine,而不是所有goroutine,例如:play.golang.org/p/0hVB0_LMdm
rogerdpack 2014年

39

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


我让它运行它只显示了我所看到的执行的goroutine。有什么办法可以看到main.go启动后执行的所有“方法”?
卢卡斯·卢卡奇

38

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

4
我认为这是作者真正寻找的,模仿了发送kill -QUIT时Java的行为。我必须做的一个小更改是将for()循环的第一行更改为:“ <-sigs”。换句话说,只需等待信号后就丢弃它。Go的最新版本不允许您在不稍后使用它的情况下声明变量。
George Armhold

@Bryan,您是否愿意根据BSD或StackOverflow要求的CC-BY-SA 3.0之外的其他更宽松的条款来许可此许可?
查尔斯·达菲

1
@CharlesDuffy在Apache许可下,您可以在这里找到很多相同的东西:github.com/weaveworks/weave/blob/…–
Bryan

37

与Java类似,SIGQUIT可用于打印Go程序及其goroutine的堆栈跟踪。
但是,关键的区别在于,默认情况下,将SIGQUIT发送到Java程序不会终止它们,而Go程序却会退出。

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

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

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


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


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


5
在浏览文档时,我没有提到SIGQUIT,而是SIGABRT。根据我自己的测试(1.7版),后者也优于前者。
soltysh '17

4
这应该是最佳答案。
史蒂文·索罗卡

该文档提到“当Go程序由于无法恢复的紧急情况或意外的运行时条件而失败时”。未捕获的信号(SIGQUIT等)是后者之一。为什么我提到SIGQUIT?因为OP表达了他们对将SIGQUIT与Java结合使用的热爱,所以这个答案强调了相似性。改写答案以使其更清晰。
Rodolfo Carvalho

26

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

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

从文档中:

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

堆栈将调用goroutine的堆栈跟踪格式格式化为buf,并返回写入buf的字节数。如果全部为真,则堆栈格式会将所有其他goroutine的跟踪信息堆叠到当前goroutine的跟踪信息之后的buf中。


包括所有goroutine的回溯信息,很好!
rogerdpack 2014年

这是无法恢复的恐慌归结为使用的格式吗?
Ztyx 2014年

2
不要忘记添加字符串(buf),否则您将在其中打印原始字节。
柯达

2
也许我做错了什么,或者功能已经更改,但是除了空字节之外,这对我没有任何帮助?
17xande

1
@koda不需要在string(buf)这里做,fmt.Printf("%s", buf)并且fmt.Printf("%s", string(buf))做完全相同的事情(请参阅docs以获取fmt软件包);唯一的区别是该string版本将buf不必要地复制字节
kbolino

20

CTRL + \

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

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



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]))
}

没有runtime.Trace; runtime.Stack 一年半前已经被提及
Dave C

我从未见过 您在什么平台上运行?
布赖恩2015年

你没看到什么?该代码应在所有平台上运行;我已经在Windows 7,Ubuntu 14.04和Mac上对其进行了测试。
David Tootill

从未见过空行。
布赖恩

4

默认情况下,^\按键(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例程:

$ GOTRACEBACK=system go run main.go

以下是所有GOTRACEBACK选项:

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

这是文档

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

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

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

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

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.