github.com/go-graphite/carbonapi@v0.17.0/zipper/helper/errors.go (about) 1 package helper 2 3 import ( 4 "context" 5 "net" 6 "net/http" 7 "net/url" 8 "strings" 9 10 "github.com/ansel1/merry" 11 "github.com/go-graphite/carbonapi/pkg/parser" 12 "github.com/go-graphite/carbonapi/zipper/types" 13 ) 14 15 func requestError(err error, server string) merry.Error { 16 // with code InternalServerError by default, overwritten by custom error 17 if merry.Is(err, context.DeadlineExceeded) { 18 return types.ErrTimeoutExceeded.WithValue("server", server).WithCause(err) 19 } 20 if urlErr, ok := err.(*url.Error); ok { 21 if netErr, ok := urlErr.Err.(*net.OpError); ok { 22 return types.ErrBackendError.WithValue("server", server).WithCause(netErr) 23 } 24 } 25 if netErr, ok := err.(*net.OpError); ok { 26 return types.ErrBackendError.WithValue("server", server).WithCause(netErr) 27 } 28 return types.ErrResponceError.WithValue("server", server) 29 } 30 31 func HttpErrorCode(err merry.Error) (code int) { 32 if err == nil { 33 code = http.StatusOK 34 } else { 35 c := merry.RootCause(err) 36 if c == nil { 37 c = err 38 } 39 40 code = merry.HTTPCode(err) 41 if code == http.StatusNotFound { 42 return 43 } else if code == http.StatusInternalServerError && merry.Is(c, parser.ErrInvalidArg) { 44 // check for invalid args, see applyByNode rewrite function 45 code = http.StatusBadRequest 46 } 47 48 if code == http.StatusGatewayTimeout || code == http.StatusBadGateway || merry.Is(c, types.ErrFailedToFetch) { 49 // simplify code, one error type for communications errors, all we can retry 50 code = http.StatusServiceUnavailable 51 } 52 } 53 54 return 55 } 56 57 // for stable return code on multiply errors 58 func recalcCode(code, newCode int) int { 59 if newCode == http.StatusGatewayTimeout || newCode == http.StatusBadGateway { 60 // simplify code, one error type for communications errors, all we can retry 61 newCode = http.StatusServiceUnavailable 62 } 63 if code == 0 || code == http.StatusNotFound { 64 return newCode 65 } 66 67 if newCode >= 400 && newCode < 500 && code >= 400 && code < 500 { 68 if newCode == http.StatusBadRequest { 69 return newCode 70 } else if newCode == http.StatusForbidden && code != http.StatusBadRequest { 71 return newCode 72 } 73 } 74 if newCode < code { 75 code = newCode 76 } 77 return code 78 } 79 80 // MerryRootError strip merry error chain 81 func MerryRootError(err error) string { 82 c := merry.RootCause(err) 83 if c == nil { 84 c = err 85 } 86 return merryError(c) 87 } 88 89 func merryError(err error) string { 90 if msg := merry.Message(err); len(msg) > 0 { 91 return strings.TrimRight(msg, "\n") 92 } else { 93 return err.Error() 94 } 95 } 96 97 func MergeHttpErrors(errors []merry.Error) (int, []string) { 98 returnCode := http.StatusNotFound 99 errMsgs := make([]string, 0) 100 for _, err := range errors { 101 c := merry.RootCause(err) 102 if c == nil { 103 c = err 104 } 105 106 code := merry.HTTPCode(err) 107 if code == http.StatusNotFound { 108 continue 109 } else if code == http.StatusInternalServerError && merry.Is(c, parser.ErrInvalidArg) { 110 // check for invalid args, see applyByNode rewrite function 111 code = http.StatusBadRequest 112 } 113 114 errMsgs = append(errMsgs, merryError(c)) 115 116 returnCode = recalcCode(returnCode, code) 117 } 118 119 return returnCode, errMsgs 120 } 121 122 func MergeHttpErrorMap(errorsMap map[string]merry.Error) (returnCode int, errMap map[string]string) { 123 returnCode = http.StatusNotFound 124 errMap = make(map[string]string) 125 for key, err := range errorsMap { 126 c := merry.RootCause(err) 127 if c == nil { 128 c = err 129 } 130 131 code := merry.HTTPCode(err) 132 if code == http.StatusNotFound { 133 continue 134 } else if code == http.StatusInternalServerError && merry.Is(c, parser.ErrInvalidArg) { 135 // check for invalid args, see applyByNode rewrite function 136 code = http.StatusBadRequest 137 } 138 139 msg := merryError(c) 140 errMap[key] = msg 141 returnCode = recalcCode(returnCode, code) 142 } 143 144 return 145 } 146 147 func HttpErrorByCode(err merry.Error) merry.Error { 148 var returnErr merry.Error 149 if err == nil { 150 returnErr = types.ErrNoMetricsFetched 151 } else { 152 code := merry.HTTPCode(err) 153 msg := stripHtmlTags(merry.Message(err), 0) 154 if code == http.StatusForbidden { 155 returnErr = types.ErrForbidden 156 if len(msg) > 0 { 157 // pass message to caller 158 returnErr = returnErr.WithMessage(msg) 159 } 160 } else if code == http.StatusServiceUnavailable || code == http.StatusBadGateway || code == http.StatusGatewayTimeout { 161 returnErr = types.ErrFailedToFetch.WithHTTPCode(code).WithMessage(msg) 162 } else { 163 returnErr = types.ErrFailed.WithHTTPCode(code).WithMessage(msg) 164 } 165 } 166 167 return returnErr 168 }