golang 打印error的堆棧信息操作
眾所周知,目前的golang error隻關註Error()信息,而不關註它的堆棧路徑,對錯誤的定位大多數通過
log.SetFlags(log.Llongfile| log.LstdFlags) log.Println(e)
一旦代碼分層,為瞭定位錯誤,可能出現每一個層次的同一個error,都得log好幾次,比如:
func DB()error{ return errors.New("time out") } func Dao()error{ if er:= DB();er!=nil{ log.Println(er) return error } return nil } func Service()error{ if er:= Dao();er!=nil{ log.Println(er) return error } return nil } func Control()error{ if er:= Service();er!=nil{ log.Println(er) return error } return nil }
如何一次性拋出錯誤,把該錯誤的堆棧全部都拿住呢
以模擬一次請求-分發-服務-數據庫操作為例:
package main import ( "errors" "fmt" "github.com/fwhezfwhez/errorx" ) func main() { if e := Control(); e != nil { e.(errorx.Error).PrintStackTrace() // log.Println(e.(errorx.Error).StackTrace()) } else { Reply() } } // assume an engine to connect mysql func DB() error { return errors.New("connect to mysql time out") } // handle database operation func Dao() error { if er := DB(); er != nil { return errorx.New(er) } return nil } // handle logic service func Service() error { if er := Dao(); er != nil { return errorx.Wrap(er) } return nil } // handle request distribute from main func Control() error { if er := Service(); er != nil { return errorx.ReGen(er, errors.New("inner service error,please call admin for help")) } return nil } // reply a the request func Reply(){ fmt.Println("handle success") }
執行結果:
StackTrace | CausedBy
G:/go_workspace/GOPATH/src/errorX/example/main.go: 26 | connect to mysql time out
G:/go_workspace/GOPATH/src/errorX/example/main.go: 34 | connect to mysql time out
G:/go_workspace/GOPATH/src/errorX/example/main.go: 42 | inner service error,please call admin for help
補充:golang 異常退出堆棧捕獲
利用golang自帶包 runtime/debug 異常時打印
DebugInfo.go
package main import ( "fmt" "os" "runtime/debug" "time" ) func TryE() { errs := recover() if errs == nil { return } 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() f.WriteString(fmt.Sprintf("%v\r\n", errs)) //輸出panic信息 f.WriteString("========\r\n") f.WriteString(string(debug.Stack())) //輸出堆棧信息 }
測試異常捕獲 main.go
package main import ( "fmt" "time" ) func main() { defer TryE() fmt.Println(time.Now()) panic(-2) fmt.Println("panic restore now, continue.") }
查看堆棧可以定位main 裡第11行拋出異常-2.
以上為個人經驗,希望能給大傢一個參考,也希望大傢多多支持WalkonNet。如有錯誤或未考慮完全的地方,望不吝賜教。
推薦閱讀:
- Golang中panic的異常處理
- Golang之defer 延遲調用操作
- GoLand安裝與環境配置的完整步驟
- 淺析golang開發Error的使用詳解
- golang coroutine 的等待與死鎖用法