基於golang實現的error工具包
來源:互聯網
上載者:User
### 寫在前面的話最近在開發Go項目,發現Go語言本身存在的`error`並沒有像觸發`panic`時顯示詳細的調試資訊。對於複雜的系統而言,這會讓我們開發人員需要一定的時間才能定位到錯誤。所以我們基本Go本身的`error`封裝了一個可以快速定位錯誤工具包。下面讓我們來看看這個工具包是怎麼實現的。### 設計思想1. 工具包提供`Err`和`Errf`兩個完善來登記錯誤,其用法分別類似於`fmt.Print`和`fmt.Printf`的使用方式,在參數的定義中添加了innerError參數來實現錯誤的傳遞,其值可為`nil`.2. 對外提供StackTrace函數,方便使用者擷取錯誤產生的堆棧資訊。3. 通過SetConfig方式實現對錯誤資訊顯示的配置,如在生產環境不需要列印堆棧資訊。通過響應的配置即可關閉。### 實現思路工具包中主要是對堆棧資訊的處理,就是如何才能定位到`error`的產生位置,通過查看官方文檔,我們發現通過`runtime`包中的`Callers`和`CallersFrames`函數可以擷取當前函數調用的堆棧資訊。並且通過Skip參數和自訂過濾條件即可拿到error的產生位置。具體的實現過程如下:#### 對外提供的2個函數的實現```type Error struct {err errormsg stringfullMsg stringstackTrace}func Errf(err error, format string, args ...interface{}) *Error {e := &Error{err: err,msg: fmt.Sprintf(format, args),}e.fullMsg = e.genFullMsg()return e}func Err(err error, args ...interface{}) *Error {e := &Error{err: err,msg: fmt.Sprint(args),}e.fullMsg = e.genFullMsg()return e}```#### 堆棧資訊的實現```type stackTrace struct {// stack infodata stringcallers []uintptr}func (err *Error) getStackTrace() string {if strings.TrimSpace(err.data) == "" {return err.genStackTrace(5)}return err.data}func (err *Error) StackTrace() string {return err.data}func (err *Error) genStackTrace(skip int) string {if config.isPrintStack == 1 {var buffer bytes.Bufferbuffer.WriteString("StackTrace:\n")var st [64]uintptrn := runtime.Callers(skip, st[:])err.callers = st[:n]frames := runtime.CallersFrames(err.callers)for {frame, ok := frames.Next()if !ok {break}if !strings.Contains(frame.File, "runtime/") {buffer.WriteString(fmt.Sprintf("%s\n\t%s:%d\n", frame.Func.Name(), frame.File, frame.Line))}}err.data = buffer.String()return err.data}return ""}```#### 錯誤資訊顯示配置的實現```const (//print stack infoPRINTSTACK = 1)// global error config objectvar config *errConfig = &errConfig{}// error configtype errConfig struct {isPrintStack uint32}//set error config infofunc SetConfig(conf byte) {if (conf & PRINTSTACK) != 0 {atomic.CompareAndSwapUint32(&config.isPrintStack, 0, 1)}}```#### 測試```func init() {errors.SetConfig(errors.PRINTSTACK)}func main() {a := func() {err := errors.Err(nil, "this is an inner error")fmt.Print(err.StackTrace())b := errors.Errf(err, "this is a %s message", "test").Error()fmt.Println(b)}a()}```錯誤資訊如下所示![1776580357-5b8b8ebf0671f_articlex.png](https://static.studygolang.com/180903/1199435976b9d24dee525f53cf7af77b.png)### 結尾該工具包只是對error資訊和堆棧資訊的封裝,還存在含多不足的地方。如果各位有好的意見。歡迎指點。123 次點擊