golang捕獲panic
阿新 • • 發佈:2019-01-09
golang當中panic的時候如果啟動的goroutine比較多,刷的資訊滿屏都是,在終端工具上因為刷的資訊太多,找不到前邊的資訊,因此很有必要程式自己捕獲panic,並且將錯誤資訊輸出到檔案當中,以便定位排查問題。
以下是一段捕獲panic的程式碼
package main
import (
"fmt"
"os"
"runtime/debug"
"time"
)
func PanicHandler() {
exeName := os.Args[0] //獲取程式名稱
now := time.Now() //獲取當前時間
pid := os.Getpid() //獲取程序ID
time_str := now.Format("20060102150405") //設定時間格式
fname := fmt.Sprintf("%s-%d-%s-dump.log", exeName, pid, time_str) //儲存錯誤資訊檔名:程式名-程序ID-當前時間(年月日時分秒)
fmt.Println("dump to file ", fname)
f, err := os.Create(fname)
if err != nil {
return
}
defer f.Close()
if err := recover(); err != nil {
f.WriteString(fmt.Sprintf("%v\r\n", err)) //輸出panic資訊
f.WriteString("========\r\n")
}
f.WriteString(string(debug.Stack())) //輸出堆疊資訊
}
以下是測試程式,這裡我們測試除數為0的異常
package main
import (
"fmt"
//"sync"
)
func test_panic() {
n := 0
i := 5 / n
fmt.Println(i)
}
func main() {
defer PanicHandler()
test_panic()
/*
var wg sync.WaitGroup
wg.Add(1)
go func() {
defer PanicHandler()
test_panic()
wg.Done()
}()
wg.Wait()
*/
}
捕獲的錯誤資訊如下:
runtime error: integer divide by zero
========
F:/MyProject/Go/src/panictest/panicHandler.go:31 (0x4017c2)
PanicHandler: f.WriteString(string(debug.Stack())) //輸出堆疊資訊
c:/go/src/runtime/asm_amd64.s:437 (0x4543e5)
call32: CALLFN(·call32, 32)
c:/go/src/runtime/panic.go:423 (0x4291f7)
gopanic: reflectcall(nil, unsafe.Pointer(d.fn), deferArgs(d), uint32(d.siz), uint32(d.siz))
c:/go/src/runtime/panic.go:24 (0x427740)
panicdivide: panic(divideError)
c:/go/src/runtime/signal_windows.go:166 (0x43a31f)
sigpanic: panicdivide()
F:/MyProject/Go/src/panictest/main.go:10 (0x401073)
test_panic: i := 5 / n
F:/MyProject/Go/src/panictest/main.go:16 (0x40119c)
main: test_panic()
c:/go/src/runtime/proc.go:111 (0x42b78e)
main: main_main()
c:/go/src/runtime/asm_amd64.s:1721 (0x456821)
goexit: BYTE $0x90 // NOP
至此獲取錯誤並且儲存的功能已經實現。
最後注意,如果是啟動的多goroutine,需要在每個goroutine執行函式的時候,寫上defer PanicHandler()
否則的話是捕獲不到其他goroutine當中的painc資訊的。