-
Notifications
You must be signed in to change notification settings - Fork 4
/
fmtwrap.go
154 lines (135 loc) · 3.36 KB
/
fmtwrap.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
package throw
import (
"fmt"
"reflect"
"sync/atomic"
)
var panicFmtFn atomic.Value
type FormatterFunc func(string, interface{}) (msg string, extra interface{}, includeExtra bool)
func GetFormatter() FormatterFunc {
if vv, ok := panicFmtFn.Load().(FormatterFunc); ok {
return vv
}
return nil
}
// SetFormatter sets a formatter to be applied by NewDescription and New
func SetFormatter(fn FormatterFunc) {
if fn == nil {
panic(IllegalValue())
}
panicFmtFn.Store(fn)
}
// NewDescription creates an error with the given description. Log structs can be used
func NewDescription(description interface{}) error {
if description == nil {
return nil
}
if fmtFn := GetFormatter(); fmtFn != nil {
return _wrap(fmtFn("", description))
}
if err, ok := description.(error); ok {
return err
}
return _wrapDesc(description)
}
// New creates an error with the given message text and description. Log structs can be used
func New(msg string, description ...interface{}) error {
return Severe(0, msg, description...)
}
func Severe(severity Severity, msg string, description ...interface{}) error {
if description == nil && msg == "" && severity == 0 {
return nil
}
if fmtFn := GetFormatter(); fmtFn != nil {
return _wrap(fmtFn(msg, description))
}
var err error
if len(description) > 0 {
d0 := description[0]
s := ""
if vv, ok := d0.(logStringer); ok {
s = vv.LogString()
} else {
s = defaultFmt(d0, false)
}
err = fmtWrap{msg: msg, severity: severity, extra: d0, useExtra: msg != s}
} else {
err = fmtWrap{msg: msg, severity: severity}
}
for i := 1; i < len(description); i++ {
if description[i] == nil {
continue
}
err = WithDetails(err, description[i])
}
return err
}
func NewFmt(msg string, errorDescription interface{}, fmtFn FormatterFunc) error {
if fmtFn == nil {
panic(IllegalValue())
}
if errorDescription == nil && msg == "" {
return nil
}
return _wrap(fmtFn(msg, errorDescription))
}
func wrapInternal(errorDescription interface{}) fmtWrap {
if fmtFn := GetFormatter(); fmtFn != nil {
return _wrap(fmtFn("", errorDescription))
}
return _wrapDesc(errorDescription)
}
func _wrapDesc(errorDescription interface{}) fmtWrap {
if vv, ok := errorDescription.(logStringer); ok {
msg := vv.LogString()
return fmtWrap{msg: msg, extra: errorDescription}
}
msg := defaultFmt(errorDescription, true)
return fmtWrap{msg: msg, extra: errorDescription}
}
func _wrap(msg string, extra interface{}, useExtra bool) fmtWrap {
return fmtWrap{msg: msg, extra: extra, useExtra: useExtra}
}
type extraInfo interface {
ExtraInfo() (string, Severity, interface{})
}
func UnwrapExtraInfo(err interface{}) (string, Severity, interface{}, bool) {
if e, ok := err.(extraInfo); ok {
st, sv, ei := e.ExtraInfo()
return st, sv, ei, true
}
return "", 0, nil, false
}
type logStringer interface{ LogString() string }
func defaultFmt(v interface{}, force bool) string {
switch vv := v.(type) {
case fmt.Stringer:
return vv.String()
case error:
return vv.Error()
case string:
return vv
case *string:
if vv != nil {
return *vv
}
case nil:
//
default:
s := ""
t := reflect.TypeOf(v)
switch {
case t.Kind() == reflect.Struct && t.PkgPath() == "":
return fmt.Sprintf("%+v", vv)
case force:
s = fmt.Sprint(vv)
default:
return ""
}
if len(s) == 0 {
s = fmt.Sprintf("%T(%[1]p)", vv)
}
return s
}
return "<nil>"
}