github.com/supragya/TendermintConnector@v0.0.0-20210619045051-113e32b84fb1/_deprecated_chains/cosmos/libs/common/errors.go (about) 1 package common 2 3 import ( 4 "fmt" 5 "runtime" 6 ) 7 8 //---------------------------------------- 9 // Convenience method. 10 11 func ErrorWrap(cause interface{}, format string, args ...interface{}) Error { 12 if causeCmnError, ok := cause.(*cmnError); ok { 13 msg := fmt.Sprintf(format, args...) 14 return causeCmnError.Stacktrace().Trace(1, msg) 15 } else if cause == nil { 16 return newCmnError(FmtError{format, args}).Stacktrace() 17 } else { 18 // NOTE: causeCmnError is a typed nil here. 19 msg := fmt.Sprintf(format, args...) 20 return newCmnError(cause).Stacktrace().Trace(1, msg) 21 } 22 } 23 24 //---------------------------------------- 25 // Error & cmnError 26 27 /* 28 29 Usage with arbitrary error data: 30 31 ```go 32 // Error construction 33 type MyError struct{} 34 var err1 error = NewErrorWithData(MyError{}, "my message") 35 ... 36 // Wrapping 37 var err2 error = ErrorWrap(err1, "another message") 38 if (err1 != err2) { panic("should be the same") 39 ... 40 // Error handling 41 switch err2.Data().(type){ 42 case MyError: ... 43 default: ... 44 } 45 ``` 46 */ 47 type Error interface { 48 Error() string 49 Stacktrace() Error 50 Trace(offset int, format string, args ...interface{}) Error 51 Data() interface{} 52 } 53 54 // New Error with formatted message. 55 // The Error's Data will be a FmtError type. 56 func NewError(format string, args ...interface{}) Error { 57 err := FmtError{format, args} 58 return newCmnError(err) 59 } 60 61 // New Error with specified data. 62 func NewErrorWithData(data interface{}) Error { 63 return newCmnError(data) 64 } 65 66 type cmnError struct { 67 data interface{} // associated data 68 msgtraces []msgtraceItem // all messages traced 69 stacktrace []uintptr // first stack trace 70 } 71 72 var _ Error = &cmnError{} 73 74 // NOTE: do not expose. 75 func newCmnError(data interface{}) *cmnError { 76 return &cmnError{ 77 data: data, 78 msgtraces: nil, 79 stacktrace: nil, 80 } 81 } 82 83 // Implements error. 84 func (err *cmnError) Error() string { 85 return fmt.Sprintf("%v", err) 86 } 87 88 // Captures a stacktrace if one was not already captured. 89 func (err *cmnError) Stacktrace() Error { 90 if err.stacktrace == nil { 91 var offset = 3 92 var depth = 32 93 err.stacktrace = captureStacktrace(offset, depth) 94 } 95 return err 96 } 97 98 // Add tracing information with msg. 99 // Set n=0 unless wrapped with some function, then n > 0. 100 func (err *cmnError) Trace(offset int, format string, args ...interface{}) Error { 101 msg := fmt.Sprintf(format, args...) 102 return err.doTrace(msg, offset) 103 } 104 105 // Return the "data" of this error. 106 // Data could be used for error handling/switching, 107 // or for holding general error/debug information. 108 func (err *cmnError) Data() interface{} { 109 return err.data 110 } 111 112 func (err *cmnError) doTrace(msg string, n int) Error { 113 pc, _, _, _ := runtime.Caller(n + 2) // +1 for doTrace(). +1 for the caller. 114 // Include file & line number & msg. 115 // Do not include the whole stack trace. 116 err.msgtraces = append(err.msgtraces, msgtraceItem{ 117 pc: pc, 118 msg: msg, 119 }) 120 return err 121 } 122 123 func (err *cmnError) Format(s fmt.State, verb rune) { 124 switch verb { 125 case 'p': 126 s.Write([]byte(fmt.Sprintf("%p", &err))) 127 default: 128 if s.Flag('#') { 129 s.Write([]byte("--= Error =--\n")) 130 // Write data. 131 s.Write([]byte(fmt.Sprintf("Data: %#v\n", err.data))) 132 // Write msg trace items. 133 s.Write([]byte(fmt.Sprintf("Msg Traces:\n"))) 134 for i, msgtrace := range err.msgtraces { 135 s.Write([]byte(fmt.Sprintf(" %4d %s\n", i, msgtrace.String()))) 136 } 137 // Write stack trace. 138 if err.stacktrace != nil { 139 s.Write([]byte(fmt.Sprintf("Stack Trace:\n"))) 140 for i, pc := range err.stacktrace { 141 fnc := runtime.FuncForPC(pc) 142 file, line := fnc.FileLine(pc) 143 s.Write([]byte(fmt.Sprintf(" %4d %s:%d\n", i, file, line))) 144 } 145 } 146 s.Write([]byte("--= /Error =--\n")) 147 } else { 148 // Write msg. 149 s.Write([]byte(fmt.Sprintf("%v", err.data))) 150 } 151 } 152 } 153 154 //---------------------------------------- 155 // stacktrace & msgtraceItem 156 157 func captureStacktrace(offset int, depth int) []uintptr { 158 var pcs = make([]uintptr, depth) 159 n := runtime.Callers(offset, pcs) 160 return pcs[0:n] 161 } 162 163 type msgtraceItem struct { 164 pc uintptr 165 msg string 166 } 167 168 func (mti msgtraceItem) String() string { 169 fnc := runtime.FuncForPC(mti.pc) 170 file, line := fnc.FileLine(mti.pc) 171 return fmt.Sprintf("%s:%d - %s", 172 file, line, 173 mti.msg, 174 ) 175 } 176 177 //---------------------------------------- 178 // fmt error 179 180 /* 181 182 FmtError is the data type for NewError() (e.g. NewError().Data().(FmtError)) 183 Theoretically it could be used to switch on the format string. 184 185 ```go 186 // Error construction 187 var err1 error = NewError("invalid username %v", "BOB") 188 var err2 error = NewError("another kind of error") 189 ... 190 // Error handling 191 switch err1.Data().(cmn.FmtError).Format() { 192 case "invalid username %v": ... 193 case "another kind of error": ... 194 default: ... 195 } 196 ``` 197 */ 198 type FmtError struct { 199 format string 200 args []interface{} 201 } 202 203 func (fe FmtError) Error() string { 204 return fmt.Sprintf(fe.format, fe.args...) 205 } 206 207 func (fe FmtError) String() string { 208 return fmt.Sprintf("FmtError{format:%v,args:%v}", 209 fe.format, fe.args) 210 } 211 212 func (fe FmtError) Format() string { 213 return fe.format 214 } 215 216 //---------------------------------------- 217 // Panic wrappers 218 // XXX DEPRECATED 219 220 // A panic resulting from a sanity check means there is a programmer error 221 // and some guarantee is not satisfied. 222 // XXX DEPRECATED 223 func PanicSanity(v interface{}) { 224 panic(fmt.Sprintf("Panicked on a Sanity Check: %v", v)) 225 } 226 227 // A panic here means something has gone horribly wrong, in the form of data corruption or 228 // failure of the operating system. In a correct/healthy system, these should never fire. 229 // If they do, it's indicative of a much more serious problem. 230 // XXX DEPRECATED 231 func PanicCrisis(v interface{}) { 232 panic(fmt.Sprintf("Panicked on a Crisis: %v", v)) 233 } 234 235 // Indicates a failure of consensus. Someone was malicious or something has 236 // gone horribly wrong. These should really boot us into an "emergency-recover" mode 237 // XXX DEPRECATED 238 func PanicConsensus(v interface{}) { 239 panic(fmt.Sprintf("Panicked on a Consensus Failure: %v", v)) 240 } 241 242 // For those times when we're not sure if we should panic 243 // XXX DEPRECATED 244 func PanicQ(v interface{}) { 245 panic(fmt.Sprintf("Panicked questionably: %v", v)) 246 }