Skip to content
This repository was archived by the owner on Nov 21, 2023. It is now read-only.

Commit 53665a7

Browse files
Merge pull request #11 from goinsane/develop
v1.2.0
2 parents d0d6273 + c935471 commit 53665a7

File tree

2 files changed

+73
-11
lines changed

2 files changed

+73
-11
lines changed

erf.go

Lines changed: 72 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -5,13 +5,15 @@ import (
55
"bytes"
66
"errors"
77
"fmt"
8+
"os"
89
"strings"
10+
"unicode"
911
"unsafe"
1012
)
1113

1214
var (
1315
// DefaultPCSize defines max length of Erf program counters in PC() method.
14-
DefaultPCSize = int(4096 / unsafe.Sizeof(uintptr(0)))
16+
DefaultPCSize = int(uintptr(os.Getpagesize()) / unsafe.Sizeof(uintptr(0)))
1517
)
1618

1719
// Erf is an error type that wraps the underlying error that stores and formats the stack trace.
@@ -45,10 +47,12 @@ func (e *Erf) Unwrap() error {
4547
//
4648
// For '%x' and '%X':
4749
// %x list all error messages by using indent and show StackTrace of errors by using format '%+s'.
50+
// %+x similar with '%x', also shows tags.
4851
// % x list all error messages by using indent and show StackTrace of errors by using format '% s'.
4952
// %#x list all error messages by using indent and show StackTrace of errors by using format '%#s'.
5053
// % #x list all error messages by using indent and show StackTrace of errors by using format '% #s'.
5154
// %X show the first error message by using indent and show the StackTrace of error by using format '%+s'.
55+
// %+X similar with '%X', also shows tags.
5256
// % X show the first error message by using indent and show the StackTrace of error by using format '% s'.
5357
// %#X show the first error message by using indent and show the StackTrace of error by using format '%#s'.
5458
// % #X show the first error message by using indent and show the StackTrace of error by using format '% #s'.
@@ -79,15 +83,15 @@ func (e *Erf) Format(f fmt.State, verb rune) {
7983
pad, wid, prec := getPadWidPrec(f)
8084
format += fmt.Sprintf("%d.%ds", wid, prec)
8185
padding, indent := bytes.Repeat([]byte{pad}, wid), bytes.Repeat([]byte{pad}, prec)
82-
count := 0
86+
newLine := false
8387
for err := error(e); err != nil; {
88+
if newLine {
89+
buf.WriteRune('\n')
90+
}
91+
newLine = true
8492
if e2, ok := err.(*Erf); ok {
85-
if count > 0 {
86-
buf.WriteRune('\n')
87-
}
88-
count++
8993
if !f.Flag('-') {
90-
for _, line := range strings.Split(e2.err.Error(), "\n") {
94+
for _, line := range strings.Split(e2.Error(), "\n") {
9195
buf.Write(padding)
9296
buf.Write(indent)
9397
buf.WriteString(line)
@@ -96,11 +100,44 @@ func (e *Erf) Format(f fmt.State, verb rune) {
96100
}
97101
buf.WriteString(fmt.Sprintf(format, e2.StackTrace()))
98102
buf.WriteRune('\n')
103+
if f.Flag('+') {
104+
tags := e2.Tags()
105+
if len(tags) > 0 {
106+
buf.Write(padding)
107+
buf.WriteString("* ")
108+
for idx, tag := range tags {
109+
if idx > 0 {
110+
buf.WriteRune(' ')
111+
}
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))))
120+
}
121+
buf.WriteRune('\n')
122+
}
123+
}
99124
buf.Write(padding)
100-
if verb == 'X' {
101-
break
125+
} else {
126+
if !f.Flag('-') {
127+
for _, line := range strings.Split(err.Error(), "\n") {
128+
buf.Write(padding)
129+
buf.Write(indent)
130+
buf.WriteString(line)
131+
buf.WriteRune('\n')
132+
}
133+
buf.Write(padding)
134+
} else {
135+
newLine = false
102136
}
103137
}
138+
if verb == 'X' {
139+
break
140+
}
104141
if wErr, ok := err.(WrappedError); ok {
105142
err = wErr.Unwrap()
106143
} else {
@@ -125,7 +162,7 @@ func (e *Erf) Len() int {
125162

126163
// Arg returns an argument value on the given index. It panics if index is out of range.
127164
func (e *Erf) Arg(index int) interface{} {
128-
if index < 0 || index >= e.Len() {
165+
if index < 0 || index >= len(e.args) {
129166
panic("index out of range")
130167
}
131168
return e.args[index]
@@ -142,6 +179,7 @@ func (e *Erf) Args() []interface{} {
142179
}
143180

144181
// Attach attaches tags to arguments, if arguments are given.
182+
// If tag is "", it passes attaching tag to corresponding argument.
145183
// It panics for given errors:
146184
// args are not using
147185
// tags are already attached
@@ -171,18 +209,41 @@ func (e *Erf) Attach(tags ...string) *Erf {
171209
return e
172210
}
173211

212+
// Attach2 is similar with Attach except that it returns the error interface instead of the Erf pointer.
213+
func (e *Erf) Attach2(tags ...string) error {
214+
return e.Attach(tags...)
215+
}
216+
174217
// Tag returns an argument value on the given tag. It returns nil if tag is not found.
175218
func (e *Erf) Tag(tag string) interface{} {
176219
index := -1
177220
if idx, ok := e.tagIndexes[tag]; ok {
178221
index = idx
179222
}
180-
if index < 0 || index >= e.Len() {
223+
if index < 0 || index >= len(e.args) {
181224
return nil
182225
}
183226
return e.args[index]
184227
}
185228

229+
// Tags returns all tags sequentially. It returns nil if tags are not attached.
230+
func (e *Erf) Tags() []string {
231+
if e.tagIndexes == nil {
232+
return nil
233+
}
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+
}
244+
return result
245+
}
246+
186247
// PC returns program counters.
187248
func (e *Erf) PC() []uintptr {
188249
result := make([]uintptr, len(e.pc))

stack.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ func (c StackCaller) String() string {
2424
// %s just show function and entry without padding and indent.
2525
// %+s show file path, line and pc. padding char '\t', default padding 0, default indent 1.
2626
// % s show file path, line and pc. padding char ' ', default padding 0, default indent 2.
27+
// %+ s exact with '% s'.
2728
// %#s same with '%+s', use file name as file path.
2829
// %+#s exact with '%#s'.
2930
// % #s same with '% s', use file name as file path.

0 commit comments

Comments
 (0)