...
1 package emperror
2
3 import (
4 "fmt"
5 "io"
6 )
7
8
9
10
11
12
13 func With(err error, keyvals ...interface{}) error {
14 if err == nil {
15 return nil
16 }
17
18 if len(keyvals) == 0 {
19 return err
20 }
21
22 var kvs []interface{}
23
24
25 if c, ok := err.(*withContext); ok {
26 err = c.err
27
28 kvs = append(kvs, c.keyvals...)
29
30 if len(kvs)%2 != 0 {
31 kvs = append(kvs, nil)
32 }
33 }
34
35 kvs = append(kvs, keyvals...)
36
37 if len(kvs)%2 != 0 {
38 kvs = append(kvs, nil)
39 }
40
41
42
43
44 return &withContext{
45 err: err,
46 keyvals: kvs[:len(kvs):len(kvs)],
47 }
48 }
49
50
51 func Context(err error) []interface{} {
52 type contextor interface {
53 Context() []interface{}
54 }
55
56 var kvs []interface{}
57
58 ForEachCause(err, func(err error) bool {
59 if cerr, ok := err.(contextor); ok {
60 kvs = append(cerr.Context(), kvs...)
61 }
62
63 return true
64 })
65
66 return kvs
67 }
68
69
70 type withContext struct {
71 err error
72 keyvals []interface{}
73 }
74
75 func (w *withContext) Error() string {
76 return w.err.Error()
77 }
78
79
80 func (w *withContext) Context() []interface{} {
81 return w.keyvals
82 }
83
84 func (w *withContext) Cause() error {
85 return w.err
86 }
87
88 func (w *withContext) Format(s fmt.State, verb rune) {
89 switch verb {
90 case 'v':
91 if s.Flag('+') {
92 _, _ = fmt.Fprintf(s, "%+v", w.Cause())
93 return
94 }
95
96 fallthrough
97
98 case 's':
99 _, _ = io.WriteString(s, w.Error())
100
101 case 'q':
102 _, _ = fmt.Fprintf(s, "%q", w.Error())
103 }
104 }
105
View as plain text