mirror of
https://github.com/kevin-DL/revel-cmd.git
synced 2026-01-11 10:44:28 +00:00
112 lines
2.8 KiB
Go
112 lines
2.8 KiB
Go
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
|
|
}
|