github.com/sandwich-go/boost@v1.3.29/xerror/xerror.go (about) 1 package xerror 2 3 import ( 4 "os" 5 ) 6 7 var IsErrorWithStack = false 8 9 // Error struct 10 type Error struct { 11 err error // 底层错误 12 text string // 错误信息 13 code int32 // 错误码 14 logic bool // 是否为逻辑层异常,主要为sandwich 的queue模式服务 15 callStack stack // 堆栈信息,内部数据自动生成 16 skip int // error skip 17 setTimeout bool // 是否设置超时, 如果明确设置超时状态,则不再根据底层错误判断 18 timeout bool // 是否为超时错误 19 } 20 21 // Logic 是否为逻辑层错误 22 func (cc *Error) Logic() bool { return cc.logic } 23 24 // Timeout 是否为超时错误 os.IsTimeout 25 func (cc *Error) Timeout() bool { 26 if !cc.setTimeout && cc.err != nil { 27 return cc.timeout || os.IsTimeout(cc.err) 28 } 29 return cc.timeout 30 } 31 32 // SetTimeout 设定为超时 33 func (cc *Error) SetTimeout() *Error { 34 cc.setTimeout = true 35 cc.timeout = true 36 return cc 37 } 38 39 // UnsetTimeout 设定为非超时 40 func (cc *Error) UnsetTimeout() *Error { 41 cc.setTimeout = true 42 cc.timeout = false 43 return cc 44 } 45 46 // WithStack 设置堆栈 47 func (cc *Error) WithStack(skip ...int) *Error { 48 cc.callStack = callers(skip...) 49 return cc 50 } 51 52 // SetLogic 设定为逻辑层错误 53 func (cc *Error) SetLogic() *Error { 54 cc.logic = true 55 return cc 56 } 57 58 // UnsetLogic 设定为非逻辑层错误 59 func (cc *Error) UnsetLogic() *Error { 60 cc.logic = false 61 return cc 62 } 63 64 // Unwrap 兼容 errors.Unwrap 65 func (cc *Error) Unwrap() error { return cc.err } 66 67 // New 新建 Error 对象 68 func New(opts ...ErrorOption) *Error { 69 e := &Error{callStack: nil} 70 for _, opt := range opts { 71 opt(e) 72 } 73 if IsErrorWithStack && e.callStack == nil { 74 e.callStack = callers(e.skip) 75 } 76 return e 77 } 78 79 type ErrorOption func(cc *Error) 80 81 func WithErr(v error) ErrorOption { return func(cc *Error) { cc.err = v } } 82 func WithText(v string) ErrorOption { return func(cc *Error) { cc.text = v } } 83 func WithCode(v int32) ErrorOption { return func(cc *Error) { cc.code = v } } 84 func WithLogic(v bool) ErrorOption { return func(cc *Error) { cc.logic = v } } 85 func WithSkip(v int) ErrorOption { return func(cc *Error) { cc.skip = v } } 86 func WithTimeout(v bool) ErrorOption { 87 return func(cc *Error) { 88 cc.setTimeout = true 89 cc.timeout = v 90 } 91 } 92 93 // WithStack option func for stack 94 func WithStack() ErrorOption { 95 return func(cc *Error) { 96 if cc.callStack != nil { 97 return 98 } 99 cc.callStack = callers(1) 100 } 101 } 102 103 func containsCode(err error, code int32) bool { 104 for { 105 if err0, ok := err.(APICode); ok && err0.Code() == code { 106 return true 107 } 108 switch x := err.(type) { 109 case interface{ Unwrap() error }: 110 if err = x.Unwrap(); err == nil { 111 return false 112 } 113 case interface{ Unwrap() []error }: 114 for _, err0 := range x.Unwrap() { 115 if err0 == nil { 116 continue 117 } 118 if containsCode(err0, code) { 119 return true 120 } 121 } 122 return false 123 default: 124 return false 125 } 126 } 127 } 128 129 // ContainsCode 是否有某个 code 130 func ContainsCode(err error, code int32) bool { 131 if err == nil { 132 return false 133 } 134 return containsCode(err, code) 135 }