-
Notifications
You must be signed in to change notification settings - Fork 1
/
guru.go
125 lines (110 loc) · 2.85 KB
/
guru.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
116
117
118
119
120
121
122
123
124
125
// Package guru provides Go errors with a Guru Meditation Code.
package guru // import "github.com/teamwork/guru"
import (
"fmt"
"github.com/pkg/errors"
)
// coder is the main interface to errors in this package.
type coder interface {
Code() int
}
// causer is a local version of github.com/pkg/errors.causer
type causer interface {
Cause() error
}
// stackTracer is a local version of github.com/pkg/errors.stackTracer
type stackTracer interface {
StackTrace() errors.StackTrace
}
type withCode struct {
error
code int
*stack
}
func (e *withCode) Cause() error { return e.error }
func (e *withCode) Code() int { return e.code }
func (e withCode) Format(s fmt.State, verb rune) { fmt.Fprintf(s, "error %v: %v", e.code, e.error) } // nolint: errcheck
type wrapped struct {
msg string
code int
error
*stack
}
func (e *wrapped) Error() string { return e.msg }
func (e *wrapped) Cause() error { return e.error }
func (e *wrapped) Code() int { return e.code }
func (e wrapped) Format(s fmt.State, verb rune) {
fmt.Fprintf(s, "error %v: %v", e.code, e.error) // nolint: errcheck
if e.msg != "" {
fmt.Fprintf(s, ": %v", e.msg) // nolint: errcheck
}
}
// New returns a new error message with a stack trace and error code.
func New(code int, msg string) error {
return &withCode{
error: errors.New(msg),
code: code,
stack: callers(),
}
}
// Errorf returns a new error message with stack trace and error code.
func Errorf(code int, format string, args ...interface{}) error {
return &withCode{
error: fmt.Errorf(format, args...),
code: code,
stack: callers(),
}
}
// WithCode wraps an existing error with the provided error code and stack
// trace. It will return nil if err is nil.
func WithCode(code int, err error) error {
if err == nil {
return nil
}
return &withCode{
error: err,
code: code,
stack: callers(),
}
}
// Wrap returns an error annotating err with a stack trace, error code, and the
// supplied message. It will return nil if err is nil.
func Wrap(code int, err error, msg string) error {
if err == nil {
return nil
}
return &wrapped{
msg: msg,
code: code,
error: err,
stack: callers(),
}
}
// Wrapf returns an error annotating err with a stack trace, error code, and the
// format specifier. It will return nil if err is nil.
func Wrapf(code int, err error, msg string, args ...interface{}) error {
if err == nil {
return nil
}
return &wrapped{
msg: fmt.Sprintf(msg, args...),
code: code,
error: err,
stack: callers(),
}
}
// Code extracts the highest-level error code from the error or the errors it
// wraps. It will return 0 if the error does not implement the coder interface.
func Code(err error) int {
for {
if sc, ok := err.(coder); ok {
return sc.Code()
}
if cause, ok := err.(causer); ok {
err = cause.Cause()
} else {
break
}
}
return 0
}