2020-10-20 18:05:43 +03:00
|
|
|
// Package errz is sq's error package. It exists to combine
|
2022-12-18 07:31:06 +03:00
|
|
|
// functionality from several error packages, including
|
2023-04-02 22:49:45 +03:00
|
|
|
// annotating errors with stack trace. Most of it comes
|
|
|
|
// from pkg/errors.
|
2022-12-18 07:31:06 +03:00
|
|
|
//
|
|
|
|
// At some point this package may become redundant, particularly in
|
|
|
|
// light of the proposed stdlib multiple error support:
|
|
|
|
// https://github.com/golang/go/issues/53435
|
2020-08-06 20:58:47 +03:00
|
|
|
package errz
|
|
|
|
|
|
|
|
import (
|
2023-04-30 17:18:56 +03:00
|
|
|
"context"
|
|
|
|
"errors"
|
2023-04-02 22:49:45 +03:00
|
|
|
"fmt"
|
|
|
|
"path/filepath"
|
2020-08-06 20:58:47 +03:00
|
|
|
|
2023-04-02 22:49:45 +03:00
|
|
|
"go.uber.org/multierr"
|
2020-08-06 20:58:47 +03:00
|
|
|
|
2023-04-02 22:49:45 +03:00
|
|
|
"golang.org/x/exp/slog"
|
|
|
|
)
|
2020-08-06 20:58:47 +03:00
|
|
|
|
2023-04-02 22:49:45 +03:00
|
|
|
// Err annotates err with a stack trace at the point WithStack was called.
|
|
|
|
// If err is nil, Err returns nil.
|
|
|
|
func Err(err error) error {
|
|
|
|
if err == nil {
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
return &withStack{
|
|
|
|
err,
|
|
|
|
callers(),
|
|
|
|
}
|
|
|
|
}
|
2020-08-06 20:58:47 +03:00
|
|
|
|
|
|
|
// Append is documented by multierr.Append.
|
|
|
|
var Append = multierr.Append
|
|
|
|
|
|
|
|
// Combine is documented by multierr.Combine.
|
|
|
|
var Combine = multierr.Combine
|
|
|
|
|
|
|
|
// Errors is documented by multierr.Errors.
|
|
|
|
var Errors = multierr.Errors
|
2023-04-02 22:49:45 +03:00
|
|
|
|
|
|
|
// logValue return a slog.Value for err.
|
|
|
|
func logValue(err error) slog.Value {
|
|
|
|
if err == nil {
|
|
|
|
return slog.Value{}
|
|
|
|
}
|
|
|
|
|
|
|
|
c := Cause(err)
|
|
|
|
if c == nil {
|
|
|
|
// Shouldn't happen
|
|
|
|
return slog.Value{}
|
|
|
|
}
|
|
|
|
|
|
|
|
msgAttr := slog.String("msg", err.Error())
|
|
|
|
causeAttr := slog.String("cause", c.Error())
|
|
|
|
typeAttr := slog.String("type", fmt.Sprintf("%T", c))
|
|
|
|
|
|
|
|
if ws, ok := err.(*withStack); ok { //nolint:errorlint
|
|
|
|
st := ws.stack.StackTrace()
|
|
|
|
|
|
|
|
if len(st) > 0 {
|
|
|
|
f := st[0]
|
|
|
|
file := f.file()
|
|
|
|
funcName := f.name()
|
|
|
|
if funcName != unknown {
|
|
|
|
fp := filepath.Join(filepath.Base(filepath.Dir(file)), filepath.Base(file))
|
|
|
|
return slog.GroupValue(
|
|
|
|
msgAttr,
|
|
|
|
causeAttr,
|
|
|
|
typeAttr,
|
|
|
|
slog.String("func", funcName),
|
|
|
|
slog.String("source", fmt.Sprintf("%s:%d", fp, f.line())),
|
|
|
|
)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return slog.GroupValue(msgAttr, causeAttr, typeAttr)
|
|
|
|
}
|
2023-04-30 17:18:56 +03:00
|
|
|
|
|
|
|
// IsErrContextDeadlineExceeded returns true if err is context.DeadlineExceeded.
|
|
|
|
func IsErrContextDeadlineExceeded(err error) bool {
|
|
|
|
return errors.Is(err, context.DeadlineExceeded)
|
|
|
|
}
|