github.com/lingyao2333/mo-zero@v1.4.1/core/logx/writer.go (about) 1 package logx 2 3 import ( 4 "bytes" 5 "encoding/json" 6 "fmt" 7 "io" 8 "log" 9 "path" 10 "sync" 11 "sync/atomic" 12 13 fatihcolor "github.com/fatih/color" 14 "github.com/lingyao2333/mo-zero/core/color" 15 ) 16 17 type ( 18 Writer interface { 19 Alert(v interface{}) 20 Close() error 21 Debug(v interface{}, fields ...LogField) 22 Error(v interface{}, fields ...LogField) 23 Info(v interface{}, fields ...LogField) 24 Severe(v interface{}) 25 Slow(v interface{}, fields ...LogField) 26 Stack(v interface{}) 27 Stat(v interface{}, fields ...LogField) 28 } 29 30 atomicWriter struct { 31 writer Writer 32 lock sync.RWMutex 33 } 34 35 concreteWriter struct { 36 infoLog io.WriteCloser 37 errorLog io.WriteCloser 38 severeLog io.WriteCloser 39 slowLog io.WriteCloser 40 statLog io.WriteCloser 41 stackLog io.Writer 42 } 43 ) 44 45 // NewWriter creates a new Writer with the given io.Writer. 46 func NewWriter(w io.Writer) Writer { 47 lw := newLogWriter(log.New(w, "", flags)) 48 49 return &concreteWriter{ 50 infoLog: lw, 51 errorLog: lw, 52 severeLog: lw, 53 slowLog: lw, 54 statLog: lw, 55 stackLog: lw, 56 } 57 } 58 59 func (w *atomicWriter) Load() Writer { 60 w.lock.RLock() 61 defer w.lock.RUnlock() 62 return w.writer 63 } 64 65 func (w *atomicWriter) Store(v Writer) { 66 w.lock.Lock() 67 defer w.lock.Unlock() 68 w.writer = v 69 } 70 71 func (w *atomicWriter) StoreIfNil(v Writer) Writer { 72 w.lock.Lock() 73 defer w.lock.Unlock() 74 75 if w.writer == nil { 76 w.writer = v 77 } 78 79 return w.writer 80 } 81 82 func (w *atomicWriter) Swap(v Writer) Writer { 83 w.lock.Lock() 84 defer w.lock.Unlock() 85 old := w.writer 86 w.writer = v 87 return old 88 } 89 90 func newConsoleWriter() Writer { 91 outLog := newLogWriter(log.New(fatihcolor.Output, "", flags)) 92 errLog := newLogWriter(log.New(fatihcolor.Error, "", flags)) 93 return &concreteWriter{ 94 infoLog: outLog, 95 errorLog: errLog, 96 severeLog: errLog, 97 slowLog: errLog, 98 stackLog: newLessWriter(errLog, options.logStackCooldownMills), 99 statLog: outLog, 100 } 101 } 102 103 func newFileWriter(c LogConf) (Writer, error) { 104 var err error 105 var opts []LogOption 106 var infoLog io.WriteCloser 107 var errorLog io.WriteCloser 108 var severeLog io.WriteCloser 109 var slowLog io.WriteCloser 110 var statLog io.WriteCloser 111 var stackLog io.Writer 112 113 if len(c.Path) == 0 { 114 return nil, ErrLogPathNotSet 115 } 116 117 opts = append(opts, WithCooldownMillis(c.StackCooldownMillis)) 118 if c.Compress { 119 opts = append(opts, WithGzip()) 120 } 121 if c.KeepDays > 0 { 122 opts = append(opts, WithKeepDays(c.KeepDays)) 123 } 124 if c.MaxBackups > 0 { 125 opts = append(opts, WithMaxBackups(c.MaxBackups)) 126 } 127 if c.MaxSize > 0 { 128 opts = append(opts, WithMaxSize(c.MaxSize)) 129 } 130 131 opts = append(opts, WithRotation(c.Rotation)) 132 133 accessFile := path.Join(c.Path, accessFilename) 134 errorFile := path.Join(c.Path, errorFilename) 135 severeFile := path.Join(c.Path, severeFilename) 136 slowFile := path.Join(c.Path, slowFilename) 137 statFile := path.Join(c.Path, statFilename) 138 139 handleOptions(opts) 140 setupLogLevel(c) 141 142 if infoLog, err = createOutput(accessFile); err != nil { 143 return nil, err 144 } 145 146 if errorLog, err = createOutput(errorFile); err != nil { 147 return nil, err 148 } 149 150 if severeLog, err = createOutput(severeFile); err != nil { 151 return nil, err 152 } 153 154 if slowLog, err = createOutput(slowFile); err != nil { 155 return nil, err 156 } 157 158 if statLog, err = createOutput(statFile); err != nil { 159 return nil, err 160 } 161 162 stackLog = newLessWriter(errorLog, options.logStackCooldownMills) 163 164 return &concreteWriter{ 165 infoLog: infoLog, 166 errorLog: errorLog, 167 severeLog: severeLog, 168 slowLog: slowLog, 169 statLog: statLog, 170 stackLog: stackLog, 171 }, nil 172 } 173 174 func (w *concreteWriter) Alert(v interface{}) { 175 output(w.errorLog, levelAlert, v) 176 } 177 178 func (w *concreteWriter) Close() error { 179 if err := w.infoLog.Close(); err != nil { 180 return err 181 } 182 183 if err := w.errorLog.Close(); err != nil { 184 return err 185 } 186 187 if err := w.severeLog.Close(); err != nil { 188 return err 189 } 190 191 if err := w.slowLog.Close(); err != nil { 192 return err 193 } 194 195 return w.statLog.Close() 196 } 197 198 func (w *concreteWriter) Debug(v interface{}, fields ...LogField) { 199 output(w.infoLog, levelDebug, v, fields...) 200 } 201 202 func (w *concreteWriter) Error(v interface{}, fields ...LogField) { 203 output(w.errorLog, levelError, v, fields...) 204 } 205 206 func (w *concreteWriter) Info(v interface{}, fields ...LogField) { 207 output(w.infoLog, levelInfo, v, fields...) 208 } 209 210 func (w *concreteWriter) Severe(v interface{}) { 211 output(w.severeLog, levelFatal, v) 212 } 213 214 func (w *concreteWriter) Slow(v interface{}, fields ...LogField) { 215 output(w.slowLog, levelSlow, v, fields...) 216 } 217 218 func (w *concreteWriter) Stack(v interface{}) { 219 output(w.stackLog, levelError, v) 220 } 221 222 func (w *concreteWriter) Stat(v interface{}, fields ...LogField) { 223 output(w.statLog, levelStat, v, fields...) 224 } 225 226 type nopWriter struct{} 227 228 func (n nopWriter) Alert(_ interface{}) { 229 } 230 231 func (n nopWriter) Close() error { 232 return nil 233 } 234 235 func (n nopWriter) Debug(_ interface{}, _ ...LogField) { 236 } 237 238 func (n nopWriter) Error(_ interface{}, _ ...LogField) { 239 } 240 241 func (n nopWriter) Info(_ interface{}, _ ...LogField) { 242 } 243 244 func (n nopWriter) Severe(_ interface{}) { 245 } 246 247 func (n nopWriter) Slow(_ interface{}, _ ...LogField) { 248 } 249 250 func (n nopWriter) Stack(_ interface{}) { 251 } 252 253 func (n nopWriter) Stat(_ interface{}, _ ...LogField) { 254 } 255 256 func buildFields(fields ...LogField) []string { 257 var items []string 258 259 for _, field := range fields { 260 items = append(items, fmt.Sprintf("%s=%v", field.Key, field.Value)) 261 } 262 263 return items 264 } 265 266 func combineGlobalFields(fields []LogField) []LogField { 267 globals := globalFields.Load() 268 if globals == nil { 269 return fields 270 } 271 272 return append(globals.([]LogField), fields...) 273 } 274 275 func output(writer io.Writer, level string, val interface{}, fields ...LogField) { 276 fields = combineGlobalFields(fields) 277 278 switch atomic.LoadUint32(&encoding) { 279 case plainEncodingType: 280 writePlainAny(writer, level, val, buildFields(fields...)...) 281 default: 282 entry := make(logEntry) 283 for _, field := range fields { 284 entry[field.Key] = field.Value 285 } 286 entry[timestampKey] = getTimestamp() 287 entry[levelKey] = level 288 entry[contentKey] = val 289 writeJson(writer, entry) 290 } 291 } 292 293 func wrapLevelWithColor(level string) string { 294 var colour color.Color 295 switch level { 296 case levelAlert: 297 colour = color.FgRed 298 case levelError: 299 colour = color.FgRed 300 case levelFatal: 301 colour = color.FgRed 302 case levelInfo: 303 colour = color.FgBlue 304 case levelSlow: 305 colour = color.FgYellow 306 case levelDebug: 307 colour = color.FgYellow 308 case levelStat: 309 colour = color.FgGreen 310 } 311 312 if colour == color.NoColor { 313 return level 314 } 315 316 return color.WithColorPadding(level, colour) 317 } 318 319 func writeJson(writer io.Writer, info interface{}) { 320 if content, err := json.Marshal(info); err != nil { 321 log.Println(err.Error()) 322 } else if writer == nil { 323 log.Println(string(content)) 324 } else { 325 writer.Write(append(content, '\n')) 326 } 327 } 328 329 func writePlainAny(writer io.Writer, level string, val interface{}, fields ...string) { 330 level = wrapLevelWithColor(level) 331 332 switch v := val.(type) { 333 case string: 334 writePlainText(writer, level, v, fields...) 335 case error: 336 writePlainText(writer, level, v.Error(), fields...) 337 case fmt.Stringer: 338 writePlainText(writer, level, v.String(), fields...) 339 default: 340 writePlainValue(writer, level, v, fields...) 341 } 342 } 343 344 func writePlainText(writer io.Writer, level, msg string, fields ...string) { 345 var buf bytes.Buffer 346 buf.WriteString(getTimestamp()) 347 buf.WriteByte(plainEncodingSep) 348 buf.WriteString(level) 349 buf.WriteByte(plainEncodingSep) 350 buf.WriteString(msg) 351 for _, item := range fields { 352 buf.WriteByte(plainEncodingSep) 353 buf.WriteString(item) 354 } 355 buf.WriteByte('\n') 356 if writer == nil { 357 log.Println(buf.String()) 358 return 359 } 360 361 if _, err := writer.Write(buf.Bytes()); err != nil { 362 log.Println(err.Error()) 363 } 364 } 365 366 func writePlainValue(writer io.Writer, level string, val interface{}, fields ...string) { 367 var buf bytes.Buffer 368 buf.WriteString(getTimestamp()) 369 buf.WriteByte(plainEncodingSep) 370 buf.WriteString(level) 371 buf.WriteByte(plainEncodingSep) 372 if err := json.NewEncoder(&buf).Encode(val); err != nil { 373 log.Println(err.Error()) 374 return 375 } 376 377 for _, item := range fields { 378 buf.WriteByte(plainEncodingSep) 379 buf.WriteString(item) 380 } 381 buf.WriteByte('\n') 382 if writer == nil { 383 log.Println(buf.String()) 384 return 385 } 386 387 if _, err := writer.Write(buf.Bytes()); err != nil { 388 log.Println(err.Error()) 389 } 390 }