gitlab.com/jokerrs1/Sia@v1.3.2/modules/host/errors.go (about) 1 package host 2 3 // errors.go is responsible for logging the various errors that the host runs 4 // into related to operations that cannot immediately provide feedback to the 5 // user. (e.g. network failures, disk failures, etc.). Different errors should 6 // be handled and logged differently, depending on severity and frequency, such 7 // that the person reading the logs is able to see all of the major issues 8 // without having them obstructed by the minor ones. 9 10 import ( 11 "errors" 12 "strings" 13 "sync/atomic" 14 15 "github.com/NebulousLabs/fastrand" 16 ) 17 18 const ( 19 errorCommunicationProbability = 5 20 errorConnectionProbability = 20 21 errorConsensusProbability = 1 22 errorInternalProbability = 3 23 errorNormalProbability = 20 24 ) 25 26 type ( 27 // ErrorCommunication errors are meant to be returned if the host and the 28 // renter seem to be miscommunicating. For example, if the renter attempts 29 // to pay an insufficient price, there has been a communication error. 30 ErrorCommunication string 31 32 // ErrorConnection is meant to be used on errors where the network is 33 // returning unexpected errors. For example, sudden disconnects or 34 // connection write failures. 35 ErrorConnection string 36 37 // ErrorConsensus errors are meant to be used when there are problems 38 // related to consensus, such as an inability to submit a storage proof to 39 // the blockchain, or an inability to get a file contract revision on to 40 // the blockchain. 41 ErrorConsensus string 42 43 // ErrorInternal errors are meant to be used if an internal process in the 44 // host is malfunctioning, for example if the disk is failing. 45 ErrorInternal string 46 ) 47 48 // composeErrors will take multiple errors and compose them into a single 49 // errors with a longer message. Any nil errors used as inputs will be stripped 50 // out, and if there are zero non-nil inputs then 'nil' will be returned. 51 // 52 // The original types of the errors is not preserved at all. 53 func composeErrors(errs ...error) error { 54 // Strip out any nil errors. 55 var errStrings []string 56 for _, err := range errs { 57 if err != nil { 58 errStrings = append(errStrings, err.Error()) 59 } 60 } 61 62 // Return nil if there are no non-nil errors in the input. 63 if len(errStrings) <= 0 { 64 return nil 65 } 66 67 // Combine all of the non-nil errors into one larger return value. 68 return errors.New(strings.Join(errStrings, "; ")) 69 } 70 71 // extendErr will return an error that is the same type as the input error, but 72 // prefixed with the provided context. This only works for the error types 73 // defined in the host package. If the input error is nil, the extension is 74 // ignored and nil will be returned. 75 func extendErr(s string, err error) error { 76 if err == nil { 77 return nil 78 } 79 80 switch v := err.(type) { 81 case ErrorCommunication: 82 return ErrorCommunication(s) + v 83 case ErrorConnection: 84 return ErrorConnection(s) + v 85 case ErrorConsensus: 86 return ErrorConsensus(s) + v 87 case ErrorInternal: 88 return ErrorInternal(s) + v 89 default: 90 return errors.New(s + err.Error()) 91 } 92 93 } 94 95 // Error satisfies the Error interface for the ErrorCommunication type. 96 func (ec ErrorCommunication) Error() string { 97 return "communication error: " + string(ec) 98 } 99 100 // Error satisfies the Error interface for the ErrorConnection type. 101 func (ec ErrorConnection) Error() string { 102 return "connection error: " + string(ec) 103 } 104 105 // Error satisfies the Error interface for the ErrorConsensus type. 106 func (ec ErrorConsensus) Error() string { 107 return "consensus error: " + string(ec) 108 } 109 110 // Error satisfies the Error interface for the ErrorInternal type. 111 func (ec ErrorInternal) Error() string { 112 return "internal error: " + string(ec) 113 } 114 115 // mangedLogError will take an error and log it to the host, depending on the 116 // type of error and whether or not the DEBUG flag has been set. 117 func (h *Host) managedLogError(err error) { 118 // Determine the type of error and the number of times that this error has 119 // been logged. 120 var num uint64 121 var probability int // Error will be logged with 1/probability chance. 122 switch err.(type) { 123 case ErrorCommunication: 124 num = atomic.LoadUint64(&h.atomicCommunicationErrors) 125 probability = errorCommunicationProbability 126 case ErrorConnection: 127 num = atomic.LoadUint64(&h.atomicConnectionErrors) 128 probability = errorConnectionProbability 129 case ErrorConsensus: 130 num = atomic.LoadUint64(&h.atomicConsensusErrors) 131 probability = errorConsensusProbability 132 case ErrorInternal: 133 num = atomic.LoadUint64(&h.atomicInternalErrors) 134 probability = errorInternalProbability 135 default: 136 num = atomic.LoadUint64(&h.atomicNormalErrors) 137 probability = errorNormalProbability 138 } 139 140 // If num > logFewLimit, substantially decrease the probability that the error 141 // gets logged. 142 if num > logFewLimit { 143 probability = probability * 25 144 } 145 146 // If we've seen less than logAllLimit of that type of error before, log 147 // the error as a normal logging statement. Otherwise, probabilistically 148 // log the statement. In debugging mode, log all statements. 149 shouldLog := num < logAllLimit || fastrand.Intn(probability+1) == probability 150 if shouldLog { 151 h.log.Println(err) 152 } else { 153 h.log.Debugln(err) 154 return 155 } 156 157 // Increment the log counter. 158 switch err.(type) { 159 case ErrorCommunication: 160 atomic.AddUint64(&h.atomicCommunicationErrors, 1) 161 case ErrorConnection: 162 atomic.AddUint64(&h.atomicConnectionErrors, 1) 163 case ErrorConsensus: 164 atomic.AddUint64(&h.atomicConsensusErrors, 1) 165 case ErrorInternal: 166 atomic.AddUint64(&h.atomicInternalErrors, 1) 167 default: 168 atomic.AddUint64(&h.atomicNormalErrors, 1) 169 } 170 }