package logger // FuncHandler returns a Handler that logs records with the given // function. import ( "fmt" "reflect" "sync" "time" ) // 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 decleration 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 { value, err := evaluateLazy(lz) if err != nil { r.Context[errorKey] = "bad lazy " + k } else { v = value } } } return h.Log(r) }) } func evaluateLazy(lz Lazy) (interface{}, error) { t := reflect.TypeOf(lz.Fn) if t.Kind() != reflect.Func { return nil, fmt.Errorf("INVALID_LAZY, not func: %+v", lz.Fn) } if t.NumIn() > 0 { return nil, fmt.Errorf("INVALID_LAZY, func takes args: %+v", lz.Fn) } if t.NumOut() == 0 { return nil, fmt.Errorf("INVALID_LAZY, no func return val: %+v", lz.Fn) } value := reflect.ValueOf(lz.Fn) results := value.Call([]reflect.Value{}) if len(results) == 1 { return results[0].Interface(), nil } else { values := make([]interface{}, len(results)) for i, v := range results { values[i] = v.Interface() } return values, nil } }