diff --git a/errors.go b/errors.go index 842ee80..8c6664e 100644 --- a/errors.go +++ b/errors.go @@ -121,6 +121,8 @@ type fundamental struct { *stack } +func (f *fundamental) hasStack() bool { return true } + func (f *fundamental) Error() string { return f.msg } func (f *fundamental) Format(s fmt.State, verb rune) { @@ -174,13 +176,24 @@ func (w *withStack) Format(s fmt.State, verb rune) { } } +func (w *withStack) hasStack() bool { return true } + // Wrap returns an error annotating err with a stack trace // at the point Wrap is called, and the supplied message. // If err is nil, Wrap returns nil. func Wrap(err error, message string) error { + type hasStacker interface { + hasStack() bool + } if err == nil { return nil } + if stacker, ok := err.(hasStacker); ok && stacker.hasStack() { + return &withMessage{ + cause: err, + msg: message, + } + } err = &withMessage{ cause: err, msg: message, @@ -195,9 +208,18 @@ func Wrap(err error, message string) error { // at the point Wrapf is call, and the format specifier. // If err is nil, Wrapf returns nil. func Wrapf(err error, format string, args ...interface{}) error { + type hasStacker interface { + hasStack() bool + } if err == nil { return nil } + if stacker, ok := err.(hasStacker); ok && stacker.hasStack() { + return &withMessage{ + cause: err, + msg: fmt.Sprintf(format, args...), + } + } err = &withMessage{ cause: err, msg: fmt.Sprintf(format, args...), @@ -242,6 +264,16 @@ func (w *withMessage) Format(s fmt.State, verb rune) { } } +func (w *withMessage) hasStack() bool { + type hasStacker interface { + hasStack() bool + } + if cause, ok := w.Cause().(hasStacker); ok { + return cause.hasStack() + } + return false +} + // Cause returns the underlying cause of the error, if possible. // An error value has a cause if it implements the following // interface: