-
Notifications
You must be signed in to change notification settings - Fork 3
/
types.go
151 lines (121 loc) · 2.88 KB
/
types.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
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
package microerror
import (
"encoding/json"
"errors"
"fmt"
)
const (
kindNil = "nil"
kindUnknown = "unknown"
)
type Error struct {
Desc string `json:"desc,omitempty"`
Docs string `json:"docs,omitempty"`
Kind string `json:"kind"`
}
// GoString is here for backward compatibility.
//
// NOTE: Use JSON(err) instead of Printf("%#v", err).
func (e *Error) GoString() string {
return JSON(e)
}
func (e *Error) Error() string {
return toStringCase(e.Kind)
}
type JSONError struct {
*Error `json:",inline"`
Annotation string `json:"annotation,omitempty"`
Stack []StackEntry `json:"stack,omitempty"`
}
type StackEntry struct {
File string `json:"file"`
Line int `json:"line"`
PC uintptr `json:"-"`
}
type annotatedError struct {
annotation string
underlying *Error
}
// GoString is here for backward compatibility.
//
// NOTE: Use JSON(err) instead of Printf("%#v", err).
func (e *annotatedError) GoString() string {
return JSON(e)
}
func (e *annotatedError) Error() string {
if e.annotation == "" {
return e.underlying.Error()
}
return e.underlying.Error() + ": " + e.annotation
}
func (e *annotatedError) MarshalJSON() ([]byte, error) {
o := JSONError{
Error: e.underlying,
Annotation: e.annotation,
}
bytes, err := json.Marshal(o)
if err != nil {
return nil, fmt.Errorf("microerror.annotatedError.MarshalJSON: %w object=%#v", err, o)
}
return bytes, nil
}
func (e *annotatedError) Unwrap() error {
return e.underlying
}
type stackedError struct {
stackEntry StackEntry
underlying error
}
// GoString is here for backward compatibility.
//
// NOTE: Use JSON(err) instead of Printf("%#v", err).
func (e *stackedError) GoString() string {
return JSON(e)
}
func (e *stackedError) Error() string {
return e.underlying.Error()
}
// MarshalJSON unwraps all the stackedError and reconstructs the stack. Then it
// tries to find annotatedError to find the custom error annotation and finally
// tries to find Error or just creates one from arbitrary error. Then it sets
// all the fields to JSONError and finally marshals it using standard
// json.Marshal call.
func (e *stackedError) MarshalJSON() ([]byte, error) {
stack := createStackTrace(e)
var eerr *Error
var annotation string
{
if errors.As(e, &eerr) {
var aerr *annotatedError
if errors.As(e, &aerr) {
annotation = aerr.annotation
}
} else {
eerr = &Error{
Kind: kindUnknown,
}
annotation = e.Error()
}
}
o := JSONError{
Error: eerr,
Annotation: annotation,
Stack: stack,
}
bytes, err := json.Marshal(o)
if err != nil {
return nil, fmt.Errorf("microerror.stackedError.MarshalJSON: %w object=%#v", err, o)
}
return bytes, nil
}
func (e *stackedError) StackTrace() []uintptr {
stack := createStackTrace(e)
var pcs []uintptr
for _, e := range stack {
pcs = append(pcs, e.PC)
}
return pcs
}
func (e *stackedError) Unwrap() error {
return e.underlying
}