-
Notifications
You must be signed in to change notification settings - Fork 0
/
wrap_handlers.go
111 lines (91 loc) · 2.76 KB
/
wrap_handlers.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
package logger
// FuncHandler returns a Handler that logs records with the given
// function.
import (
"fmt"
"reflect"
"sync"
"time"
)
// Error is used for constant errors.
type Error string
// Error implements the error interface.
func (e Error) Error() string {
return string(e)
}
const (
ErrNotFunc Error = "not a function"
ErrTakesArgs Error = "takes arguments"
ErrNoReturn Error = "no return value"
)
// Function handler wraps the declared function and returns the handler for it.
func FuncHandler(fn func(r *Record) error) LogHandler {
return funcHandler(fn)
}
// The type declaration for the function.
type funcHandler func(r *Record) error
// The implementation of the Log.
func (h funcHandler) Log(r *Record) error {
return h(r)
}
// This function allows you to do a full declaration for the log,
// it is recommended you use FuncHandler instead.
func HandlerFunc(log func(message string, time time.Time, level LogLevel, call CallStack, context ContextMap) error) LogHandler {
return remoteHandler(log)
}
// The type used for the HandlerFunc.
type remoteHandler func(message string, time time.Time, level LogLevel, call CallStack, context ContextMap) error
// The Log implementation.
func (c remoteHandler) Log(record *Record) error {
return c(record.Message, record.Time, record.Level, record.Call, record.Context)
}
// SyncHandler can be wrapped around a handler to guarantee that
// only a single Log operation can proceed at a time. It's necessary
// for thread-safe concurrent writes.
func SyncHandler(h LogHandler) LogHandler {
var mu sync.Mutex
return FuncHandler(func(r *Record) error {
defer mu.Unlock()
mu.Lock()
return h.Log(r)
})
}
// LazyHandler writes all values to the wrapped handler after evaluating
// any lazy functions in the record's context. It is already wrapped
// around StreamHandler and SyslogHandler in this library, you'll only need
// it if you write your own Handler.
func LazyHandler(h LogHandler) LogHandler {
return FuncHandler(func(r *Record) error {
for k, v := range r.Context {
if lz, ok := v.(Lazy); ok {
_, err := evaluateLazy(lz)
if err != nil {
r.Context[errorKey] = "bad lazy " + k
}
}
}
return h.Log(r)
})
}
func evaluateLazy(lz Lazy) (interface{}, error) {
t := reflect.TypeOf(lz.Fn)
if t.Kind() != reflect.Func {
return nil, fmt.Errorf("%w %+v", ErrNotFunc, lz.Fn)
}
if t.NumIn() > 0 {
return nil, fmt.Errorf("%w %+v", ErrTakesArgs, lz.Fn)
}
if t.NumOut() == 0 {
return nil, fmt.Errorf("%w %+v", ErrNoReturn, lz.Fn)
}
value := reflect.ValueOf(lz.Fn)
results := value.Call([]reflect.Value{})
if len(results) == 1 {
return results[0].Interface(), nil
}
values := make([]interface{}, len(results))
for i, v := range results {
values[i] = v.Interface()
}
return values, nil
}