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