-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy patherror_builder.go
188 lines (147 loc) · 4.67 KB
/
error_builder.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
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
package tower
import (
"context"
"fmt"
"time"
)
/*
ErrorBuilder is an interface to create customizable error.
ErrorBuilder by itself is not an error type. You have to call .Freeze() method to create proper Error type.
*/
type ErrorBuilder interface {
/*
Sets the error code for this error.
This is used to identify the error type and how towerhttp will interact with this error.
The default implementation for Tower handles code like this:
The default value, if anything in the error implements CodeHint interface,
use the outermost CodeHint implementer, otherwise fallsback to 500.
`tower.Error` that is generated by tower implements CodeHinter interface,
and thus if the error is wrapped again, the default code for this error will be the code of the wrapped `tower.Error`.
Example:
if err != nil {
return tower.Wrap(err).Code(500).Freeze()
}
*/
Code(i int) ErrorBuilder
/*
Overrides the error message for this error.
In built in implementation, If args are supplied, fmt.Sprintf will be called with s as base string.
*/
Message(s string, args ...any) ErrorBuilder
/*
Sets the origin error for ErrorBuilder. Very unlikely to need to set this because tower.Wrap already wraps the error.
But the api is available to set the origin error.
*/
Error(err error) ErrorBuilder
/*
Sets additional data that will enrich how the error will look.
`tower.Fields` is a type that is well integrated with built-in Messengers.
Using this type as Context value will have the performance more optimized when being marshaled
or provides additional quality of life improvements without having to implement those features
yourself. Use `tower.F` as alias for this type.
In built-in implementation, additional call to .Context() will make additional index, not replacing what you already set.
Example:
tower.Wrap(err).Code(400).Context(tower.F{"foo": "bar"}).Freeze()
*/
Context(ctx ...any) ErrorBuilder
/*
Sets the key for this error. This is how Messenger will use to identify if an error is the same as previous or not.
In tower's built-in implementation, by default, no key is set.
Usually by not setting the key, The Messenger will generate their own.
In built in implementation, If args are supplied, fmt.Sprintf will be called with key as base string.
*/
Key(key string, args ...any) ErrorBuilder
/*
Sets the caller for this error.
In tower's built-in implementation, by default, the caller is the location where you call `tower.Wrap` or `tower.WrapFreeze`
*/
Caller(c Caller) ErrorBuilder
/*
Sets the level for this error.
In tower's built-in implementation, this defaults to ErrorLevel if not set.
*/
Level(lvl Level) ErrorBuilder
/*
Sets the time for this error.
In tower's built-in implementation, this is already set to when tower.Wrap is called.
*/
Time(t time.Time) ErrorBuilder
/*
Freeze this ErrorBuilder, preventing further mutations and set this ErrorBuilder into proper error.
The returned Error is safe for multithreaded usage because of its immutable nature.
*/
Freeze() Error
/*
Logs this error. Implicitly calls .Freeze() on this ErrorBuilder.
*/
Log(ctx context.Context) Error
/*
Notifies this error to Messengers. Implicitly calls .Freeze() on this ErrorBuilder.
*/
Notify(ctx context.Context, opts ...MessageOption) Error
}
type errorBuilder struct {
code int
message string
caller Caller
context []any
key string
level Level
origin error
tower *Tower
time time.Time
}
func (e *errorBuilder) Level(lvl Level) ErrorBuilder {
e.level = lvl
return e
}
func (e *errorBuilder) Caller(c Caller) ErrorBuilder {
e.caller = c
return e
}
func (e *errorBuilder) Code(i int) ErrorBuilder {
e.code = i
return e
}
func (e *errorBuilder) Error(err error) ErrorBuilder {
e.origin = err
return e
}
func (e *errorBuilder) Message(s string, args ...any) ErrorBuilder {
if len(args) > 0 {
e.message = fmt.Sprintf(s, args...)
} else {
e.message = s
}
return e
}
func (e *errorBuilder) Context(ctx ...any) ErrorBuilder {
e.context = append(e.context, ctx...)
return e
}
func (e *errorBuilder) Key(key string, args ...any) ErrorBuilder {
if len(args) > 0 {
e.key = fmt.Sprintf(key, args...)
} else {
e.key = key
}
return e
}
func (e *errorBuilder) Time(t time.Time) ErrorBuilder {
e.time = t
return e
}
func (e *errorBuilder) Freeze() Error {
node := &ErrorNode{inner: e}
if child, ok := e.origin.(*ErrorNode); ok {
node.next = child
child.prev = node
}
return node
}
func (e *errorBuilder) Log(ctx context.Context) Error {
return e.Freeze().Log(ctx)
}
func (e *errorBuilder) Notify(ctx context.Context, opts ...MessageOption) Error {
return e.Freeze().Notify(ctx, opts...)
}