Write it in front.
Recently, in the development of the Go Project, it was found that the go language itself error
does not panic
display detailed debugging information like a trigger. For complex systems, this will give our developers some time to navigate to the error. So our basic go itself error
encapsulates a tool pack that can quickly locate the error. Let's take a look at how this toolkit is implemented.
Design ideas
- The toolkit provides
Err
and Errf
two perfect to register errors, their usage is similar to fmt.Print
and fmt.Printf
how to use, and in the definition of parameters to add the Innererror parameter to implement the wrong pass, its value can be nil
.
- The StackTrace function is available externally to allow users to obtain stack information generated by the error.
- Configure the display of error messages in a setconfig way, such as no need to print stack information in a production environment. The configuration of the response can be turned off.
Implementation ideas
The toolkit is primarily about handling stack information, that is, how to locate error
the resulting location, and by looking at the official documentation, we find that the runtime
stack information for the Callers
CallersFrames
current function call can be obtained through the and functions in the package. And you can get the error location by using the skip parameter and the custom filter condition. The specific implementation process is as follows:
Implementation of 2 functions provided externally
type Error struct { err error msg string fullMsg string stackTrace}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}
Implementation of Stack information
type stackTrace struct {//stack info data string callers []uintptr}func (Err *error) Getstacktrac E () string {if strings. Trimspace (err.data) = = "" {return Err.genstacktrace (5)} return Err.data}func (Err *error) StackTrace () stri ng {return Err.data}func (err *error) genstacktrace (skip int) string {if Config.isprintstack = = 1 {var buf Fer bytes. Buffer buffer. WriteString ("stacktrace:\n") var St [64]uintptr N: = 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 ""}
Error message displays the implementation of the configuration
const ( //print stack info PRINTSTACK = 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) }}
Test
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()}
The error message is as follows
End
The toolkit is just a encapsulation of error information and stack information, and there are many deficiencies. If you have a good opinion. Welcome advice.