diff --git a/middleware/grpc_logging.go b/middleware/grpc_logging.go index 59994413..e5b0e670 100644 --- a/middleware/grpc_logging.go +++ b/middleware/grpc_logging.go @@ -1,6 +1,7 @@ package middleware import ( + "errors" "time" "golang.org/x/net/context" @@ -31,6 +32,9 @@ func (s GRPCServerLog) UnaryServerInterceptor(ctx context.Context, req interface if err == nil && s.DisableRequestSuccessLog { return resp, nil } + if errors.Is(err, DoNotLogError{}) { + return resp, err + } entry := user.LogWith(ctx, s.Log).WithFields(logging.Fields{"method": info.FullMethod, "duration": time.Since(begin)}) if err != nil { diff --git a/middleware/logging.go b/middleware/logging.go index fcb8453f..c3c00b99 100644 --- a/middleware/logging.go +++ b/middleware/logging.go @@ -46,6 +46,14 @@ func NewLogMiddleware(log logging.Interface, logRequestHeaders bool, logRequestA } } +// This can be used with `errors.Is` to see if the error marked itself as not to be logged. +// E.g. if the error is caused by overload, then we don't want to log it because that uses more resource. +type DoNotLogError struct{ Err error } + +func (i DoNotLogError) Error() string { return i.Err.Error() } +func (i DoNotLogError) Unwrap() error { return i.Err } +func (i DoNotLogError) Is(target error) bool { _, ok := target.(DoNotLogError); return ok } + // logWithRequest information from the request and context as fields. func (l Log) logWithRequest(r *http.Request) logging.Interface { localLog := l.Log @@ -83,6 +91,9 @@ func (l Log) Wrap(next http.Handler) http.Handler { statusCode, writeErr := wrapped.getStatusCode(), wrapped.getWriteError() if writeErr != nil { + if errors.Is(writeErr, DoNotLogError{}) { + return + } if errors.Is(writeErr, context.Canceled) { if l.LogRequestAtInfoLevel { requestLog.Infof("%s %s %s, request cancelled: %s ws: %v; %s", r.Method, uri, time.Since(begin), writeErr, IsWSHandshakeRequest(r), headers) diff --git a/middleware/logging_test.go b/middleware/logging_test.go index c282064c..f9b2883e 100644 --- a/middleware/logging_test.go +++ b/middleware/logging_test.go @@ -28,6 +28,9 @@ func TestBadWriteLogging(t *testing.T) { }, { err: nil, logContains: []string{"debug", "GET http://example.com/foo (200)"}, + }, { + err: DoNotLogError{Err: errors.New("yolo")}, + logContains: nil, }} { buf := bytes.NewBuffer(nil) logrusLogger := logrus.New() @@ -51,6 +54,9 @@ func TestBadWriteLogging(t *testing.T) { } loggingHandler.ServeHTTP(w, req) + if len(tc.logContains) == 0 { + require.Empty(t, buf) + } for _, content := range tc.logContains { require.True(t, bytes.Contains(buf.Bytes(), []byte(content))) }