如何获取最后(理想情况下)go例程(应用程序具有多个go例程)的堆栈跟踪(该例程恐慌并恢复并仅记录了很少的描述性错误消息)?我不知道哪个程序恢复了。另外,请记住,我不会更改任何导入包的代码。这种恐慌发生在某些导入的程序包中,该程序包创建了多个go例程,因此我需要一种方法来捕获上次恢复的例程的堆栈跟踪,以便找到恐慌的地方。
简短的答案是:不可能,但是有例外。
Golang有一些堆栈控制方法和类型。
您可以使用runtime / debug / SetTraceback控制堆栈级别
func SetTraceback(level string)
SetTraceback设置运行时在由于无法恢复的紧急情况或内部运行时错误而退出之前在其打印的回溯中打印的详细信息量。level参数采用与GOTRACEBACK环境变量相同的值。例如,SetTraceback(“ all”)确保程序在崩溃时打印所有goroutine。
有关详细信息,请参见程序包运行时文档。如果以低于环境变量的级别调用SetTraceback,则该调用将被忽略。
您还可以使用runtime / debug / Stack打印堆栈strace
func Stack() []byte
堆栈返回调用它的goroutine的格式化堆栈跟踪。它使用足够大的缓冲区调用runtime.Stack来捕获整个跟踪。
另外,您还需要了解内置功能的recover
工作原理。
恢复内置功能允许程序管理紧急恐慌例程的行为。在延迟函数(但不是由它调用的任何函数)中执行恢复调用将通过恢复正常执行来停止恐慌序列,并检索传递给panic调用的错误值。如果在延迟函数之外调用了restore,它将不会停止紧急处理序列。在这种情况下,或者当goroutine没有惊慌时,或者如果提供给panic的参数为nil,则restore返回nil。因此,来自recovery的返回值将报告goroutine是否感到恐慌。
func recover() interface{}
此示例假定程序包未调用恢复(在另一节中详细介绍)。
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)
}
如果代码正在从紧急情况中恢复,则需要使用调试器或删除,recover
以了解正在发生的情况,如以下示例所示,该示例表明已恢复的紧急情况无法再次“恢复”。
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)
}
使用Delve调试或临时编辑软件包,以便记录完整的消息(一旦了解,您可以还原更改)。
另外,如果您发现问题,请让软件包作者知道,以便可以解决。
本文收集自互联网,转载请注明来源。
如有侵权,请联系 [email protected] 删除。
我来说两句