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 }