funcmain() { if err := bindUser(); err != nil { // %s: Returns the user-safe error string mapped to the error code or the error message if none is specified. fmt.Println("====================> %s <====================") fmt.Printf("%s\n\n", err)
// %v: Alias for %s. fmt.Println("====================> %v <====================") fmt.Printf("%v\n\n", err)
// %+v: Output full error stack details, useful for debugging. fmt.Println("====================> %+v <====================") fmt.Printf("%+v\n\n", err)
// %#-v: Output caller details, useful for troubleshooting with JSON formatted output. fmt.Println("====================> %#-v <====================") fmt.Printf("%#-v\n\n", err)
// %#+v: Output full error stack details, useful for debugging with JSON formatted output. fmt.Println("====================> %#+v <====================") fmt.Printf("%#+v\n\n", err)
// do some business process based on the error type if errors.IsCode(err, code.ErrEncodingFailed) { fmt.Println("this is a ErrEncodingFailed error") }
if errors.IsCode(err, code.ErrDatabase) { fmt.Println("this is a ErrDatabase error") }
// we can also find the cause error fmt.Println(errors.Cause(err)) } }
funcbindUser()error { if err := getUser(); err != nil { // Step3: Wrap the error with a new error message and a new error code if needed. return errors.WrapC(err, code.ErrEncodingFailed, "encoding user 'Lingfei Kong' failed.") }
returnnil }
funcgetUser()error { if err := queryDatabase(); err != nil { // Step2: Wrap the error with a new error message. return errors.Wrap(err, "get user failed.") }
returnnil }
funcqueryDatabase()error { // Step1. Create error with specified error code. return errors.WithCode(code.ErrDatabase, "user 'Lingfei Kong' not found.") }
// codes contains a map of error codes to metadata. var codes = map[int]Coder{} var codeMux = &sync.Mutex{}
// Register register a user define error code. // It will overrid the exist code. funcRegister(coder Coder) { if coder.Code() == 0 { panic("code `0` is reserved by `github.com/marmotedu/errors` as unknownCode error code") }
codeMux.Lock() defer codeMux.Unlock()
codes[coder.Code()] = coder }
// MustRegister register a user define error code. // It will panic when the same Code already exist. funcMustRegister(coder Coder) { if coder.Code() == 0 { panic("code '0' is reserved by 'github.com/marmotedu/errors' as ErrUnknown error code") }
codeMux.Lock() defer codeMux.Unlock()
if _, ok := codes[coder.Code()]; ok { panic(fmt.Sprintf("code: %d already exist", coder.Code())) }
codes[coder.Code()] = coder }
1 2 3 4 5 6 7 8 9 10 11 12 13 14
// Coder defines an interface for an error code detail information. type Coder interface { // HTTP status that should be used for the associated error code. HTTPStatus() int
// Is reports whether any error in err's chain matches target. // // The chain consists of err itself followed by the sequence of errors obtained by // repeatedly calling Unwrap. // // An error is considered to match a target if it is equal to that target or if // it implements a method Is(error) bool such that Is(target) returns true. funcIs(err, target error)bool { return stderrors.Is(err, target) }
// As finds the first error in err's chain that matches target, and if so, sets // target to that error value and returns true. // // The chain consists of err itself followed by the sequence of errors obtained by // repeatedly calling Unwrap. // // An error matches target if the error's concrete value is assignable to the value // pointed to by target, or if the error has a method As(interface{}) bool such that // As(target) returns true. In the latter case, the As method is responsible for // setting target. // // As will panic if target is not a non-nil pointer to either a type that implements // error, or to any interface type. As returns false if err is nil. funcAs(err error, target interface{})bool { return stderrors.As(err, target) }
// Unwrap returns the result of calling the Unwrap method on err, if err's // type contains an Unwrap method returning error. // Otherwise, Unwrap returns nil. funcUnwrap(err error)error { return stderrors.Unwrap(err) }
IsCode
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
// IsCode reports whether any error in err's chain contains the given error code. funcIsCode(err error, code int)bool { if v, ok := err.(*withCode); ok { if v.code == code { returntrue }
if v.cause != nil { return IsCode(v.cause, code) }
returnfalse }
returnfalse }
ParseCoder
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
// ParseCoder parse any error into *withCode. // nil error will return nil direct. // None withStack error will be parsed as ErrUnknown. funcParseCoder(err error) Coder { if err == nil { returnnil }
if v, ok := err.(*withCode); ok { if coder, ok := codes[v.code]; ok { return coder } }
// Response defines project response format which in marmotedu organization. type Response struct { Code errors.Code `json:"code,omitempty"` Message string`json:"message,omitempty"` Reference string`json:"reference,omitempty"` Data interface{} `json:"data,omitempty"` }
// WriteResponse used to write an error and JSON data into response. funcWriteResponse(c *gin.Context, err error, data interface{}) { if err != nil { coder := errors.ParseCoder(err)
funcGetUser(c *gin.Context) { log.Info("get user function called.", "X-Request-Id", requestid.Get(c)) // Get the user by the `username` from the database. user, err := store.Client().Users().Get(c.Param("username"), metav1.GetOptions{}) if err != nil { core.WriteResponse(c, code.ErrUserNotFound.Error(), nil) return }