Merge "Add INFO.yaml"
[iec.git] / src / foundation / api / revel / logger / wrap_handlers.go
1 package logger
2
3 // FuncHandler returns a Handler that logs records with the given
4 // function.
5 import (
6         "fmt"
7         "reflect"
8         "sync"
9         "time"
10 )
11
12 // Function handler wraps the declared function and returns the handler for it
13 func FuncHandler(fn func(r *Record) error) LogHandler {
14         return funcHandler(fn)
15 }
16
17 // The type decleration for the function
18 type funcHandler func(r *Record) error
19
20 // The implementation of the Log
21 func (h funcHandler) Log(r *Record) error {
22         return h(r)
23 }
24
25 // This function allows you to do a full declaration for the log,
26 // it is recommended you use FuncHandler instead
27 func HandlerFunc(log func(message string, time time.Time, level LogLevel, call CallStack, context ContextMap) error) LogHandler {
28         return remoteHandler(log)
29 }
30
31 // The type used for the HandlerFunc
32 type remoteHandler func(message string, time time.Time, level LogLevel, call CallStack, context ContextMap) error
33
34 // The Log implementation
35 func (c remoteHandler) Log(record *Record) error {
36         return c(record.Message, record.Time, record.Level, record.Call, record.Context)
37 }
38
39 // SyncHandler can be wrapped around a handler to guarantee that
40 // only a single Log operation can proceed at a time. It's necessary
41 // for thread-safe concurrent writes.
42 func SyncHandler(h LogHandler) LogHandler {
43         var mu sync.Mutex
44         return FuncHandler(func(r *Record) error {
45                 defer mu.Unlock()
46                 mu.Lock()
47                 return h.Log(r)
48         })
49 }
50
51 // LazyHandler writes all values to the wrapped handler after evaluating
52 // any lazy functions in the record's context. It is already wrapped
53 // around StreamHandler and SyslogHandler in this library, you'll only need
54 // it if you write your own Handler.
55 func LazyHandler(h LogHandler) LogHandler {
56         return FuncHandler(func(r *Record) error {
57                 for k, v := range r.Context {
58                         if lz, ok := v.(Lazy); ok {
59                                 value, err := evaluateLazy(lz)
60                                 if err != nil {
61                                         r.Context[errorKey] = "bad lazy " + k
62                                 } else {
63                                         v = value
64                                 }
65                         }
66                 }
67
68                 return h.Log(r)
69         })
70 }
71
72 func evaluateLazy(lz Lazy) (interface{}, error) {
73         t := reflect.TypeOf(lz.Fn)
74
75         if t.Kind() != reflect.Func {
76                 return nil, fmt.Errorf("INVALID_LAZY, not func: %+v", lz.Fn)
77         }
78
79         if t.NumIn() > 0 {
80                 return nil, fmt.Errorf("INVALID_LAZY, func takes args: %+v", lz.Fn)
81         }
82
83         if t.NumOut() == 0 {
84                 return nil, fmt.Errorf("INVALID_LAZY, no func return val: %+v", lz.Fn)
85         }
86
87         value := reflect.ValueOf(lz.Fn)
88         results := value.Call([]reflect.Value{})
89         if len(results) == 1 {
90                 return results[0].Interface(), nil
91         } else {
92                 values := make([]interface{}, len(results))
93                 for i, v := range results {
94                         values[i] = v.Interface()
95                 }
96                 return values, nil
97         }
98 }