From b521ff421ea09ad3d7440fdc84562d6fca2d4b46 Mon Sep 17 00:00:00 2001
From: Nattawit Chaiworawitsakul <c.nattawit@gmail.com>
Date: Sat, 17 Jun 2017 11:30:34 +0700
Subject: [PATCH] #75 Wrap() add withStack only if no cause with stack present

---
 errors.go | 32 ++++++++++++++++++++++++++++++++
 1 file changed, 32 insertions(+)

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: