This repository has been archived by the owner on Aug 14, 2019. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathwrap.go
115 lines (88 loc) · 2.1 KB
/
wrap.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
package emperror
import (
"fmt"
"io"
"runtime"
"github.com/pkg/errors"
)
func callers() []uintptr {
const depth = 32
var pcs [depth]uintptr
n := runtime.Callers(3, pcs[:])
return pcs[0:n]
}
type wrappedError struct {
err error
stack []uintptr
}
func (e *wrappedError) Error() string {
return e.err.Error()
}
func (e *wrappedError) Cause() error {
return e.err
}
func (e *wrappedError) StackTrace() errors.StackTrace {
f := make([]errors.Frame, len(e.stack))
for i := 0; i < len(f); i++ {
f[i] = errors.Frame((e.stack)[i])
}
return f
}
func (e *wrappedError) Format(s fmt.State, verb rune) {
switch verb {
case 'v':
if s.Flag('+') {
_, _ = fmt.Fprintf(s, "%+v", e.Cause())
for _, pc := range e.stack {
f := errors.Frame(pc)
_, _ = fmt.Fprintf(s, "\n%+v", f)
}
return
}
fallthrough
case 's':
_, _ = io.WriteString(s, e.Error())
case 'q':
_, _ = fmt.Fprintf(s, "%q", e.Error())
}
}
// Wrap returns an error annotating err with a stack trace
// at the point Wrap is called (if there is none attached to the error yet), and the supplied message.
// If err is nil, Wrap returns nil.
//
// Note: do not use this method when passing errors between goroutines.
func Wrap(err error, message string) error {
if err == nil {
return nil
}
_, ok := getStackTracer(err)
err = errors.WithMessage(err, message)
// There is no stack trace in the error, so attach it here
if !ok {
err = &wrappedError{
err: err,
stack: callers(),
}
}
return err
}
// Wrapf returns an error annotating err with a stack trace
// at the point Wrapf is call (if there is none attached to the error yet), and the format specifier.
// If err is nil, Wrapf returns nil.
//
// Note: do not use this method when passing errors between goroutines.
func Wrapf(err error, format string, args ...interface{}) error {
if err == nil {
return nil
}
_, ok := getStackTracer(err)
err = errors.WithMessage(err, fmt.Sprintf(format, args...))
// There is no stack trace in the error, so attach it here
if !ok {
err = &wrappedError{
err: err,
stack: callers(),
}
}
return err
}