github.com/klaytn/klaytn@v1.12.1/log/handler.go (about)

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