Skip to content

Commit 6ac87c7

Browse files
committed
[minor] added support for annotation verbs ('%v', '%+v', '%s', '%+s')
1 parent 3118138 commit 6ac87c7

File tree

2 files changed

+67
-17
lines changed

2 files changed

+67
-17
lines changed

errors.go

Lines changed: 61 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22
package errors
33

44
import (
5+
"fmt"
6+
"io"
57
"net/http"
68
"runtime"
79
"strings"
@@ -62,24 +64,41 @@ type Error struct {
6264
func (e *Error) Error() string {
6365
if e.original != nil {
6466
// string concatenation with + is ~100x faster than fmt.Sprintf()
65-
return e.fileLine + " " + e.original.Error()
66-
/*
67-
// use the following code instead of the above return, to avoid nested filename:line
68-
err, _ := e.original.(*Error)
69-
if err != nil {
70-
return err.Error()
67+
return e.fileLine + ": " + e.message + "\n" + e.original.Error()
68+
}
69+
70+
if e.message != "" {
71+
// string concatenation with + is ~100x faster than fmt.Sprintf()
72+
return e.fileLine + ": " + e.message
73+
}
74+
75+
// string concatenation with + is ~100x faster than fmt.Sprintf()
76+
return e.fileLine + ": " + DefaultMessage
77+
}
78+
79+
// ErrorWithoutFileLine prints the final string without the stack trace / file+line number
80+
func (e *Error) ErrorWithoutFileLine() string {
81+
if e.original != nil {
82+
if e.message != "" {
83+
// string concatenation with + is ~100x faster than fmt.Sprintf()
84+
msg := e.message + ": "
85+
if o, ok := e.original.(*Error); ok {
86+
msg += o.ErrorWithoutFileLine()
87+
} else {
88+
msg += e.original.Error()
7189
}
72-
return fmt.Sprintf("%s %s", e.fileLine, e.original.Error())
73-
*/
90+
return msg
91+
}
92+
return e.original.Error()
7493
}
7594

7695
if e.message != "" {
7796
// string concatenation with + is ~100x faster than fmt.Sprintf()
78-
return e.fileLine + " " + e.message
97+
return e.message
7998
}
8099

81100
// string concatenation with + is ~100x faster than fmt.Sprintf()
82-
return e.fileLine + " " + DefaultMessage
101+
return e.fileLine
83102
}
84103

85104
// Message returns the user friendly message stored in the error struct. It will ignore all errors
@@ -101,7 +120,7 @@ func (e *Error) Message() string {
101120
}
102121

103122
if len(messages) > 0 {
104-
return strings.Join(messages, ". ")
123+
return strings.Join(messages, ": ")
105124
}
106125

107126
return e.Error()
@@ -173,6 +192,37 @@ func (e *Error) Type() errType {
173192
return e.eType
174193
}
175194

195+
// Format implements the verbs supported by Error to be used in fmt annotated/formatted strings
196+
/*
197+
%v - the same output as Message(). i.e. recursively get all the custom messages set by user
198+
- if any of the wrapped error is not of type *Error, that will *not* be displayed
199+
%+v - recursively prints all the messages along with the file & line number. Also includes output of `Error()` of
200+
non *Error types.
201+
202+
%s - identical to %v
203+
%+s - recursively prints all the messages without file & line number. Also includes output `Error()` of
204+
non *Error types.
205+
*/
206+
207+
func (e *Error) Format(s fmt.State, verb rune) {
208+
switch verb {
209+
case 'v':
210+
if s.Flag('+') {
211+
io.WriteString(s, e.Error())
212+
} else {
213+
io.WriteString(s, e.Message())
214+
}
215+
case 's':
216+
{
217+
if s.Flag('+') {
218+
io.WriteString(s, e.ErrorWithoutFileLine())
219+
} else {
220+
io.WriteString(s, e.Message())
221+
}
222+
}
223+
}
224+
}
225+
176226
// New returns a new instance of Error with the relavant fields initialized
177227
func New(msg string) *Error {
178228
_, file, line, _ := runtime.Caller(1)

errors_test.go

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ func TestError_Error(t *testing.T) {
5252
eType: TypeInternal,
5353
fileLine: "",
5454
},
55-
want: " hello world",
55+
want: ": hello world",
5656
},
5757
{
5858
name: "single error, no original error, has fileline",
@@ -62,7 +62,7 @@ func TestError_Error(t *testing.T) {
6262
eType: TypeInternal,
6363
fileLine: "/home/user/main.go:60",
6464
},
65-
want: "/home/user/main.go:60 hello world",
65+
want: "/home/user/main.go:60: hello world",
6666
},
6767
{
6868
name: "with original error",
@@ -72,7 +72,7 @@ func TestError_Error(t *testing.T) {
7272
eType: TypeInternal,
7373
fileLine: "/home/user/main.go:60",
7474
},
75-
want: "/home/user/main.go:60 bad error",
75+
want: "/home/user/main.go:60: hello world\nbad error",
7676
},
7777
{
7878
name: "with original error of type *Error",
@@ -82,7 +82,7 @@ func TestError_Error(t *testing.T) {
8282
eType: TypeInternal,
8383
fileLine: "",
8484
},
85-
want: fmt.Sprintf(" %s:%d %s", file, line, sampleErrContent),
85+
want: fmt.Sprintf(": hello world\n%s:%d: %s", file, line, sampleErrContent),
8686
},
8787
}
8888
for _, tt := range tests {
@@ -94,7 +94,7 @@ func TestError_Error(t *testing.T) {
9494
fileLine: tt.fields.fileLine,
9595
}
9696
if got := e.Error(); got != tt.want {
97-
t.Errorf("Error.Error() = %v, want %v", got, tt.want)
97+
t.Errorf("Error.Error() = '%v', want '%v'", got, tt.want)
9898
}
9999
})
100100
}
@@ -256,7 +256,7 @@ func TestError_Message(t *testing.T) {
256256
eType: TypeInternal,
257257
fileLine: "errors.go:87",
258258
},
259-
want: "errors.go:87 unknown error occurred",
259+
want: "errors.go:87: unknown error occurred",
260260
},
261261
{
262262
name: "Nested error with message",

0 commit comments

Comments
 (0)