Go1.17 新特性,優化拋出的錯誤堆棧
本文轉載自微信公眾號「腦子進煎魚了」,作者陳煎魚。轉載本文請聯系腦子進煎魚了公眾號。
大家好,我是煎魚。
平時在日常工程中,我們常常會用到異常恐慌(panic)的記錄和追蹤。最常見的就是,線上 panic 了之后,我們總想從中找到一些蛛絲馬跡。
我們很多人是看 panic 是看他的調用堆棧。然后就開始猜,看代碼。猜測是不是哪里寫的有問題,就想知道 panic 是由什么參數引起的?
因為知道了誘發的參數,排查問題就非常方便了。為此在 Go1.17,官方對這塊的調用堆棧信息展示進行了優化,使其可讀性更友好。
案例
結合我們平時所使用的 panic 案例。如下:
- func main() {
- example(make([]string, 1, 2), "煎魚", 3)
- }
- //go:noinline
- func example(slice []string, str string, i int) error {
- panic("腦子進煎魚了")
- }
運行結果:
- $ go run main.go
- panic: 腦子進煎魚了
- goroutine 1 [running]:
- main.example(0xc000032758, 0x1, 0x2, 0x1073d11, 0x6, 0x3, 0xc000102058, 0x1013201)
- /Users/eddycjy/go-application/awesomeProject/main.go:9 +0x39
- main.main()
- /Users/eddycjy/go-application/awesomeProject/main.go:4 +0x68
- exit status 2
我們函數的入參是:[]string、string、int,核心關注到 main.example 方法的調用堆棧信息:
- main.example(
- 0xc000032758,
- 0x1,
- 0x2,
- 0x1073d11,
- 0x6,
- 0x3,
- 0xc000102058,
- 0x1013201
- )
明明只是函數三個參數,卻輸出了一堆,對應起來非常的不清晰。
其實際對應是:
- slice:0xc000032758、0x1、0x2。
- string:0x1073d11、0x6。
- int:0x3。
這里存在的問題是,看調用堆棧的人,還得必須了解基本數據結構(例如:slice、string、int 等),他才知道每個函數入參他對應擁有幾個字段,才能知道其內存布局的結構,有一點麻煩。
并且從程序運行的角度來講,這么水平平鋪的方式,并不直觀和準確。因為不同類型他是多個字段組合成結構才能代表一個類型。這不得還要人為估測?
優化
終于,這一塊的調用堆棧查看在 Go1.17 做了正式的改善。如下:
- $ go1.17 run main.go
- panic: 腦子進煎魚了
- goroutine 1 [running]:
- main.example({0x0, 0xc0000001a0, 0xc000034770}, {0x1004319, 0x60}, 0x0)
- /Users/eddycjy/go-application/awesomeProject/main.go:9 +0x27
- main.main()
- /Users/eddycjy/go-application/awesomeProject/main.go:4 +0x47
- exit status 2
新版本的調用堆棧的信息改變:
- main.example(
- {0x0, 0xc0000001a0, 0xc000034770},
- {0x1004319, 0x60},
- 0x0
- )
在 Go 語言以前的版本中,調用堆棧中的函數參數被打印成基于內存布局的十六進制值的形式,比較難以讀取。
在 Go1.17 后,每個函數的參數都會被單獨打印,并且以 “,” 隔開,復合數據類型(例如:結構體、數組、切片等)的參數會用大括號包裹起來,整體更易讀。
其實際對應如下:
- slice:0x0, 0xc0000001a0, 0xc000034770。
- string:0x1004319, 0x60。
- int:0x0。
這里也有一塊細節要注意,你會發現 Go1.17 的函數參數的數量和以往的版本相比,少了。是因為函數的返回值存在于寄存器中,而不會存儲到內存中。
因此函數返回值可能會是不準確的,所以也在新版本中也就不再打印了。
總結
在 Go1.17 的新版本中,調用堆棧的函數參數的可讀性得到了進一步的優化和調整,在后續的使用上可能能夠帶來一定的排錯效率的提高。
你平時在借助調用堆棧排查問題呢,希望還獲得什么輔助呢?
參考
GoTip: New Stack Trace Output Wrong
cmd/compile: bad traceback arguments
Go 1.17新特性詳解:使用基于寄存器的調用慣例
doc/go1.17: reword "results" in stack trace printing