gopkg.in/hedzr/errors.v3@v3.3.1/errors.go (about) 1 package errors 2 3 import ( 4 "errors" 5 "fmt" 6 ) 7 8 // New returns an error with the supplied message. 9 // New also records the Stack trace at the point where it was called. 10 // 11 // New supports two kind of args: an Opt option or a message format 12 // with variadic args. 13 // 14 // Sample 1: 15 // 16 // var err = errors.New("message here: %s", "hello") 17 // 18 // Sample 2: 19 // 20 // var err = errors.New(errors.WithErrors(errs...)) 21 // var err = errors.New(errors.WithStack(cause)) 22 // 23 // Sample 3: 24 // 25 // var err = errors.New().WithErrors(errs...) 26 func New(args ...interface{}) Error { //nolint:revive 27 if len(args) > 0 { 28 s := &builder{skip: 1} 29 30 if message, ok := args[0].(string); ok { 31 return s.WithSkip(2).WithMessage(message, args[1:]...).Build() 32 } 33 34 for _, opt := range args { 35 if o, ok := opt.(Opt); ok { 36 o(s) 37 } 38 } 39 return s.Build() 40 } 41 42 return &WithStackInfo{Stack: callers(1)} 43 } 44 45 // NewLite returns a simple message error object via stdlib (errors.New). 46 // 47 // Sample: 48 // 49 // var err1 = errors.New("message") // simple message 50 // var err1 = errors.New(errors.WithStack(cause)) // return Error object with Opt 51 // 52 // If no send any args as parameters, Code `UnsupportedOperation` returned. 53 func NewLite(args ...interface{}) error { //nolint:revive 54 if len(args) > 0 { 55 if message, ok := args[0].(string); ok { 56 if len(args) > 1 { 57 message = fmt.Sprintf(message, args[1:]...) 58 } 59 return errors.New(message) 60 } 61 62 s := &builder{skip: 1} 63 for _, opt := range args { 64 if o, ok := opt.(Opt); ok { 65 o(s) 66 } 67 } 68 return s.Build() 69 } 70 return UnsupportedOperation // errors.ErrUnsupported 71 } 72 73 // Opt _ 74 type Opt func(s *builder) 75 76 // WithErrors attach child errors into an error container. 77 // For a container which has IsEmpty() interface, it would not be 78 // attached if it is empty (i.e. no errors). 79 // For a nil error object, it will be ignored. 80 // 81 // Sample: 82 // 83 // err := errors.New(errors.WithErrors(errs...)) 84 func WithErrors(errs ...error) Opt { 85 return func(s *builder) { 86 s.WithErrors(errs...) 87 } 88 } 89 90 // Skip sets how many frames will be ignored while we are extracting 91 // the stacktrace info. 92 // Skip starts a builder with fluent API style, so you could continue 93 // build the error what you want: 94 // 95 // err := errors.Skip(1).Message("hello %v", "you").Build() 96 func Skip(skip int) Builder { 97 return &builder{skip: skip} 98 } 99 100 // Message formats a message and starts a builder to create the final 101 // error object. 102 // 103 // err := errors.Message("hello %v", "you").Attach(causer).Build() 104 func Message(message string, args ...interface{}) Builder { //nolint:revive 105 return NewBuilder().WithMessage(message, args...) 106 } 107 108 // NewBuilder starts a new error builder. 109 // 110 // Typically, you could make an error with fluent calls: 111 // 112 // err = errors.NewBuilder(). 113 // WithCode(Internal). 114 // WithErrors(io.EOF). 115 // WithErrors(io.ErrShortWrite). 116 // Build() 117 // t.Logf("failed: %+v", err) 118 func NewBuilder() Builder { 119 return &builder{skip: 1} 120 } 121 122 // Builder provides a fluent calling interface to make error 123 // building easy. 124 type Builder interface { 125 // WithSkip specifies a special number of stack frames that will 126 // be ignored. 127 WithSkip(skip int) Builder 128 // WithErrors attaches the given errs as inner errors. 129 // For a container which has IsEmpty() interface, it would not 130 // be attached if it is empty (i.e. no errors). 131 // For a nil error object, it will be ignored. 132 WithErrors(errs ...error) Builder 133 // WithMessage formats the error message 134 WithMessage(message string, args ...interface{}) Builder //nolint:revive 135 // WithCode specifies an error code. 136 WithCode(code Code) Builder 137 138 // Build builds the final error object (with Buildable interface 139 // bound) 140 Build() Error 141 142 // BREAK - Use WithErrors() for instead 143 // Attach inner errors for backward compatibility to v2 144 // Attach(errs ...error) 145 } 146 147 type builder struct { 148 skip int 149 causes2 causes2 150 sites []interface{} //nolint:revive 151 taggedSites TaggedData 152 } 153 154 // WithSkip specifies a special number of stack frames that will 155 // be ignored. 156 func (s *builder) WithSkip(skip int) Builder { 157 s.skip = skip 158 return s 159 } 160 161 // WithCode specifies an error code. 162 func (s *builder) WithCode(code Code) Builder { 163 s.causes2.Code = code 164 return s 165 } 166 167 // // Attach attaches the given errs as inner errors. 168 // // For backward compatibility to v2 169 // func (s *builder) Attach(errs ...error) Buildable { 170 // return s.WithErrors(errs...).Build() 171 // } 172 173 // WithMessage formats the error message 174 func (s *builder) WithMessage(message string, args ...interface{}) Builder { //nolint:revive 175 if len(args) > 0 { 176 message = fmt.Sprintf(message, args...) //nolint:revive 177 } 178 s.causes2.msg = message 179 return s 180 } 181 182 // WithErrors attaches the given errs as inner errors. 183 // For a container which has IsEmpty() interface, it would not 184 // be attached if it is empty (i.e. no errors). 185 // For a nil error object, it will be ignored. 186 func (s *builder) WithErrors(errs ...error) Builder { 187 _ = s.causes2.WithErrors(errs...) 188 return s 189 } 190 191 // WithData appends errs if the general object is a error object. 192 // It can be used in defer-recover block typically. For example: 193 // 194 // defer func() { 195 // if e := recover(); e != nil { 196 // err = errors.New("[recovered] copyTo unsatisfied ([%v] %v -> [%v] %v), causes: %v", 197 // c.indirectType(from.Type()), from, c.indirectType(to.Type()), to, e). 198 // WithData(e) 199 // n := log.CalcStackFrames(1) // skip defer-recover frame at first 200 // log.Skip(n).Errorf("%v", err) // skip go-lib frames and defer-recover frame, back to the point throwing panic 201 // } 202 // }() 203 func (s *builder) WithData(errs ...interface{}) Builder { //nolint:revive 204 s.sites = append(s.sites, errs...) 205 return s 206 } 207 208 // WithTaggedData appends user data with tag into internal container. 209 // These data can be retrieved by 210 func (s *builder) WithTaggedData(siteScenes TaggedData) Builder { 211 if s.taggedSites == nil { 212 s.taggedSites = make(TaggedData) 213 } 214 for k, v := range siteScenes { 215 s.taggedSites[k] = v 216 } 217 return s 218 } 219 220 // WithCause sets the underlying error manually if necessary. 221 func (s *builder) WithCause(cause error) Builder { 222 _ = s.causes2.WithErrors(cause) 223 return s 224 } 225 226 // Build builds the final error object (with *WithStackInfo type wrapped) 227 func (s *builder) Build() Error { 228 w := &WithStackInfo{ 229 causes2: s.causes2, 230 Stack: callers(s.skip), 231 } 232 return w 233 }