7
7
"fmt"
8
8
"os"
9
9
"strings"
10
- "unicode"
11
10
"unsafe"
12
11
)
13
12
@@ -21,8 +20,10 @@ type Erf struct {
21
20
err error
22
21
format string
23
22
args []interface {}
23
+ tags []string
24
24
tagIndexes map [string ]int
25
25
pc []uintptr
26
+ top int
26
27
}
27
28
28
29
// Error is implementation of error.
@@ -38,6 +39,20 @@ func (e *Erf) Unwrap() error {
38
39
return nil
39
40
}
40
41
42
+ // UnwrapAll returns all errors using Unwrap method. The first element in the returned value is e.
43
+ func (e * Erf ) UnwrapAll () []error {
44
+ result := make ([]error , 0 , 4096 )
45
+ for err := error (e ); err != nil ; {
46
+ result = append (result , err )
47
+ if wErr , ok := err .(WrappedError ); ok {
48
+ err = wErr .Unwrap ()
49
+ } else {
50
+ err = nil
51
+ }
52
+ }
53
+ return result
54
+ }
55
+
41
56
// Format is implementation of fmt.Formatter.
42
57
// Format lists error messages and appends StackTrace's for underlying Erf and all of wrapped Erf's,
43
58
// line by line with given format.
@@ -83,12 +98,10 @@ func (e *Erf) Format(f fmt.State, verb rune) {
83
98
pad , wid , prec := getPadWidPrec (f )
84
99
format += fmt .Sprintf ("%d.%ds" , wid , prec )
85
100
padding , indent := bytes .Repeat ([]byte {pad }, wid ), bytes .Repeat ([]byte {pad }, prec )
86
- newLine := false
87
- for err := error (e ); err != nil ; {
88
- if newLine {
101
+ for idx , err := range e .UnwrapAll () {
102
+ if idx > 0 {
89
103
buf .WriteRune ('\n' )
90
104
}
91
- newLine = true
92
105
if e2 , ok := err .(* Erf ); ok {
93
106
if ! f .Flag ('-' ) {
94
107
for _ , line := range strings .Split (e2 .Error (), "\n " ) {
@@ -98,30 +111,28 @@ func (e *Erf) Format(f fmt.State, verb rune) {
98
111
buf .WriteRune ('\n' )
99
112
}
100
113
}
101
- buf .WriteString (fmt .Sprintf (format , e2 .StackTrace ()))
114
+ str := fmt .Sprintf (format , e2 .StackTrace ())
115
+ if str != "" {
116
+ buf .WriteString (str )
117
+ } else {
118
+ buf .Write (padding )
119
+ buf .WriteString ("* " )
120
+ }
102
121
buf .WriteRune ('\n' )
103
122
if f .Flag ('+' ) {
104
123
tags := e2 .Tags ()
105
124
if len (tags ) > 0 {
106
125
buf .Write (padding )
107
- buf .WriteString ("* " )
126
+ buf .WriteString ("+ " )
108
127
for idx , tag := range tags {
109
128
if idx > 0 {
110
129
buf .WriteRune (' ' )
111
130
}
112
- v := "s"
113
- for _ , r := range tag {
114
- if unicode .IsSpace (r ) || r == '"' || r == '\'' {
115
- v = "q"
116
- break
117
- }
118
- }
119
- buf .WriteString (fmt .Sprintf ("%" + v + "=%q" , tag , fmt .Sprintf ("%v" , e2 .Tag (tag ))))
131
+ buf .WriteString (fmt .Sprintf ("%q=%q" , tag , fmt .Sprintf ("%v" , e2 .Tag (tag ))))
120
132
}
121
133
buf .WriteRune ('\n' )
122
134
}
123
135
}
124
- buf .Write (padding )
125
136
} else {
126
137
if ! f .Flag ('-' ) {
127
138
for _ , line := range strings .Split (err .Error (), "\n " ) {
@@ -130,19 +141,16 @@ func (e *Erf) Format(f fmt.State, verb rune) {
130
141
buf .WriteString (line )
131
142
buf .WriteRune ('\n' )
132
143
}
133
- buf .Write (padding )
134
144
} else {
135
- newLine = false
145
+ buf .Write (padding )
146
+ buf .WriteString ("- " )
147
+ buf .WriteRune ('\n' )
136
148
}
137
149
}
150
+ buf .Write (padding )
138
151
if verb == 'X' {
139
152
break
140
153
}
141
- if wErr , ok := err .(WrappedError ); ok {
142
- err = wErr .Unwrap ()
143
- } else {
144
- err = nil
145
- }
146
154
}
147
155
default :
148
156
return
@@ -189,23 +197,26 @@ func (e *Erf) Attach(tags ...string) *Erf {
189
197
if e .args == nil {
190
198
panic ("args are not using" )
191
199
}
192
- if e .tagIndexes != nil {
200
+ if e .tags != nil || e . tagIndexes != nil {
193
201
panic ("tags are already attached" )
194
202
}
195
203
if len (tags ) > len (e .args ) {
196
204
panic ("number of tags is more than args" )
197
205
}
198
- tagIndexes := make (map [string ]int , len (tags ))
206
+ t := make ([]string , 0 , len (tags ))
207
+ ti := make (map [string ]int , len (tags ))
199
208
for index , tag := range tags {
200
209
if tag == "" {
201
210
continue
202
211
}
203
- if _ , ok := tagIndexes [tag ]; ok {
212
+ if _ , ok := ti [tag ]; ok {
204
213
panic ("tag already defined" )
205
214
}
206
- tagIndexes [tag ] = index
215
+ t = append (t , tag )
216
+ ti [tag ] = index
207
217
}
208
- e .tagIndexes = tagIndexes
218
+ e .tags = t
219
+ e .tagIndexes = ti
209
220
return e
210
221
}
211
222
@@ -228,32 +239,39 @@ func (e *Erf) Tag(tag string) interface{} {
228
239
229
240
// Tags returns all tags sequentially. It returns nil if tags are not attached.
230
241
func (e * Erf ) Tags () []string {
231
- if e .tagIndexes == nil {
242
+ if e .tags == nil {
232
243
return nil
233
244
}
234
- m := make (map [int ]string , len (e .tagIndexes ))
235
- for tag , index := range e .tagIndexes {
236
- m [index ] = tag
237
- }
238
- result := make ([]string , 0 , len (m ))
239
- for i , j := 0 , len (m ); i < j ; i ++ {
240
- if tag , ok := m [i ]; ok {
241
- result = append (result , tag )
242
- }
243
- }
245
+ result := make ([]string , len (e .tags ))
246
+ copy (result , e .tags )
244
247
return result
245
248
}
246
249
247
250
// PC returns program counters.
248
251
func (e * Erf ) PC () []uintptr {
249
- result := make ([]uintptr , len (e .pc ))
250
- copy (result , e .pc )
252
+ src := e .pc [e .top :]
253
+ result := make ([]uintptr , len (src ))
254
+ copy (result , src )
251
255
return result
252
256
}
253
257
254
258
// StackTrace returns a StackTrace of Erf.
255
259
func (e * Erf ) StackTrace () * StackTrace {
256
- return NewStackTrace (e .pc ... )
260
+ return NewStackTrace (e .pc [e .top :]... )
261
+ }
262
+
263
+ // Top sets top of program counters in Erf.
264
+ // If the argument top is negative it returns just old value and doesn't set, otherwise sets and returns old value.
265
+ func (e * Erf ) Top (top int ) int {
266
+ if top < 0 {
267
+ return e .top
268
+ }
269
+ result := e .top
270
+ if top > len (e .pc ) {
271
+ panic ("top out of range" )
272
+ }
273
+ e .top = top
274
+ return result
257
275
}
258
276
259
277
func (e * Erf ) initialize (skip int ) {
0 commit comments