github.com/linapex/ethereum-dpos-chinese@v0.0.0-20190316121959-b78b3a4a1ece/log/logger.go (about) 1 2 //<developer> 3 // <name>linapex 曹一峰</name> 4 // <email>linapex@163.com</email> 5 // <wx>superexc</wx> 6 // <qqgroup>128148617</qqgroup> 7 // <url>https://jsq.ink</url> 8 // <role>pku engineer</role> 9 // <date>2019-03-16 12:09:41</date> 10 //</624342646705360896> 11 12 package log 13 14 import ( 15 "fmt" 16 "os" 17 "time" 18 19 "github.com/go-stack/stack" 20 ) 21 22 const timeKey = "t" 23 const lvlKey = "lvl" 24 const msgKey = "msg" 25 const ctxKey = "ctx" 26 const errorKey = "LOG15_ERROR" 27 const skipLevel = 2 28 29 type Lvl int 30 31 const ( 32 LvlCrit Lvl = iota 33 LvlError 34 LvlWarn 35 LvlInfo 36 LvlDebug 37 LvlTrace 38 ) 39 40 //AlignedString返回包含lvl名称的5个字符的字符串。 41 func (l Lvl) AlignedString() string { 42 switch l { 43 case LvlTrace: 44 return "TRACE" 45 case LvlDebug: 46 return "DEBUG" 47 case LvlInfo: 48 return "INFO " 49 case LvlWarn: 50 return "WARN " 51 case LvlError: 52 return "ERROR" 53 case LvlCrit: 54 return "CRIT " 55 default: 56 panic("bad level") 57 } 58 } 59 60 //字符串返回LVL的名称。 61 func (l Lvl) String() string { 62 switch l { 63 case LvlTrace: 64 return "trce" 65 case LvlDebug: 66 return "dbug" 67 case LvlInfo: 68 return "info" 69 case LvlWarn: 70 return "warn" 71 case LvlError: 72 return "eror" 73 case LvlCrit: 74 return "crit" 75 default: 76 panic("bad level") 77 } 78 } 79 80 //lvl from string从字符串名称返回适当的lvl。 81 //用于分析命令行参数和配置文件。 82 func LvlFromString(lvlString string) (Lvl, error) { 83 switch lvlString { 84 case "trace", "trce": 85 return LvlTrace, nil 86 case "debug", "dbug": 87 return LvlDebug, nil 88 case "info": 89 return LvlInfo, nil 90 case "warn": 91 return LvlWarn, nil 92 case "error", "eror": 93 return LvlError, nil 94 case "crit": 95 return LvlCrit, nil 96 default: 97 return LvlDebug, fmt.Errorf("Unknown level: %v", lvlString) 98 } 99 } 100 101 //记录是记录器要求其处理程序写入的内容。 102 type Record struct { 103 Time time.Time 104 Lvl Lvl 105 Msg string 106 Ctx []interface{} 107 Call stack.Call 108 KeyNames RecordKeyNames 109 } 110 111 //当执行写入函数时,recordkeynames存储在记录中。 112 type RecordKeyNames struct { 113 Time string 114 Msg string 115 Lvl string 116 Ctx string 117 } 118 119 //记录器将键/值对写入处理程序 120 type Logger interface { 121 //new返回一个新的记录器,该记录器的上下文加上给定的上下文 122 New(ctx ...interface{}) Logger 123 124 //GetHandler获取与记录器关联的处理程序。 125 GetHandler() Handler 126 127 //sethandler更新记录器以将记录写入指定的处理程序。 128 SetHandler(h Handler) 129 130 //使用上下文键/值对在给定级别记录消息 131 Trace(msg string, ctx ...interface{}) 132 Debug(msg string, ctx ...interface{}) 133 Info(msg string, ctx ...interface{}) 134 Warn(msg string, ctx ...interface{}) 135 Error(msg string, ctx ...interface{}) 136 Crit(msg string, ctx ...interface{}) 137 } 138 139 type logger struct { 140 ctx []interface{} 141 h *swapHandler 142 } 143 144 func (l *logger) write(msg string, lvl Lvl, ctx []interface{}, skip int) { 145 l.h.Log(&Record{ 146 Time: time.Now(), 147 Lvl: lvl, 148 Msg: msg, 149 Ctx: newContext(l.ctx, ctx), 150 Call: stack.Caller(skip), 151 KeyNames: RecordKeyNames{ 152 Time: timeKey, 153 Msg: msgKey, 154 Lvl: lvlKey, 155 Ctx: ctxKey, 156 }, 157 }) 158 } 159 160 func (l *logger) New(ctx ...interface{}) Logger { 161 child := &logger{newContext(l.ctx, ctx), new(swapHandler)} 162 child.SetHandler(l.h) 163 return child 164 } 165 166 func newContext(prefix []interface{}, suffix []interface{}) []interface{} { 167 normalizedSuffix := normalize(suffix) 168 newCtx := make([]interface{}, len(prefix)+len(normalizedSuffix)) 169 n := copy(newCtx, prefix) 170 copy(newCtx[n:], normalizedSuffix) 171 return newCtx 172 } 173 174 func (l *logger) Trace(msg string, ctx ...interface{}) { 175 l.write(msg, LvlTrace, ctx, skipLevel) 176 } 177 178 func (l *logger) Debug(msg string, ctx ...interface{}) { 179 l.write(msg, LvlDebug, ctx, skipLevel) 180 } 181 182 func (l *logger) Info(msg string, ctx ...interface{}) { 183 l.write(msg, LvlInfo, ctx, skipLevel) 184 } 185 186 func (l *logger) Warn(msg string, ctx ...interface{}) { 187 l.write(msg, LvlWarn, ctx, skipLevel) 188 } 189 190 func (l *logger) Error(msg string, ctx ...interface{}) { 191 l.write(msg, LvlError, ctx, skipLevel) 192 } 193 194 func (l *logger) Crit(msg string, ctx ...interface{}) { 195 l.write(msg, LvlCrit, ctx, skipLevel) 196 os.Exit(1) 197 } 198 199 func (l *logger) GetHandler() Handler { 200 return l.h.Get() 201 } 202 203 func (l *logger) SetHandler(h Handler) { 204 l.h.Swap(h) 205 } 206 207 func normalize(ctx []interface{}) []interface{} { 208 //如果调用方传递了CTX对象,则展开它 209 if len(ctx) == 1 { 210 if ctxMap, ok := ctx[0].(Ctx); ok { 211 ctx = ctxMap.toArray() 212 } 213 } 214 215 //CTX必须是偶数,因为它是一系列键/值对 216 //没有人想检查日志功能的错误, 217 //因此,我们不必担心输入错误,只需确保 218 //事情是正确的长度,用户可以修复错误 219 //当他们看到输出看起来错误时 220 if len(ctx)%2 != 0 { 221 ctx = append(ctx, nil, errorKey, "Normalized odd number of arguments by adding nil") 222 } 223 224 return ctx 225 } 226 227 //Lazy允许您延迟计算昂贵的日志值 228 //计算,直到确定必须使用给定的过滤器对其进行评估。 229 // 230 //lazy还可以与记录器的new()函数一起使用。 231 //生成始终报告更改的当前值的子记录器 232 //状态。 233 // 234 //您可以包装任何不带参数的函数。它可以返回任何 235 //任何类型的值的数目。 236 type Lazy struct { 237 Fn interface{} 238 } 239 240 //CTX是作为上下文传递给日志函数的键/值对的映射 241 //只有当你真的需要在你传递的参数周围更大的安全性时才使用这个 242 //到日志功能。 243 type Ctx map[string]interface{} 244 245 func (c Ctx) toArray() []interface{} { 246 arr := make([]interface{}, len(c)*2) 247 248 i := 0 249 for k, v := range c { 250 arr[i] = k 251 arr[i+1] = v 252 i += 2 253 } 254 255 return arr 256 } 257