github.com/gochain-io/gochain@v2.2.26+incompatible/log/handler.go (about)

     1  package log
     2  
     3  import (
     4  	"fmt"
     5  	"io"
     6  	"net"
     7  	"os"
     8  	"reflect"
     9  	"sync"
    10  
    11  	"github.com/go-stack/stack"
    12  )
    13  
    14  // A Logger prints its log records by writing to a Handler.
    15  // The Handler interface defines where and how log records are written.
    16  // Handlers are composable, providing you great flexibility in combining
    17  // them to achieve the logging structure that suits your applications.
    18  type Handler interface {
    19  	Log(r *Record) error
    20  	// IsLogging returns true if global logging for level is enabled.
    21  	IsLogging(Lvl) bool
    22  }
    23  
    24  // FuncHandler returns a Handler that logs records with the given
    25  // functions.
    26  func FuncHandler(log func(r *Record) error, isLogging func(Lvl) bool) Handler {
    27  	return &funcHandler{
    28  		log:       log,
    29  		isLogging: isLogging,
    30  	}
    31  }
    32  
    33  type funcHandler struct {
    34  	log       func(r *Record) error
    35  	isLogging func(Lvl) bool
    36  }
    37  
    38  func (h funcHandler) Log(r *Record) error {
    39  	return h.log(r)
    40  }
    41  
    42  func (h funcHandler) IsLogging(level Lvl) bool {
    43  	return h.isLogging(level)
    44  }
    45  
    46  // StreamHandler writes log records to an io.Writer
    47  // with the given format. StreamHandler can be used
    48  // to easily begin writing log records to other
    49  // outputs.
    50  //
    51  // StreamHandler wraps itself with LazyHandler and SyncHandler
    52  // to evaluate Lazy objects and perform safe concurrent writes.
    53  func StreamHandler(wr io.Writer, fmtr Format) Handler {
    54  	h := FuncHandler(func(r *Record) error {
    55  		_, err := wr.Write(fmtr.Format(r))
    56  		return err
    57  	}, func(Lvl) bool { return true })
    58  	return LazyHandler(SyncHandler(h))
    59  }
    60  
    61  // SyncHandler can be wrapped around a handler to guarantee that
    62  // only a single Log operation can proceed at a time. It's necessary
    63  // for thread-safe concurrent writes.
    64  func SyncHandler(h Handler) Handler {
    65  	var mu sync.Mutex
    66  	return FuncHandler(func(r *Record) error {
    67  		mu.Lock()
    68  		err := h.Log(r)
    69  		mu.Unlock()
    70  		return err
    71  	}, h.IsLogging)
    72  }
    73  
    74  // FileHandler returns a handler which writes log records to the give file
    75  // using the given format. If the path
    76  // already exists, FileHandler will append to the given file. If it does not,
    77  // FileHandler will create the file with mode 0644.
    78  func FileHandler(path string, fmtr Format) (Handler, error) {
    79  	f, err := os.OpenFile(path, os.O_CREATE|os.O_APPEND|os.O_WRONLY, 0644)
    80  	if err != nil {
    81  		return nil, err
    82  	}
    83  	return closingHandler{f, StreamHandler(f, fmtr)}, nil
    84  }
    85  
    86  // NetHandler opens a socket to the given address and writes records
    87  // over the connection.
    88  func NetHandler(network, addr string, fmtr Format) (Handler, error) {
    89  	conn, err := net.Dial(network, addr)
    90  	if err != nil {
    91  		return nil, err
    92  	}
    93  
    94  	return closingHandler{conn, StreamHandler(conn, fmtr)}, nil
    95  }
    96  
    97  // XXX: closingHandler is essentially unused at the moment
    98  // it's meant for a future time when the Handler interface supports
    99  // a possible Close() operation
   100  type closingHandler struct {
   101  	io.WriteCloser
   102  	Handler
   103  }
   104  
   105  func (h *closingHandler) Close() error {
   106  	return h.WriteCloser.Close()
   107  }
   108  
   109  // FilterHandler returns a Handler that only writes records to the
   110  // wrapped Handler if the given function evaluates true. For example,
   111  // to only log records where the 'err' key is not nil:
   112  //
   113  //    logger.SetHandler(FilterHandler(func(r *Record) bool {
   114  //        for i := 0; i < len(r.Ctx); i += 2 {
   115  //            if r.Ctx[i] == "err" {
   116  //                return r.Ctx[i+1] != nil
   117  //            }
   118  //        }
   119  //        return false
   120  //    }, h))
   121  //
   122  func FilterHandler(fn func(r *Record) bool, h Handler) Handler {
   123  	return FuncHandler(func(r *Record) error {
   124  		if fn(r) {
   125  			return h.Log(r)
   126  		}
   127  		return nil
   128  	}, h.IsLogging)
   129  }
   130  
   131  // LvlFilterHandler returns a Handler that only writes
   132  // records which are less than the given verbosity
   133  // level to the wrapped Handler. For example, to only
   134  // log Error/Crit records:
   135  //
   136  //     log.LvlFilterHandler(log.LvlError, log.StdoutHandler)
   137  //
   138  func LvlFilterHandler(maxLvl Lvl, h Handler) Handler {
   139  	return FilterHandler(func(r *Record) (pass bool) {
   140  		return r.Lvl <= maxLvl
   141  	}, h)
   142  }
   143  
   144  // LazyHandler writes all values to the wrapped handler after evaluating
   145  // any lazy functions in the record's context. It is already wrapped
   146  // around StreamHandler and SyslogHandler in this library, you'll only need
   147  // it if you write your own Handler.
   148  func LazyHandler(h Handler) Handler {
   149  	return FuncHandler(func(r *Record) error {
   150  		// go through the values (odd indices) and reassign
   151  		// the values of any lazy fn to the result of its execution
   152  		hadErr := false
   153  		for i := 1; i < len(r.Ctx); i += 2 {
   154  			lz, ok := r.Ctx[i].(Lazy)
   155  			if ok {
   156  				v, err := evaluateLazy(lz)
   157  				if err != nil {
   158  					hadErr = true
   159  					r.Ctx[i] = err
   160  				} else {
   161  					if cs, ok := v.(stack.CallStack); ok {
   162  						v = cs.TrimBelow(r.Call).TrimRuntime()
   163  					}
   164  					r.Ctx[i] = v
   165  				}
   166  			}
   167  		}
   168  
   169  		if hadErr {
   170  			r.Ctx = append(r.Ctx, errorKey, "bad lazy")
   171  		}
   172  
   173  		return h.Log(r)
   174  	}, h.IsLogging)
   175  }
   176  
   177  func evaluateLazy(lz Lazy) (interface{}, error) {
   178  	t := reflect.TypeOf(lz.Fn)
   179  
   180  	if t.Kind() != reflect.Func {
   181  		return nil, fmt.Errorf("INVALID_LAZY, not func: %+v", lz.Fn)
   182  	}
   183  
   184  	if t.NumIn() > 0 {
   185  		return nil, fmt.Errorf("INVALID_LAZY, func takes args: %+v", lz.Fn)
   186  	}
   187  
   188  	if t.NumOut() == 0 {
   189  		return nil, fmt.Errorf("INVALID_LAZY, no func return val: %+v", lz.Fn)
   190  	}
   191  
   192  	value := reflect.ValueOf(lz.Fn)
   193  	results := value.Call([]reflect.Value{})
   194  	if len(results) == 1 {
   195  		return results[0].Interface(), nil
   196  	} else {
   197  		values := make([]interface{}, len(results))
   198  		for i, v := range results {
   199  			values[i] = v.Interface()
   200  		}
   201  		return values, nil
   202  	}
   203  }
   204  
   205  // DiscardHandler reports success for all writes but does nothing.
   206  // It is useful for dynamically disabling logging at runtime via
   207  // a Logger's SetHandler method.
   208  func DiscardHandler() Handler {
   209  	return FuncHandler(func(r *Record) error {
   210  		return nil
   211  	}, func(Lvl) bool { return false })
   212  }
   213  
   214  // The Must object provides the following Handler creation functions
   215  // which instead of returning an error parameter only return a Handler
   216  // and panic on failure: FileHandler, NetHandler, SyslogHandler, SyslogNetHandler
   217  var Must muster
   218  
   219  func must(h Handler, err error) Handler {
   220  	if err != nil {
   221  		panic(err)
   222  	}
   223  	return h
   224  }
   225  
   226  type muster struct{}
   227  
   228  func (m muster) FileHandler(path string, fmtr Format) Handler {
   229  	return must(FileHandler(path, fmtr))
   230  }
   231  
   232  func (m muster) NetHandler(network, addr string, fmtr Format) Handler {
   233  	return must(NetHandler(network, addr, fmtr))
   234  }