This is a creation in Article, where the information may have evolved or changed.
In order to facilitate the sharing, specifically to copy the blog here =
It is hard to tolerate the fact that the error log is printed everywhere in the code, and I have figured out an elegant way of handling errors. Specially sorted out to share.
Source Address: Https://github.com/mozhata/merr
Demand
- I want to know where the original error occurred and what the corresponding function call stack was.
- I want to add some additional information to the error returned by a function, but I want to keep the original error message.
- You may also need a status code to identify a class of errors
- I think... Well, I think too much.
That's probably the effect of printing.
E500: err: new errraw err: origin errcall stack: main.warpper practice/go/example/main.go:18main.main practice/go/example/main.go:12runtime.main runtime/proc.go:183runtime.goexit runtime/asm_amd64.s:2086
(print function included)
func logMerr(err error) { e := merr.WrapErr(err) fmt.Printf("E%d: err: %s\nraw err: %s\ncall stack: %s\n", e.StatusCode, e.Error(), e.RawErr(), e.CallStack(), )}
Key code
The first thing to do is to get a wrong class
type MErr struct { Message string // 保存自定义的错误信息 StatusCode int // 错误状态码 rawErr error // 保存原始错误信息 stackPC []uintptr // 保存函数调用栈指针}
And then there are some key ways
func (e *MErr) Error() string { return e.Message}// RawErr the origin errfunc (e MErr) RawErr() error { return e.rawErr}// CallStack get function call stackfunc (e MErr) CallStack() string { frames := runtime.CallersFrames(e.stackPC) var ( f runtime.Frame more bool result string index int ) for { f, more = frames.Next() if index = strings.Index(f.File, "src"); index != -1 { // trim GOPATH or GOROOT prifix f.File = string(f.File[index+4:]) } result = fmt.Sprintf("%s%s\n\t%s:%d\n", result, f.Function, f.File, f.Line) if !more { break } } return result}
CallStack()
The method is used to convert the function call stack pointer to a string
There is a missing package method
Maintain Rawerr and update Message if Fmtandargs is not empty//update StatusCode to code if code was not 0//notice:th E returned value is used as error, so, should not return Nilfunc Wraperr (err error, code int, Fmtandargs ... interface{}) * MERR {msg: = Fmterrmsg (Fmtandargs ...) If Err = = Nil {err = errors. New (MSG)} If E, OK: = Err. (*merr); OK {if msg! = "" {e.message = msg} if code! = 0 {e.statuscode = code } return e} pcs: = make ([]uintptr, +)//Skip the first 3 invocations count: = Runtime. Callers (3, pcs) e: = &merr{statuscode:code, message:msg, Rawerr:err, STACKPC : Pcs[:count],} if e.message = = "" {E.message = Err. Error ()} return e}//fmterrmsg used to format error Messagefunc fmterrmsg (msgs ... interface{}) string {If Len (m SGS) > 1 {return FMT. Sprintf (Msgs[0]. ( String), Msgs[1:] ...) } If Len (msGS) = = 1 {if V, OK: = Msgs[0]. ( string); OK {return V} if V, OK: = Msgs[0]. (error); OK {return V.error ()}} ' return '}
It can be seen that this method of error handling is mainly fmtErrMsg
wrapErr
CallStack
implemented by these three parts
Next, encapsulate a few handy functions
// WrapErr equal to InternalErr(err)// notice: be careful, the returned value is *MErr, not errorfunc WrapErr(err error, fmtAndArgs ...interface{}) *MErr { return wrapErr(err, http.StatusInternalServerError, fmtAndArgs...)}// WrapErrWithCode if code is not 0, update StatusCode to code,// if fmtAndArgs is not nil, update the Message according to fmtAndArgs// notice: be careful, the returned value is *MErr, not errorfunc WrapErrWithCode(err error, code int, fmtAndArgs ...interface{}) *MErr { return wrapErr(err, code, fmtAndArgs...)}// NotFoundErr use http.StatusNotFound as StatusCode to express not found err// if fmtAndArgs is not nil, update the Message according to fmtAndArgsfunc NotFoundErr(err error, fmtAndArgs ...interface{}) error { return wrapErr(err, http.StatusNotFound, fmtAndArgs...)}
This is basically the whole code. There is not much to explain, the basic look at the code is clear. For more detailed usage, you can view the test file
This is the source address