package errors import ( "fmt" "io" "runtime" "github.com/pkg/errors" ) func callers() []uintptr { var pcs [32]uintptr l := runtime.Callers(3, pcs[:]) return pcs[:l] } // Error a error with caller stack information type Error interface { error t() } var _ Error = (*item)(nil) var _ fmt.Formatter = (*item)(nil) type item struct { msg string stack []uintptr } func (i *item) Error() string { return i.msg } func (i *item) t() {} // Format used by go.uber.org/zap in Verbose func (i *item) Format(s fmt.State, verb rune) { _, _ = io.WriteString(s, i.msg) _, _ = io.WriteString(s, "\n") for _, pc := range i.stack { _, _ = fmt.Fprintf(s, "%+v\n", errors.Frame(pc)) } } // New create a new error func New(msg string) Error { return &item{msg: msg, stack: callers()} } // Errorf create a new error func Errorf(format string, args ...any) Error { return &item{msg: fmt.Sprintf(format, args...), stack: callers()} } // Wrap with some extra message into err func Wrap(err error, msg string) Error { if err == nil { return nil } e, ok := err.(*item) if !ok { return &item{msg: fmt.Sprintf("%s; %s", msg, err.Error()), stack: callers()} } e.msg = fmt.Sprintf("%s; %s", msg, e.msg) return e } // Wrapf with some extra message into err func Wrapf(err error, format string, args ...any) Error { if err == nil { return nil } msg := fmt.Sprintf(format, args...) e, ok := err.(*item) if !ok { return &item{msg: fmt.Sprintf("%s; %s", msg, err.Error()), stack: callers()} } e.msg = fmt.Sprintf("%s; %s", msg, e.msg) return e } // WithStack add caller stack information func WithStack(err error) Error { if err == nil { return nil } if e, ok := err.(*item); ok { return e } return &item{msg: err.Error(), stack: callers()} }