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  }