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 }