Skip to content

Commit ea1ce07

Browse files
committed
don't log errors that are expected
1 parent 49affad commit ea1ce07

File tree

2 files changed

+66
-19
lines changed

2 files changed

+66
-19
lines changed

router/errors.go

Lines changed: 19 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -86,40 +86,40 @@ func httpError(code int, fmtString string, args ...interface{}) *HTTPError {
8686
}
8787
}
8888

89-
// HandleError will handle an error
89+
// HandleError will handle any error. If it is of type *HTTPError then it will
90+
// log anything of a 50x or an InternalError. It will write the right error response
91+
// to the client. This way if you return a BadRequestError, it will simply write to the client.
92+
// Any non-HTTPError will be treated as unhandled and result in a 50x
9093
func HandleError(err error, w http.ResponseWriter, r *http.Request) {
94+
if err == nil || reflect.ValueOf(err).IsNil() {
95+
return
96+
}
97+
9198
log := tracing.GetLogger(r)
9299
errorID := tracing.GetRequestID(r)
93100

94101
var notifyBugsnag bool
95102

96103
switch e := err.(type) {
97-
case nil:
98-
return
99104
case *HTTPError:
100-
// assert to *HTTPError to check nil intrface
101-
httpErr := err.(*HTTPError)
102-
if httpErr == nil {
103-
return
104-
}
105-
105+
e.ErrorID = errorID
106106
if e.Code >= http.StatusInternalServerError {
107-
e.ErrorID = errorID
108-
// this will get us the stack trace too
109-
log.WithError(e.Cause()).Error(e.Error())
110107
notifyBugsnag = true
111-
} else {
112-
log.WithError(e.Cause()).Infof("unexpected error: %s", e.Error())
108+
elog := log.WithError(e)
109+
if e.InternalError != nil {
110+
elog = elog.WithField("internal_err", e.InternalError.Error())
111+
}
112+
113+
elog.Errorf("internal server error: %s", e.InternalMessage)
114+
} else if e.InternalError != nil {
115+
notifyBugsnag = true
116+
log.WithError(e).Infof("unexpected error: %s", e.InternalMessage)
113117
}
114118

115119
if jsonErr := SendJSON(w, e.Code, e); jsonErr != nil {
116120
log.WithError(jsonErr).Error("Failed to write the JSON error response")
117121
}
118122
default:
119-
// this is 5ns slower than using unsafe but a unhandled internal server error should not happen that often
120-
if reflect.ValueOf(err).IsNil() {
121-
return
122-
}
123123
notifyBugsnag = true
124124
metriks.Inc("unhandled_errors", 1)
125125
log.WithError(e).Errorf("Unhandled server error: %s", e.Error())
@@ -129,6 +129,7 @@ func HandleError(err error, w http.ResponseWriter, r *http.Request) {
129129
log.WithError(writeErr).Error("Error writing generic error message")
130130
}
131131
}
132+
132133
if notifyBugsnag {
133134
bugsnag.Notify(err, r, r.Context(), bugsnag.MetaData{
134135
"meta": map[string]interface{}{

router/errors_test.go

Lines changed: 47 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,26 @@ func TestHandleError_ErrorIsNilPointerToTypeHTTPError(t *testing.T) {
5454
assert.Empty(t, w.Header())
5555
}
5656

57+
func TestHandleError_ErrorIsNilInterface(t *testing.T) {
58+
logger, loggerOutput := test.NewNullLogger()
59+
w, r, _ := tracing.NewTracer(
60+
httptest.NewRecorder(),
61+
httptest.NewRequest(http.MethodGet, "/", nil),
62+
logger,
63+
"test",
64+
"test",
65+
)
66+
67+
h := func(_ http.ResponseWriter, _ *http.Request) error {
68+
return nil
69+
}
70+
71+
HandleError(h(w, r), w, r)
72+
73+
assert.Empty(t, loggerOutput.AllEntries())
74+
assert.Empty(t, w.Header())
75+
}
76+
5777
func TestHandleError_StandardError(t *testing.T) {
5878
logger, loggerOutput := test.NewNullLogger()
5979
w, r, _ := tracing.NewTracer(
@@ -99,7 +119,33 @@ func TestHandleError_HTTPError(t *testing.T) {
99119
assert.Equal(t, expectedBody, string(b))
100120

101121
require.Len(t, loggerOutput.AllEntries(), 1)
102-
assert.Equal(t, httpErr.InternalMessage, loggerOutput.AllEntries()[0].Message)
122+
assert.Equal(t, "internal server error: "+httpErr.InternalMessage, loggerOutput.AllEntries()[0].Message)
123+
}
124+
125+
func TestHandleError_NoLogForNormalErrors(t *testing.T) {
126+
logger, loggerOutput := test.NewNullLogger()
127+
recorder := httptest.NewRecorder()
128+
w, r, _ := tracing.NewTracer(
129+
recorder,
130+
httptest.NewRequest(http.MethodGet, "/", nil),
131+
logger,
132+
"test",
133+
"test",
134+
)
135+
136+
httpErr := BadRequestError("not found yo.")
137+
138+
HandleError(httpErr, w, r)
139+
140+
resp := recorder.Result()
141+
b, err := ioutil.ReadAll(resp.Body)
142+
require.NoError(t, err)
143+
144+
expectedBody := fmt.Sprintf(`{"code":400,"msg":"not found yo.","error_id":"%s"}`, tracing.GetRequestID(r))
145+
assert.Equal(t, expectedBody, string(b))
146+
147+
// we shouldn't log anything, this is a normal error
148+
require.Len(t, loggerOutput.AllEntries(), 0)
103149
}
104150

105151
type OtherError struct {

0 commit comments

Comments
 (0)