github.com/songzhibin97/gkit@v1.2.13/errors/error.go (about) 1 package errors 2 3 import ( 4 "errors" 5 "fmt" 6 7 "github.com/golang/protobuf/proto" 8 httputil "github.com/songzhibin97/gkit/errors/internal" 9 "google.golang.org/genproto/googleapis/rpc/errdetails" 10 "google.golang.org/grpc/status" 11 ) 12 13 //go:generate protoc -I. --go_out=paths=source_relative:. errors.proto 14 15 const ( 16 // UnknownCode is unknown code for error info. 17 UnknownCode = 500 18 // UnknownReason is unknown reason for error info. 19 UnknownReason = "" 20 ) 21 22 var ErrDetails = errors.New("no error details for status with code OK") 23 24 // Error 实现Error接口 25 func (x *Error) Error() string { 26 return fmt.Sprintf("error: code = %d reason = %s message = %s details = %v", x.Code, x.Reason, x.Message, x.Metadata) 27 } 28 29 // StatusCode HTTP code 30 func (x *Error) StatusCode() int { 31 return int(x.Code) 32 } 33 34 // GRPCStatus 返回grpc status 35 func (x *Error) GRPCStatus() *status.Status { 36 s, _ := status.New(httputil.GRPCCodeFromStatus(x.StatusCode()), x.Message). 37 WithDetails(&errdetails.ErrorInfo{ 38 Reason: x.Reason, 39 Metadata: x.Metadata, 40 }) 41 return s 42 } 43 44 // Is 跟 target Error 比较 判断是否相等 45 func (x *Error) Is(target error) bool { 46 if err, ok := target.(*Error); !ok { 47 return false 48 } else { 49 return x.Code == err.Code 50 } 51 } 52 53 // AddMetadata 增加metadata 54 func (x *Error) AddMetadata(mp map[string]string) *Error { 55 err := proto.Clone(x).(*Error) 56 err.Metadata = mp 57 return err 58 } 59 60 // New 实例化 Error 对象 61 func New(code int, reason, message string) *Error { 62 return &Error{ 63 Code: int32(code), 64 Reason: reason, 65 Message: message, 66 } 67 } 68 69 func Errorf(code int, reason, format string, a ...interface{}) *Error { 70 return New(code, reason, fmt.Sprintf(format, a...)) 71 } 72 73 func FromError(err error) *Error { 74 if err == nil { 75 return nil 76 } 77 if se := new(Error); errors.As(err, &se) { 78 return se 79 } 80 gs, ok := status.FromError(err) 81 if ok { 82 for _, detail := range gs.Details() { 83 switch d := detail.(type) { 84 case *errdetails.ErrorInfo: 85 return New( 86 httputil.StatusFromGRPCCode(gs.Code()), 87 d.Reason, 88 gs.Message(), 89 ).AddMetadata(d.Metadata) 90 } 91 } 92 } 93 return New(UnknownCode, UnknownReason, err.Error()) 94 } 95 96 // Code 返回err指定的错误码 97 func Code(err error) int { 98 if err == nil { 99 return 0 100 } 101 if se := FromError(err); err != nil { 102 return int(se.Code) 103 } 104 return UnknownCode 105 } 106 107 // Reason 返回err的reason 108 func Reason(err error) string { 109 if se := FromError(err); err != nil { 110 return se.Reason 111 } 112 return UnknownReason 113 } 114 115 func Is(err, target error) bool { return errors.Is(err, target) } 116 117 func As(err error, target interface{}) bool { return errors.As(err, target) } 118 119 func Unwrap(err error) error { return errors.Unwrap(err) }