mirror of
https://github.com/mjl-/mox.git
synced 2025-07-13 02:54:38 +03:00
check and log errors more often in deferred cleanup calls, and log remote-induced errors at lower priority
We normally check errors for all operations. But for some cleanup calls, eg "defer file.Close()", we didn't. Now we also check and log most of those. Partially because those errors can point to some mishandling or unexpected code paths (eg file unexpected already closed). And in part to make it easier to use "errcheck" to find the real missing error checks, there is too much noise now. The log.Check function can now be used unconditionally for checking and logging about errors. It adjusts the log level if the error is caused by a network connection being closed, or a context is canceled or its deadline reached, or a socket deadline is reached.
This commit is contained in:
24
mlog/isclosed.go
Normal file
24
mlog/isclosed.go
Normal file
@ -0,0 +1,24 @@
|
||||
package mlog
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"net"
|
||||
"syscall"
|
||||
)
|
||||
|
||||
// In separate file because of import of syscall.
|
||||
|
||||
// IsClosed returns whether i/o failed, typically because the connection is closed
|
||||
// or otherwise cannot be used for further i/o.
|
||||
//
|
||||
// Used to prevent error logging for connections that are closed.
|
||||
func IsClosed(err error) bool {
|
||||
return errors.Is(err, net.ErrClosed) || errors.Is(err, syscall.EPIPE) || errors.Is(err, syscall.ECONNRESET) || isRemoteTLSError(err)
|
||||
}
|
||||
|
||||
// A remote TLS client can send a message indicating failure, this makes it back to
|
||||
// us as a write error.
|
||||
func isRemoteTLSError(err error) bool {
|
||||
var netErr *net.OpError
|
||||
return errors.As(err, &netErr) && netErr.Op == "remote error"
|
||||
}
|
17
mlog/log.go
17
mlog/log.go
@ -16,6 +16,7 @@ import (
|
||||
"bytes"
|
||||
"context"
|
||||
"encoding/base64"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"log/slog"
|
||||
@ -199,11 +200,21 @@ func (l Log) WithFunc(fn func() []slog.Attr) Log {
|
||||
}
|
||||
|
||||
// Check logs an error if err is not nil. Intended for logging errors that are good
|
||||
// to know, but would not influence program flow.
|
||||
// to know, but would not influence program flow. Context deadline/cancelation
|
||||
// errors and timeouts are logged at "info" level. Closed remote connections are
|
||||
// logged at "debug" level. Other errors at "error" level.
|
||||
func (l Log) Check(err error, msg string, attrs ...slog.Attr) {
|
||||
if err != nil {
|
||||
l.Errorx(msg, err, attrs...)
|
||||
if err == nil {
|
||||
return
|
||||
}
|
||||
level := LevelError
|
||||
if errors.Is(err, context.DeadlineExceeded) || errors.Is(err, context.Canceled) || errors.Is(err, os.ErrDeadlineExceeded) {
|
||||
level = LevelInfo
|
||||
} else if IsClosed(err) {
|
||||
level = LevelDebug
|
||||
}
|
||||
attrs = append([]slog.Attr{errAttr(err)}, attrs...)
|
||||
l.Logger.LogAttrs(noctx, level, msg, attrs...)
|
||||
}
|
||||
|
||||
func errAttr(err error) slog.Attr {
|
||||
|
Reference in New Issue
Block a user