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  }