github.com/turingchain2020/turingchain@v1.1.21/common/log/log15/handler.go (about)

     1  // Copyright Turing Corp. 2018 All Rights Reserved.
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  package log15
     6  
     7  import (
     8  	"fmt"
     9  	"io"
    10  	"net"
    11  	"os"
    12  	"reflect"
    13  	"sync"
    14  
    15  	"github.com/go-stack/stack"
    16  )
    17  
    18  // Handler interface defines where and how log records are written.
    19  // A logger prints its log records by writing to a Handler.
    20  // Handlers are composable, providing you great flexibility in combining
    21  // them to achieve the logging structure that suits your applications.
    22  type Handler interface {
    23  	Log(r *Record) error
    24  	MaxLevel() int
    25  	SetMaxLevel(int)
    26  }
    27  
    28  // FuncHandler returns a Handler that logs records with the given
    29  // function.
    30  func FuncHandler(maxLevel int, fn func(r *Record) error) Handler {
    31  	return &handlebase{fn, maxLevel}
    32  }
    33  
    34  type handlebase struct {
    35  	funcHandler func(r *Record) error
    36  	maxLevel    int
    37  }
    38  
    39  func (h *handlebase) Log(r *Record) error {
    40  	return h.funcHandler(r)
    41  }
    42  
    43  func (h *handlebase) MaxLevel() int {
    44  	return h.maxLevel
    45  }
    46  
    47  func (h *handlebase) SetMaxLevel(maxLevel int) {
    48  	h.maxLevel = maxLevel
    49  }
    50  
    51  // StreamHandler writes log records to an io.Writer
    52  // with the given format. StreamHandler can be used
    53  // to easily begin writing log records to other
    54  // outputs.
    55  //
    56  // StreamHandler wraps itself with LazyHandler and SyncHandler
    57  // to evaluate Lazy objects and perform safe concurrent writes.
    58  func StreamHandler(wr io.Writer, fmtr Format) Handler {
    59  	h := FuncHandler(int(LvlDebug), func(r *Record) error {
    60  		_, err := wr.Write(fmtr.Format(r))
    61  		return err
    62  	})
    63  	return LazyHandler(SyncHandler(h))
    64  }
    65  
    66  // SyncHandler can be wrapped around a handler to guarantee that
    67  // only a single Log operation can proceed at a time. It's necessary
    68  // for thread-safe concurrent writes.
    69  func SyncHandler(h Handler) Handler {
    70  	var mu sync.Mutex
    71  	return FuncHandler(h.MaxLevel(), func(r *Record) error {
    72  		mu.Lock()
    73  		err := h.Log(r)
    74  		mu.Unlock()
    75  		return err
    76  	})
    77  }
    78  
    79  // FileHandler returns a handler which writes log records to the give file
    80  // using the given format. If the path
    81  // already exists, FileHandler will append to the given file. If it does not,
    82  // FileHandler will create the file with mode 0644.
    83  func FileHandler(path string, fmtr Format) (Handler, error) {
    84  	f, err := os.OpenFile(path, os.O_CREATE|os.O_APPEND|os.O_WRONLY, 0644)
    85  	if err != nil {
    86  		return nil, err
    87  	}
    88  	return closingHandler{f, StreamHandler(f, fmtr)}, nil
    89  }
    90  
    91  // NetHandler opens a socket to the given address and writes records
    92  // over the connection.
    93  func NetHandler(network, addr string, fmtr Format) (Handler, error) {
    94  	conn, err := net.Dial(network, addr)
    95  	if err != nil {
    96  		return nil, err
    97  	}
    98  
    99  	return closingHandler{conn, StreamHandler(conn, fmtr)}, nil
   100  }
   101  
   102  // XXX: closingHandler is essentially unused at the moment
   103  // it's meant for a future time when the Handler interface supports
   104  // a possible Close() operation
   105  type closingHandler struct {
   106  	io.WriteCloser
   107  	Handler
   108  }
   109  
   110  func (h *closingHandler) Close() error {
   111  	return h.WriteCloser.Close()
   112  }
   113  
   114  // CallerFileHandler returns a Handler that adds the line number and file of
   115  // the calling function to the context with key "caller".
   116  func CallerFileHandler(h Handler) Handler {
   117  	return FuncHandler(h.MaxLevel(), func(r *Record) error {
   118  		r.Ctx = append(r.Ctx, "caller", fmt.Sprint(r.Call))
   119  		return h.Log(r)
   120  	})
   121  }
   122  
   123  // CallerFuncHandler returns a Handler that adds the calling function name to
   124  // the context with key "fn".
   125  func CallerFuncHandler(h Handler) Handler {
   126  	return FuncHandler(h.MaxLevel(), func(r *Record) error {
   127  		r.Ctx = append(r.Ctx, "fn", fmt.Sprintf("%+n", r.Call))
   128  		return h.Log(r)
   129  	})
   130  }
   131  
   132  // CallerStackHandler returns a Handler that adds a stack trace to the context
   133  // with key "stack". The stack trace is formated as a space separated list of
   134  // call sites inside matching []'s. The most recent call site is listed first.
   135  // Each call site is formatted according to format. See the documentation of
   136  // package github.com/go-stack/stack for the list of supported formats.
   137  func CallerStackHandler(format string, h Handler) Handler {
   138  	return FuncHandler(h.MaxLevel(), func(r *Record) error {
   139  		s := stack.Trace().TrimBelow(r.Call).TrimRuntime()
   140  		if len(s) > 0 {
   141  			r.Ctx = append(r.Ctx, "stack", fmt.Sprintf(format, s))
   142  		}
   143  		return h.Log(r)
   144  	})
   145  }
   146  
   147  // FilterHandler returns a Handler that only writes records to the
   148  // wrapped Handler if the given function evaluates true. For example,
   149  // to only log records where the 'err' key is not nil:
   150  //
   151  //    logger.SetHandler(FilterHandler(func(r *Record) bool {
   152  //        for i := 0; i < len(r.Ctx); i += 2 {
   153  //            if r.Ctx[i] == "err" {
   154  //                return r.Ctx[i+1] != nil
   155  //            }
   156  //        }
   157  //        return false
   158  //    }, h))
   159  //
   160  func FilterHandler(fn func(r *Record) bool, h Handler) Handler {
   161  	return FuncHandler(h.MaxLevel(), func(r *Record) error {
   162  		if fn(r) {
   163  			return h.Log(r)
   164  		}
   165  		return nil
   166  	})
   167  }
   168  
   169  // MatchFilterHandler returns a Handler that only writes records
   170  // to the wrapped Handler if the given key in the logged
   171  // context matches the value. For example, to only log records
   172  // from your ui package:
   173  //
   174  //    log.MatchFilterHandler("pkg", "app/ui", log.StdoutHandler)
   175  //
   176  func MatchFilterHandler(key string, value interface{}, h Handler) Handler {
   177  	return FilterHandler(func(r *Record) (pass bool) {
   178  		switch key {
   179  		case r.KeyNames.Lvl:
   180  			return r.Lvl == value
   181  		case r.KeyNames.Time:
   182  			return r.Time == value
   183  		case r.KeyNames.Msg:
   184  			return r.Msg == value
   185  		}
   186  
   187  		for i := 0; i < len(r.Ctx); i += 2 {
   188  			if r.Ctx[i] == key {
   189  				return r.Ctx[i+1] == value
   190  			}
   191  		}
   192  		return false
   193  	}, h)
   194  }
   195  
   196  // LvlFilterHandler returns a Handler that only writes
   197  // records which are less than the given verbosity
   198  // level to the wrapped Handler. For example, to only
   199  // log Error/Crit records:
   200  //
   201  //     log.LvlFilterHandler(log.LvlError, log.StdoutHandler)
   202  //
   203  func LvlFilterHandler(maxLvl Lvl, h Handler) Handler {
   204  	h.SetMaxLevel(int(maxLvl))
   205  	return FilterHandler(func(r *Record) (pass bool) {
   206  		return r.Lvl <= maxLvl
   207  	}, h)
   208  }
   209  
   210  // MultiHandler dispatches any write to each of its handlers.
   211  // This is useful for writing different types of log information
   212  // to different locations. For example, to log to a file and
   213  // standard error:
   214  //
   215  //     log.MultiHandler(
   216  //         log.Must.FileHandler("/var/log/app.log", log.LogfmtFormat()),
   217  //         log.StderrHandler)
   218  //
   219  
   220  func maxLevelHanldes(hs []Handler) int {
   221  	maxLevel := 0
   222  	for _, handle := range hs {
   223  		if handle.MaxLevel() > maxLevel {
   224  			maxLevel = handle.MaxLevel()
   225  		}
   226  	}
   227  	return maxLevel
   228  }
   229  
   230  //MultiHandler ...
   231  func MultiHandler(hs ...Handler) Handler {
   232  	return FuncHandler(maxLevelHanldes(hs), func(r *Record) error {
   233  		for _, h := range hs {
   234  			// what to do about failures?
   235  			h.Log(r)
   236  		}
   237  		return nil
   238  	})
   239  }
   240  
   241  // FailoverHandler writes all log records to the first handler
   242  // specified, but will failover and write to the second handler if
   243  // the first handler has failed, and so on for all handlers specified.
   244  // For example you might want to log to a network socket, but failover
   245  // to writing to a file if the network fails, and then to
   246  // standard out if the file write fails:
   247  //
   248  //     log.FailoverHandler(
   249  //         log.Must.NetHandler("tcp", ":9090", log.JSONFormat()),
   250  //         log.Must.FileHandler("/var/log/app.log", log.LogfmtFormat()),
   251  //         log.StdoutHandler)
   252  //
   253  // All writes that do not go to the first handler will add context with keys of
   254  // the form "failover_err_{idx}" which explain the error encountered while
   255  // trying to write to the handlers before them in the list.
   256  func FailoverHandler(hs ...Handler) Handler {
   257  	return FuncHandler(maxLevelHanldes(hs), func(r *Record) error {
   258  		var err error
   259  		for i, h := range hs {
   260  			err = h.Log(r)
   261  			if err == nil {
   262  				return nil
   263  			}
   264  			r.Ctx = append(r.Ctx, fmt.Sprintf("failover_err_%d", i), err)
   265  		}
   266  		return err
   267  	})
   268  }
   269  
   270  // ChannelHandler writes all records to the given channel.
   271  // It blocks if the channel is full. Useful for async processing
   272  // of log messages, it's used by BufferedHandler.
   273  func ChannelHandler(recs chan<- *Record, maxLevel int) Handler {
   274  	return FuncHandler(maxLevel, func(r *Record) error {
   275  		recs <- r
   276  		return nil
   277  	})
   278  }
   279  
   280  // BufferedHandler writes all records to a buffered
   281  // channel of the given size which flushes into the wrapped
   282  // handler whenever it is available for writing. Since these
   283  // writes happen asynchronously, all writes to a BufferedHandler
   284  // never return an error and any errors from the wrapped handler are ignored.
   285  func BufferedHandler(bufSize int, h Handler) Handler {
   286  	recs := make(chan *Record, bufSize)
   287  	go func() {
   288  		for m := range recs {
   289  			_ = h.Log(m)
   290  		}
   291  	}()
   292  	return ChannelHandler(recs, h.MaxLevel())
   293  }
   294  
   295  // LazyHandler writes all values to the wrapped handler after evaluating
   296  // any lazy functions in the record's context. It is already wrapped
   297  // around StreamHandler and SyslogHandler in this library, you'll only need
   298  // it if you write your own Handler.
   299  func LazyHandler(h Handler) Handler {
   300  	return FuncHandler(h.MaxLevel(), func(r *Record) error {
   301  		// go through the values (odd indices) and reassign
   302  		// the values of any lazy fn to the result of its execution
   303  		hadErr := false
   304  		for i := 1; i < len(r.Ctx); i += 2 {
   305  			lz, ok := r.Ctx[i].(Lazy)
   306  			if ok {
   307  				v, err := evaluateLazy(lz)
   308  				if err != nil {
   309  					hadErr = true
   310  					r.Ctx[i] = err
   311  				} else {
   312  					if cs, ok := v.(stack.CallStack); ok {
   313  						v = cs.TrimBelow(r.Call).TrimRuntime()
   314  					}
   315  					r.Ctx[i] = v
   316  				}
   317  			}
   318  		}
   319  
   320  		if hadErr {
   321  			r.Ctx = append(r.Ctx, errorKey, "bad lazy")
   322  		}
   323  
   324  		return h.Log(r)
   325  	})
   326  }
   327  
   328  func evaluateLazy(lz Lazy) (interface{}, error) {
   329  	t := reflect.TypeOf(lz.Fn)
   330  
   331  	if t.Kind() != reflect.Func {
   332  		return nil, fmt.Errorf("INVALID_LAZY, not func: %+v", lz.Fn)
   333  	}
   334  
   335  	if t.NumIn() > 0 {
   336  		return nil, fmt.Errorf("INVALID_LAZY, func takes args: %+v", lz.Fn)
   337  	}
   338  
   339  	if t.NumOut() == 0 {
   340  		return nil, fmt.Errorf("INVALID_LAZY, no func return val: %+v", lz.Fn)
   341  	}
   342  
   343  	value := reflect.ValueOf(lz.Fn)
   344  	results := value.Call([]reflect.Value{})
   345  	if len(results) == 1 {
   346  		return results[0].Interface(), nil
   347  	}
   348  	values := make([]interface{}, len(results))
   349  	for i, v := range results {
   350  		values[i] = v.Interface()
   351  	}
   352  	return values, nil
   353  }
   354  
   355  // DiscardHandler reports success for all writes but does nothing.
   356  // It is useful for dynamically disabling logging at runtime via
   357  // a Logger's SetHandler method.
   358  func DiscardHandler() Handler {
   359  	return FuncHandler(int(LvlCrit), func(r *Record) error {
   360  		return nil
   361  	})
   362  }
   363  
   364  // Must object provides the following Handler creation functions
   365  // which instead of returning an error parameter only return a Handler
   366  // and panic on failure: FileHandler, NetHandler, SyslogHandler, SyslogNetHandler
   367  var Must muster
   368  
   369  func must(h Handler, err error) Handler {
   370  	if err != nil {
   371  		panic(err)
   372  	}
   373  	return h
   374  }
   375  
   376  type muster struct{}
   377  
   378  func (m muster) FileHandler(path string, fmtr Format) Handler {
   379  	return must(FileHandler(path, fmtr))
   380  }
   381  
   382  func (m muster) NetHandler(network, addr string, fmtr Format) Handler {
   383  	return must(NetHandler(network, addr, fmtr))
   384  }