-
Notifications
You must be signed in to change notification settings - Fork 19
/
handler.go
221 lines (182 loc) · 6.4 KB
/
handler.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
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
package emperror
import (
"context"
"emperror.dev/errors"
)
// ErrorHandler is a generic error handler that allows applications (and libraries) to handle errors
// without worrying about the actual error handling strategy (logging, error tracking service, etc).
type ErrorHandler interface {
// Handle handles an error.
//
// If err is nil, Handle should immediately return.
Handle(err error)
}
// ErrorHandlerContext is an optional interface that MAY be implemented by an ErrorHandler.
// It is similar to ErrorHandler, but it receives a context as the first parameter.
// An implementation MAY extract information from the context and annotate err with it.
//
// ErrorHandlerContext MAY honor the deadline carried by the context, but that's not a hard requirement.
type ErrorHandlerContext interface {
// HandleContext handles an error.
//
// If err is nil, HandleContext should immediately return.
HandleContext(ctx context.Context, err error)
}
// ErrorHandlerFacade is a combination of ErrorHandler and ErrorHandlerContext.
// It's sole purpose is to make the API of the package concise by exposing a common interface type
// for returned handlers. It's not supposed to be used by consumers of this package.
//
// It goes directly against the "Use interfaces, return structs" idiom of Go,
// but at the current phase of the package the smaller API surface makes more sense.
//
// In the future it might get replaced with concrete types.
type ErrorHandlerFacade interface {
ErrorHandler
ErrorHandlerContext
}
// ErrorHandlerSet is a combination of ErrorHandler and ErrorHandlerContext.
// It's sole purpose is to make the API of the package concise by exposing a common interface type
// for returned handlers. It's not supposed to be used by consumers of this package.
//
// It goes directly against the "Use interfaces, return structs" idiom of Go,
// but at the current phase of the package the smaller API surface makes more sense.
//
// In the future it might get replaced with concrete types.
//
// Deprecated: use ErrorHandlerFacade.
type ErrorHandlerSet = ErrorHandlerFacade
func ensureErrorHandlerFacade(handler ErrorHandler) ErrorHandlerFacade {
if handler, ok := handler.(ErrorHandlerFacade); ok {
return handler
}
return ErrorHandlerFunc(handler.Handle)
}
// ErrorHandlers combines a number of error handlers into a single one.
type ErrorHandlers []ErrorHandler
func (h ErrorHandlers) Handle(err error) {
for _, handler := range h {
handler.Handle(err)
}
}
func (h ErrorHandlers) HandleContext(ctx context.Context, err error) {
for _, handler := range h {
if handlerCtx, ok := handler.(ErrorHandlerContext); ok {
handlerCtx.HandleContext(ctx, err)
} else {
handler.Handle(err)
}
}
}
// Close calls Close on the underlying handlers (if there is any closable handler).
func (h ErrorHandlers) Close() error {
if len(h) < 1 {
return nil
}
errs := make([]error, len(h))
for i, handler := range h {
if closer, ok := handler.(interface{ Close() error }); ok {
errs[i] = closer.Close()
}
}
return errors.Combine(errs...)
}
// ErrorHandlerFunc wraps a function and turns it into an ErrorHandler
// if the function's definition matches the interface.
type ErrorHandlerFunc func(err error)
func (h ErrorHandlerFunc) Handle(err error) {
h(err)
}
func (h ErrorHandlerFunc) HandleContext(_ context.Context, err error) {
h(err)
}
// ErrorHandlerContextFunc wraps a function and turns it into an ErrorHandlerContext
// if the function's definition matches the interface.
type ErrorHandlerContextFunc func(ctx context.Context, err error)
func (h ErrorHandlerContextFunc) Handle(err error) {
h(context.Background(), err)
}
func (h ErrorHandlerContextFunc) HandleContext(ctx context.Context, err error) {
h(ctx, err)
}
// NoopHandler is a no-op error handler that discards all received errors.
//
// It implements both ErrorHandler and ErrorHandlerContext interfaces.
type NoopHandler struct{}
func (NoopHandler) Handle(_ error) {}
func (NoopHandler) HandleContext(_ context.Context, _ error) {}
// Handler is a generic error handler. It allows applications (and libraries) to handle errors
// without worrying about the actual error handling strategy (logging, error tracking service, etc).
//
// Deprecated: use ErrorHandler instead.
type Handler interface {
// Handle handles an error.
Handle(err error)
}
// ContextAwareHandler is similar to Handler, except it receives a context as well.
// It is useful in request terminal error handling situations.
// An implementation MAY extract information from the context and annotate err with it.
//
// Deprecated: user ErrorHandlerContext instead.
type ContextAwareHandler interface {
// Handle handles an error.
Handle(ctx context.Context, err error)
}
// Handlers collects a number of error handlers into a single one.
//
// Deprecated: use ErrorHandlers instead.
type Handlers []Handler
func (h Handlers) Handle(err error) {
for _, handler := range h {
handler.Handle(err)
}
}
// Close calls Close on the underlying handlers (if there is any closable handler).
func (h Handlers) Close() error {
if len(h) < 1 {
return nil
}
errs := make([]error, len(h))
for i, handler := range h {
if closer, ok := handler.(interface{ Close() error }); ok {
errs[i] = closer.Close()
}
}
return errors.Combine(errs...)
}
// HandlerFunc wraps a function and turns it into an error handler.
//
// Deprecated: use ErrorHandlerFunc.
type HandlerFunc func(err error)
// Handle calls the underlying function.
func (h HandlerFunc) Handle(err error) {
h(err)
}
// Handle handles an error (if one occurred).
//
// Deprecated: no replacement. ErrorHandler should return if err is nil.
func Handle(handler Handler, err error) {
if err != nil {
handler.Handle(err)
}
}
// NewNoopHandler creates a no-op error handler that discards all received errors.
// Useful in examples and as a fallback error handler.
//
// Deprecated: use NoopHandler.
func NewNoopHandler() Handler {
return NoopHandler{}
}
// MakeContextAware wraps an error handler and turns it into a ContextAwareHandler.
//
// Deprecated: no replacement at this time.
func MakeContextAware(handler Handler) ContextAwareHandler {
return &contextAwareHandler{handler}
}
// contextAwareHandler wraps an error handler and turns it into a ContextAwareHandler.
type contextAwareHandler struct {
handler Handler
}
// Handle calls the underlying error handler.
func (h contextAwareHandler) Handle(_ context.Context, err error) {
h.handler.Handle(err)
}