Skip to content

Commit 872a696

Browse files
committed
errors with tags, codes and auto error location like file, method, line
0 parents  commit 872a696

File tree

2 files changed

+251
-0
lines changed

2 files changed

+251
-0
lines changed

error.go

Lines changed: 116 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,116 @@
1+
package errors
2+
3+
import (
4+
"encoding/json"
5+
"errors"
6+
"fmt"
7+
"runtime"
8+
"strings"
9+
)
10+
11+
type Error struct {
12+
s struct{ Message, Name, Code string }
13+
err error
14+
}
15+
16+
func New(message, name, code string, caller ...int) *Error {
17+
if len(caller) == 0 {
18+
caller = append(caller, 1)
19+
}
20+
var err Error
21+
message, name, code = strings.TrimSpace(message), strings.TrimSpace(name), strings.TrimSpace(code)
22+
if name == "" && code == "" {
23+
if p, f, l, ok := runtime.Caller(caller[0]); ok {
24+
name, code = runtime.FuncForPC(p).Name(), fmt.Sprintf("%s@L%d", f[strings.LastIndex(f, "/")+1:], l)
25+
}
26+
}
27+
err.s.Message, err.s.Name, err.s.Code = message, name, code
28+
return &err
29+
}
30+
31+
func Errorf(format string, args ...any) *Error {
32+
var m, n, c = fmt.Errorf(format, args...).Error(), "", ""
33+
if i := strings.Index(m, ":"); i > 0 && !strings.Contains(m[:i], " ") {
34+
n, m = m[:i], m[i+1:]
35+
if k := strings.Index(n, "#"); k >= 0 {
36+
c, n = n[k+1:], n[:k]
37+
}
38+
}
39+
40+
e := New(m, n, c, 2)
41+
42+
// find wrapped error and store it in domain.Error
43+
var s = len(format)
44+
var k int
45+
for i := range format {
46+
if i+2 <= s && format[i:i+2] == "%w" {
47+
e.err = args[k].(error)
48+
break
49+
}
50+
if format[i] == '%' {
51+
k++
52+
}
53+
}
54+
55+
return e
56+
}
57+
58+
func Err(from error) *Error {
59+
var e *Error
60+
if errors.As(from, &e) {
61+
return e
62+
}
63+
return nil
64+
}
65+
66+
func (e *Error) Name() string {
67+
return e.s.Name
68+
}
69+
70+
func (e *Error) Code() string {
71+
return e.s.Code
72+
}
73+
74+
func (e *Error) Message() string {
75+
return e.s.Message
76+
}
77+
78+
func (e *Error) Error() string {
79+
s := fmt.Sprintf("%s#%s: %s", e.s.Name, e.s.Code, e.s.Message)
80+
if s[:3] == "#: " {
81+
s = s[3:]
82+
}
83+
if n := len(s); n > 2 && s[n-2:] == ": " {
84+
s = s[:n-2]
85+
}
86+
if n := len(s); n > 1 && s[n-1:] == "#" {
87+
s = s[:n-1] + ":"
88+
}
89+
return strings.Replace(s, "#:", ":", -1)
90+
}
91+
92+
func (e *Error) Unwrap() error {
93+
return e.err
94+
}
95+
96+
func (e *Error) MarshalJSON() ([]byte, error) {
97+
return json.Marshal(e.s)
98+
}
99+
100+
func ErrL(err error) (o []error) {
101+
o = append(o, err)
102+
for {
103+
//s1 := err.Error()
104+
var err2 error
105+
if err2 = errors.Unwrap(err); err2 == nil {
106+
//fmt.Printf("%T: %s\n", err2, s1)
107+
return
108+
}
109+
110+
//s2 := err2.Error()
111+
//s := strings.Replace(s1, s2, "", -1)
112+
//fmt.Printf("%T: %s\n", err, s)
113+
o = append(o, err2)
114+
err = err2
115+
}
116+
}

error_test.go

Lines changed: 135 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,135 @@
1+
package errors_test
2+
3+
import (
4+
"fmt"
5+
"testing"
6+
7+
"github.com/sokool/errors"
8+
)
9+
10+
func TestErrorf(t *testing.T) {
11+
type scenario struct {
12+
description string
13+
err *errors.Error // given
14+
name, code, message, string string // expects
15+
}
16+
17+
cases := []scenario{
18+
{
19+
description: "empty",
20+
err: errors.Errorf(""),
21+
string: "github.com/sokool/errors_test.TestErrorf#error_test.go@L20",
22+
name: "github.com/sokool/errors_test.TestErrorf",
23+
code: "error_test.go@L20",
24+
},
25+
{
26+
description: "just message",
27+
err: errors.Errorf("hi there"),
28+
string: "github.com/sokool/errors_test.TestErrorf#error_test.go@L27: hi there",
29+
name: "github.com/sokool/errors_test.TestErrorf",
30+
code: "error_test.go@L27",
31+
message: "hi there",
32+
},
33+
{
34+
description: "message with arguments",
35+
err: errors.Errorf("hi there %s", "man"),
36+
string: "github.com/sokool/errors_test.TestErrorf#error_test.go@L35: hi there man",
37+
name: "github.com/sokool/errors_test.TestErrorf",
38+
code: "error_test.go@L35",
39+
message: "hi there man",
40+
},
41+
{
42+
description: "just name",
43+
err: errors.Errorf("test:"),
44+
string: "test:",
45+
name: "test",
46+
},
47+
{
48+
description: "just code",
49+
err: errors.Errorf("#h6b7:"),
50+
string: "#h6b7",
51+
code: "h6b7",
52+
},
53+
{
54+
description: "with name,message",
55+
err: errors.Errorf("test:hi there"),
56+
string: "test: hi there",
57+
name: "test",
58+
message: "hi there",
59+
},
60+
{
61+
description: "with name,code,message",
62+
err: errors.Errorf("email#h1: invalid hostname "),
63+
string: "email#h1: invalid hostname",
64+
name: "email",
65+
code: "h1",
66+
message: "invalid hostname",
67+
},
68+
{
69+
description: "with name,code,message from arguments",
70+
err: errors.Errorf("%s#%s: invalid %s", "email", "h45", "username"),
71+
string: "email#h45: invalid username",
72+
name: "email",
73+
code: "h45",
74+
message: "invalid username",
75+
},
76+
{
77+
description: "with code,message",
78+
err: errors.Errorf("#e87:failed"),
79+
string: "#e87: failed",
80+
code: "e87",
81+
message: "failed",
82+
},
83+
{
84+
description: "with code,name signs in wrong place",
85+
err: errors.Errorf("failed due abc: #triggered"),
86+
name: "github.com/sokool/errors_test.TestErrorf",
87+
string: "github.com/sokool/errors_test.TestErrorf#error_test.go@L85: failed due abc: #triggered",
88+
code: "error_test.go@L85",
89+
message: "failed due abc: #triggered",
90+
},
91+
}
92+
93+
for _, c := range cases {
94+
t.Run(c.description, func(t *testing.T) {
95+
if s := c.err.Name(); s != c.name {
96+
t.Fatalf("expected name `%s`, got `%s`", c.name, s)
97+
}
98+
if s := c.err.Code(); s != c.code {
99+
t.Fatalf("expected code `%s`, got `%s`", c.code, s)
100+
}
101+
if s := c.err.Message(); s != c.message {
102+
t.Fatalf("expected message `%s`, got `%s`", c.message, s)
103+
}
104+
if s := c.err.Error(); s != c.string {
105+
t.Fatalf("expected string `%s`, got `%s`", c.string, s)
106+
}
107+
})
108+
}
109+
}
110+
111+
func TestGetErr(t *testing.T) {
112+
a := errors.Errorf("eloszki")
113+
b := fmt.Errorf("second %w", a)
114+
c := fmt.Errorf("third %w", b)
115+
d := errors.Err(c)
116+
117+
if a != d {
118+
t.Fatal()
119+
}
120+
121+
//a1 := errors.Errorf("#1")
122+
//b1 := fmt.Errorf("#2 %w", a1)
123+
124+
x := errors.Errorf("#4 %s %w %%nio %d", "elo", fmt.Errorf("#3 %w", fmt.Errorf("#2 %w", fmt.Errorf("#1"))), 13)
125+
126+
y := errors.ErrL(x)
127+
fmt.Println("----")
128+
129+
for _, err := range y {
130+
fmt.Println(err)
131+
}
132+
133+
//fmt.Println(errors.Unwrap(d1))
134+
135+
}

0 commit comments

Comments
 (0)