github.com/jd-ly/cmd@v1.0.10/logger/wrap_handlers.go (about) 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 }