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

     1  // Copyright 2018 The klaytn Authors
     2  //
     3  // This file is derived from log/logger.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  	"os"
    10  	"runtime"
    11  	"time"
    12  
    13  	"github.com/go-stack/stack"
    14  )
    15  
    16  const (
    17  	timeKey  = "t"
    18  	lvlKey   = "lvl"
    19  	msgKey   = "msg"
    20  	errorKey = "LOG15_ERROR"
    21  )
    22  
    23  type Lvl int
    24  
    25  const (
    26  	LvlCrit Lvl = iota
    27  	LvlError
    28  	LvlWarn
    29  	LvlInfo
    30  	LvlDebug
    31  	LvlTrace
    32  	LvlEnd
    33  )
    34  
    35  // Aligned returns a 5-character string containing the name of a Lvl.
    36  func (l Lvl) AlignedString() string {
    37  	switch l {
    38  	case LvlTrace:
    39  		return "TRACE"
    40  	case LvlDebug:
    41  		return "DEBUG"
    42  	case LvlInfo:
    43  		return "INFO"
    44  	case LvlWarn:
    45  		return "WARN"
    46  	case LvlError:
    47  		return "ERROR"
    48  	case LvlCrit:
    49  		return "CRIT"
    50  	default:
    51  		panic("bad level")
    52  	}
    53  }
    54  
    55  // Strings returns the name of a Lvl.
    56  func (l Lvl) String() string {
    57  	switch l {
    58  	case LvlTrace:
    59  		return "trce"
    60  	case LvlDebug:
    61  		return "dbug"
    62  	case LvlInfo:
    63  		return "info"
    64  	case LvlWarn:
    65  		return "warn"
    66  	case LvlError:
    67  		return "eror"
    68  	case LvlCrit:
    69  		return "crit"
    70  	default:
    71  		panic("bad level")
    72  	}
    73  }
    74  
    75  type Record struct {
    76  	Time     time.Time
    77  	Lvl      Lvl
    78  	Msg      string
    79  	Ctx      []interface{}
    80  	Call     stack.Call
    81  	KeyNames RecordKeyNames
    82  }
    83  
    84  type RecordKeyNames struct {
    85  	Time string
    86  	Msg  string
    87  	Lvl  string
    88  }
    89  
    90  var (
    91  	root          = &log15Logger{[]interface{}{}, new(swapHandler)}
    92  	StdoutHandler = StreamHandler(os.Stdout, LogfmtFormat())
    93  	StderrHandler = StreamHandler(os.Stderr, LogfmtFormat())
    94  )
    95  
    96  // Root returns the root logger
    97  func Root() Logger {
    98  	return root
    99  }
   100  
   101  type log15Logger struct {
   102  	ctx []interface{}
   103  	h   *swapHandler
   104  }
   105  
   106  func (l *log15Logger) write(msg string, lvl Lvl, ctx []interface{}) {
   107  	l.h.Log(&Record{
   108  		Time: time.Now(),
   109  		Lvl:  lvl,
   110  		Msg:  msg,
   111  		Ctx:  newContext(l.ctx, ctx),
   112  		Call: stack.Caller(2),
   113  		KeyNames: RecordKeyNames{
   114  			Time: timeKey,
   115  			Msg:  msgKey,
   116  			Lvl:  lvlKey,
   117  		},
   118  	})
   119  }
   120  
   121  func (l *log15Logger) NewWith(keysAndValues ...interface{}) Logger {
   122  	child := &log15Logger{newContext(l.ctx, keysAndValues), new(swapHandler)}
   123  	child.SetHandler(l.h)
   124  	return child
   125  }
   126  
   127  func (l *log15Logger) newModuleLogger(mi ModuleID) Logger {
   128  	return l.NewWith(module, mi)
   129  }
   130  
   131  func newContext(prefix []interface{}, suffix []interface{}) []interface{} {
   132  	normalizedSuffix := normalize(suffix)
   133  	newCtx := make([]interface{}, len(prefix)+len(normalizedSuffix))
   134  	n := copy(newCtx, prefix)
   135  	copy(newCtx[n:], normalizedSuffix)
   136  	return newCtx
   137  }
   138  
   139  func (l *log15Logger) Trace(msg string, ctx ...interface{}) {
   140  	l.write(msg, LvlTrace, ctx)
   141  }
   142  
   143  func (l *log15Logger) Debug(msg string, ctx ...interface{}) {
   144  	l.write(msg, LvlDebug, ctx)
   145  }
   146  
   147  func (l *log15Logger) Info(msg string, ctx ...interface{}) {
   148  	l.write(msg, LvlInfo, ctx)
   149  }
   150  
   151  func (l *log15Logger) Warn(msg string, ctx ...interface{}) {
   152  	l.write(msg, LvlWarn, ctx)
   153  }
   154  
   155  func (l *log15Logger) Error(msg string, ctx ...interface{}) {
   156  	l.write(msg, LvlError, ctx)
   157  }
   158  
   159  func (l *log15Logger) ErrorWithStack(msg string, ctx ...interface{}) {
   160  	buf := make([]byte, 1024*1024)
   161  	buf = buf[:runtime.Stack(buf, true)]
   162  	msg = string(buf) + "\n\n" + msg
   163  	l.write(msg, LvlError, ctx)
   164  }
   165  
   166  func (l *log15Logger) Crit(msg string, ctx ...interface{}) {
   167  	l.write(msg, LvlCrit, ctx)
   168  	os.Exit(1)
   169  }
   170  
   171  func (l *log15Logger) CritWithStack(msg string, ctx ...interface{}) {
   172  	buf := make([]byte, 1024*1024)
   173  	buf = buf[:runtime.Stack(buf, true)]
   174  	msg = string(buf) + "\n\n" + msg
   175  	l.write(msg, LvlCrit, ctx)
   176  	os.Exit(1)
   177  }
   178  
   179  func (l *log15Logger) GetHandler() Handler {
   180  	return l.h.Get()
   181  }
   182  
   183  func (l *log15Logger) SetHandler(h Handler) {
   184  	l.h.Swap(h)
   185  }
   186  
   187  func normalize(ctx []interface{}) []interface{} {
   188  	// if the caller passed a Ctx object, then expand it
   189  	if len(ctx) == 1 {
   190  		if ctxMap, ok := ctx[0].(Ctx); ok {
   191  			ctx = ctxMap.toArray()
   192  		}
   193  	}
   194  
   195  	// ctx needs to be even because it's a series of key/value pairs
   196  	// no one wants to check for errors on logging functions,
   197  	// so instead of erroring on bad input, we'll just make sure
   198  	// that things are the right length and users can fix bugs
   199  	// when they see the output looks wrong
   200  	if len(ctx)%2 != 0 {
   201  		ctx = append(ctx, nil, errorKey, "Normalized odd number of arguments by adding nil")
   202  	}
   203  
   204  	return ctx
   205  }
   206  
   207  // Lazy allows you to defer calculation of a logged value that is expensive
   208  // to compute until it is certain that it must be evaluated with the given filters.
   209  //
   210  // Lazy may also be used in conjunction with a Logger's New() function
   211  // to generate a child logger which always reports the current value of changing
   212  // state.
   213  //
   214  // You may wrap any function which takes no arguments to Lazy. It may return any
   215  // number of values of any type.
   216  type Lazy struct {
   217  	Fn interface{}
   218  }
   219  
   220  // Ctx is a map of key/value pairs to pass as context to a log function
   221  // Use this only if you really need greater safety around the arguments you pass
   222  // to the logging functions.
   223  type Ctx map[string]interface{}
   224  
   225  func (c Ctx) toArray() []interface{} {
   226  	arr := make([]interface{}, len(c)*2)
   227  
   228  	i := 0
   229  	for k, v := range c {
   230  		arr[i] = k
   231  		arr[i+1] = v
   232  		i += 2
   233  	}
   234  
   235  	return arr
   236  }