从导入的包中执行go例程的堆栈跟踪?
如何获取最后一个(理想情况下是所有)go例程(应用程序有多个go例程)的堆栈跟踪,该例程惊慌失措并恢复,只记录了一条不太具描述性的错误消息?我不知道哪种例行程序恢复了。另外,请记住,我不会更改任何导入包的代码。这种恐慌发生在一些导入的包中,这些包创建了多个go例程,因此我需要一种方法来抓取上次恢复的例程的堆栈跟踪,以便找到它恐慌的位置。简短的回答是:不可能,但存在异常 Golang有一些堆栈控制方法和类型 您可以使用以下命令控制堆栈级别:从导入的包中执行go例程的堆栈跟踪?,go,Go,如何获取最后一个(理想情况下是所有)go例程(应用程序有多个go例程)的堆栈跟踪,该例程惊慌失措并恢复,只记录了一条不太具描述性的错误消息?我不知道哪种例行程序恢复了。另外,请记住,我不会更改任何导入包的代码。这种恐慌发生在一些导入的包中,这些包创建了多个go例程,因此我需要一种方法来抓取上次恢复的例程的堆栈跟踪,以便找到它恐慌的位置。简短的回答是:不可能,但存在异常 Golang有一些堆栈控制方法和类型 您可以使用以下命令控制堆栈级别: func设置回溯(级别字符串) SetTraceback
func设置回溯(级别字符串)
SetTraceback设置运行时打印的详细信息量
在回溯中,它在退出之前打印,因为
未恢复的死机或内部运行时错误。
level参数采用与GOTRACEBACK相同的值
环境变量。例如,SetTraceback(“all”)确保
程序崩溃时打印所有goroutine。有关详细信息,请参阅包运行时文档。如果 使用低于的级别调用SetTraceback 环境变量,则忽略该调用 也可以使用打印堆栈strace
func Stack()[]字节
堆栈返回调用它的goroutine的格式化堆栈跟踪。它使用足够大的缓冲区调用runtime.Stack来捕获整个跟踪
您还需要了解内置函数recover的工作原理
恢复内置功能允许程序管理服务器的行为
惊慌失措的戈罗廷。执行调用以在延迟
函数(但不是它调用的任何函数)停止恐慌序列
通过恢复正常执行并检索传递给
恐慌的召唤。如果在deferred函数之外调用recover,它将
不能阻止一个恐慌的序列。在这种情况下,或者当goroutine不是
恐慌,或者如果提供给恐慌的参数为零,则恢复返回
无因此,recover的返回值报告goroutine是否为
惊慌失措
func recover()接口{}
工作示例
本例假设包不调用recover(在另一节中详细介绍)
如果包调用恢复
如果代码正在从死机中恢复,则需要使用调试器或删除recover
,以了解正在发生的情况,如下面的示例所示,该示例表明恢复的死机无法再次“恢复”
两害相轻
使用调试或临时编辑包,使其记录完整消息(一旦理解,您可以恢复更改)
此外,如果发现问题,请告知软件包作者,以便解决问题。为什么不能更改软件包代码?如果你能构建程序,你就有了代码。我会尝试,但我要求提供一种更方便的方法来获取主程序的跟踪:)如果代码从死机中恢复,你就看不到死机。您可以尝试在调试器中设置断点,但考虑到调试器的状态,注释掉
recover
并获取堆栈跟踪可能要快得多。
package main
import (
"log"
"errors"
"runtime/debug"
"time"
)
func f2() {
panic(errors.New("oops")) // line 11
}
func f1() {
f2() // line 15
}
func main() {
defer func() {
if e := recover(); e != nil {
log.Printf("%s: %s", e, debug.Stack()) // line 20
}
}()
go f1() // line 25
time.Sleep(time.Second * 1)
}
package main
import (
"log"
"errors"
"runtime/debug"
"time"
)
func f2() {
panic(errors.New("oops")) // line 11
}
func f1() {
defer func() {
if e := recover(); e != nil {
log.Printf("internal %s: %s", e, debug.Stack()) // line 20
}
}()
f2() // line 15
}
func main() {
defer func() {
if e := recover(); e != nil {
log.Printf("external %s: %s", e, debug.Stack()) // line 20
} else {
log.Println("Nothing to print")
}
}()
go f1() // line 25
time.Sleep(time.Second * 1)
}