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