简介
拥有必要的 Go 语言调试技巧能让我们在定位问题的时候节省大量的时间。我认为尽可能地记录下详尽的日志信息是一个很好的实践,但是有时候单单记录下错误是不足够的。正确的理解 stack trace(堆栈轨迹)的信息能让你准确地定位到 bug 的所在,避免出现日志记录不够,需要添加更多跟踪日志,然后等待 bug 重现的窘境。
我在开始编写 Go 程序的时候就已经开始了解 stack trace 方面的知识。我们有时会写错代码,使得 Go 运行时 panic 掉我们的程序并抛出一个 stack trace。我将会在本文中告诉你 stack trace 给我们提供了什么信息,还有如何查看到每个函数被调用时传递给它的参数的值。
函数
我们先来写一小段会导致程序崩溃并抛出 stack trace 的代码:
清单 1
package main
func main() {
slice := make([]string, 2, 4)
Example(slice, "hello", 10)
}
func Example(slice []string, str string, i int) {
panic("Want stack trace")
}
清单 1 的 main
函数在第 5 行调用了 Example
函数,这个在第 8 行声明的 Example
函数接收 3 个参数:一个字符串切片、一个字符串和一个整型。Example
函数唯一的代码就是调用内置的 panic
函数(在第 9 行),这个函数会导致程序退出并立刻打印出一个 stack trace:
清单 2
Panic: Want stack trace
goroutine 1 [running]:
main.Example(0x2080c3f50, 0x2, 0x4, 0x425c0, 0x5, 0xa)
/Users/bill/Spaces/Go/Projects/src/github.com/goinaction/code/
temp/main.go:9 +0x64
main.main()
/Users/bill/Spaces/Go/Projects/src/github.com/goinaction/code/
temp/main.go:5 +0x85
goroutine 2 [runnable]:
runtime.forcegchelper()
/Users/bill/go/src/runtime/proc.go:90
runtime.goexit()
/Users/bill/go/src/runtime/asm_amd64.s:2232 +0x1
goroutine 3 [runnable]:
runtime.bgsweep()
/Users/bill/go/src/runtime/mgc0.go:82
runtime.goexit()
/Users/bill/go/src/runtime/asm_amd64.s:2232 +0x1
清单 2 中的 stack trace 显示了 panic 的时候所有存在的 Goroutine、所有 Goroutine 的运行状态和 Goroutine 对应的调用栈。正在运行并且导致了程序 panic 的 Goroutines 将会在顶上。我们先来关注一下导致 panic 的 Goroutine。
清单 3
01 Goroutine 1 [running]:
02 main.Example(0x2080c3f50, 0x2, 0x4, 0x425c0, 0x5,