This repository has been archived by the owner on Aug 14, 2019. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 1
/
handler_context.go
93 lines (72 loc) · 2.76 KB
/
handler_context.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
package emperror
// The implementation bellow is heavily influenced by go-kit's log context.
// HandlerWith returns a new error handler with keyvals context appended to it.
// If the wrapped error handler is already a contextual error handler created by HandlerWith or HandlerWithPrefix
// keyvals is appended to the existing context, but a new error handler is returned.
//
// The created handler will prepend it's own context to the handled errors.
func HandlerWith(handler Handler, keyvals ...interface{}) Handler {
if len(keyvals) == 0 {
return handler
}
kvs, handler := extractHandlerContext(handler)
kvs = append(kvs, keyvals...)
if len(kvs)%2 != 0 {
kvs = append(kvs, nil)
}
// Limiting the capacity of the stored keyvals ensures that a new
// backing array is created if the slice must grow in HandlerWith.
// Using the extra capacity without copying risks a data race.
return newContextualHandler(handler, kvs[:len(kvs):len(kvs)])
}
// HandlerWithPrefix returns a new error handler with keyvals context prepended to it.
// If the wrapped error handler is already a contextual error handler created by HandlerWith or HandlerWithPrefix
// keyvals is prepended to the existing context, but a new error handler is returned.
//
// The created handler will prepend it's own context to the handled errors.
func HandlerWithPrefix(handler Handler, keyvals ...interface{}) Handler {
if len(keyvals) == 0 {
return handler
}
prevkvs, handler := extractHandlerContext(handler)
n := len(prevkvs) + len(keyvals)
if len(keyvals)%2 != 0 {
n++
}
kvs := make([]interface{}, 0, n)
kvs = append(kvs, keyvals...)
if len(kvs)%2 != 0 {
kvs = append(kvs, nil)
}
kvs = append(kvs, prevkvs...)
return newContextualHandler(handler, kvs)
}
// extractHandlerContext extracts the context and optionally the wrapped handler when it's the same container.
func extractHandlerContext(handler Handler) ([]interface{}, Handler) {
var kvs []interface{}
if c, ok := handler.(*contextualHandler); ok {
handler = c.handler
kvs = c.keyvals
}
return kvs, handler
}
// contextualHandler is a Handler implementation returned by HandlerWith or HandlerWithPrefix.
//
// It wraps an error handler and a holds keyvals as the context.
type contextualHandler struct {
handler Handler
keyvals []interface{}
}
// newContextualHandler creates a new *contextualHandler or a struct which is contextual and holds a stack trace.
func newContextualHandler(handler Handler, kvs []interface{}) Handler {
chandler := &contextualHandler{
handler: handler,
keyvals: kvs,
}
return chandler
}
// Handle prepends the handler's context to the error's (if any) and delegates the call to the underlying handler.
func (h *contextualHandler) Handle(err error) {
err = With(err, h.keyvals...)
h.handler.Handle(err)
}