github.com/sunvim/utils@v0.1.0/errors/errors.go (about) 1 // from https://github.com/pkg/errors 2 // Package errors provides simple error handling primitives. 3 // 4 // The traditional error handling idiom in Go is roughly akin to 5 // 6 // if err != nil { 7 // return err 8 // } 9 // 10 // which when applied recursively up the call stack results in error reports 11 // without context or debugging information. The errors package allows 12 // programmers to add context to the failure path in their code in a way 13 // that does not destroy the original value of the error. 14 // 15 // Adding context to an error 16 // 17 // The errors.Wrap function returns a new error that adds context to the 18 // original error by recording a stack trace at the point Wrap is called, 19 // together with the supplied message. For example 20 // 21 // _, err := ioutil.ReadAll(r) 22 // if err != nil { 23 // return errors.Wrap(err, "read failed") 24 // } 25 // 26 // If additional control is required, the errors.WithStack and 27 // errors.WithMessage functions destructure errors.Wrap into its component 28 // operations: annotating an error with a stack trace and with a message, 29 // respectively. 30 // 31 // Retrieving the cause of an error 32 // 33 // Using errors.Wrap constructs a stack of errors, adding context to the 34 // preceding error. Depending on the nature of the error it may be necessary 35 // to reverse the operation of errors.Wrap to retrieve the original error 36 // for inspection. Any error value which implements this interface 37 // 38 // type causer interface { 39 // Cause() error 40 // } 41 // 42 // can be inspected by errors.Cause. errors.Cause will recursively retrieve 43 // the topmost error that does not implement causer, which is assumed to be 44 // the original cause. For example: 45 // 46 // switch err := errors.Cause(err).(type) { 47 // case *MyError: 48 // // handle specifically 49 // default: 50 // // unknown error 51 // } 52 // 53 // Although the causer interface is not exported by this package, it is 54 // considered a part of its stable public interface. 55 // 56 // Formatted printing of errors 57 // 58 // All error values returned from this package implement fmt.Formatter and can 59 // be formatted by the fmt package. The following verbs are supported: 60 // 61 // %s print the error. If the error has a Cause it will be 62 // printed recursively. 63 // %v see %s 64 // %+v extended format. Each Frame of the error's StackTrace will 65 // be printed in detail. 66 // 67 // Retrieving the stack trace of an error or wrapper 68 // 69 // New, Errorf, Wrap, and Wrapf record a stack trace at the point they are 70 // invoked. This information can be retrieved with the following interface: 71 // 72 // type stackTracer interface { 73 // StackTrace() errors.StackTrace 74 // } 75 // 76 // The returned errors.StackTrace type is defined as 77 // 78 // type StackTrace []Frame 79 // 80 // The Frame type represents a call site in the stack trace. Frame supports 81 // the fmt.Formatter interface that can be used for printing information about 82 // the stack trace of this error. For example: 83 // 84 // if err, ok := err.(stackTracer); ok { 85 // for _, f := range err.StackTrace() { 86 // fmt.Printf("%+s:%d", f) 87 // } 88 // } 89 // 90 // Although the stackTracer interface is not exported by this package, it is 91 // considered a part of its stable public interface. 92 // 93 // See the documentation for Frame.Format for more details. 94 package errors 95 96 import ( 97 "fmt" 98 "io" 99 ) 100 101 // New returns an error with the supplied message. 102 // New also records the stack trace at the point it was called. 103 func New(message string) error { 104 return &fundamental{ 105 msg: message, 106 stack: callers(), 107 } 108 } 109 110 // Errorf formats according to a format specifier and returns the string 111 // as a value that satisfies error. 112 // Errorf also records the stack trace at the point it was called. 113 func Errorf(format string, args ...interface{}) error { 114 return &fundamental{ 115 msg: fmt.Sprintf(format, args...), 116 stack: callers(), 117 } 118 } 119 120 // fundamental is an error that has a message and a stack, but no caller. 121 type fundamental struct { 122 msg string 123 *stack 124 } 125 126 func (f *fundamental) Error() string { return f.msg } 127 128 func (f *fundamental) Format(s fmt.State, verb rune) { 129 switch verb { 130 case 'v': 131 if s.Flag('+') { 132 io.WriteString(s, f.msg) 133 f.stack.Format(s, verb) 134 return 135 } 136 fallthrough 137 case 's': 138 io.WriteString(s, f.msg) 139 case 'q': 140 fmt.Fprintf(s, "%q", f.msg) 141 } 142 } 143 144 // WithStack annotates err with a stack trace at the point WithStack was called. 145 // If err is nil, WithStack returns nil. 146 func WithStack(err error) error { 147 if err == nil { 148 return nil 149 } 150 return &withStack{ 151 err, 152 callers(), 153 } 154 } 155 156 type withStack struct { 157 error 158 *stack 159 } 160 161 func (w *withStack) Cause() error { return w.error } 162 163 func (w *withStack) Format(s fmt.State, verb rune) { 164 switch verb { 165 case 'v': 166 if s.Flag('+') { 167 fmt.Fprintf(s, "%+v", w.Cause()) 168 w.stack.Format(s, verb) 169 return 170 } 171 fallthrough 172 case 's': 173 io.WriteString(s, w.Error()) 174 case 'q': 175 fmt.Fprintf(s, "%q", w.Error()) 176 } 177 } 178 179 // Wrap returns an error annotating err with a stack trace 180 // at the point Wrap is called, and the supplied message. 181 // If err is nil, Wrap returns nil. 182 func Wrap(err error, message string) error { 183 if err == nil { 184 return nil 185 } 186 err = &withMessage{ 187 cause: err, 188 msg: message, 189 } 190 return &withStack{ 191 err, 192 callers(), 193 } 194 } 195 196 // Wrapf returns an error annotating err with a stack trace 197 // at the point Wrapf is called, and the format specifier. 198 // If err is nil, Wrapf returns nil. 199 func Wrapf(err error, format string, args ...interface{}) error { 200 if err == nil { 201 return nil 202 } 203 err = &withMessage{ 204 cause: err, 205 msg: fmt.Sprintf(format, args...), 206 } 207 return &withStack{ 208 err, 209 callers(), 210 } 211 } 212 213 // WithMessage annotates err with a new message. 214 // If err is nil, WithMessage returns nil. 215 func WithMessage(err error, message string) error { 216 if err == nil { 217 return nil 218 } 219 return &withMessage{ 220 cause: err, 221 msg: message, 222 } 223 } 224 225 // WithMessagef annotates err with the format specifier. 226 // If err is nil, WithMessagef returns nil. 227 func WithMessagef(err error, format string, args ...interface{}) error { 228 if err == nil { 229 return nil 230 } 231 return &withMessage{ 232 cause: err, 233 msg: fmt.Sprintf(format, args...), 234 } 235 } 236 237 type withMessage struct { 238 cause error 239 msg string 240 } 241 242 func (w *withMessage) Error() string { return w.msg + ": " + w.cause.Error() } 243 func (w *withMessage) Cause() error { return w.cause } 244 245 func (w *withMessage) Format(s fmt.State, verb rune) { 246 switch verb { 247 case 'v': 248 if s.Flag('+') { 249 fmt.Fprintf(s, "%+v\n", w.Cause()) 250 io.WriteString(s, w.msg) 251 return 252 } 253 fallthrough 254 case 's', 'q': 255 io.WriteString(s, w.Error()) 256 } 257 } 258 259 // Cause returns the underlying cause of the error, if possible. 260 // An error value has a cause if it implements the following 261 // interface: 262 // 263 // type causer interface { 264 // Cause() error 265 // } 266 // 267 // If the error does not implement Cause, the original error will 268 // be returned. If the error is nil, nil will be returned without further 269 // investigation. 270 func Cause(err error) error { 271 type causer interface { 272 Cause() error 273 } 274 275 for err != nil { 276 cause, ok := err.(causer) 277 if !ok { 278 break 279 } 280 err = cause.Cause() 281 } 282 return err 283 }