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  }