sq/libsq/core/errz/errz.go
Neil O'Toole c7bba4dfe4
go1.21: changes to support slog as part of stdlib (#299)
* go1.21: changes to support slog as part of stdlib

* Removed accidentially checked-in line of code

* Fixed minor linting issues; reenable typecheck

* go1.21: switched to stdlib slices pkg
2023-08-12 12:54:14 -06:00

85 lines
1.9 KiB
Go

// Package errz is sq's error package. It exists to combine
// functionality from several error packages, including
// annotating errors with stack trace. Most of it comes
// from pkg/errors.
//
// 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
package errz
import (
"context"
"errors"
"fmt"
"log/slog"
"path/filepath"
"go.uber.org/multierr"
)
// 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(),
}
}
// 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
// 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)
}
// IsErrContextDeadlineExceeded returns true if err is context.DeadlineExceeded.
func IsErrContextDeadlineExceeded(err error) bool {
return errors.Is(err, context.DeadlineExceeded)
}