github.com/vnforks/kid/v5@v5.22.1-0.20200408055009-b89d99c65676/mlog/log.go (about) 1 // Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. 2 // See LICENSE.txt for license information. 3 4 package mlog 5 6 import ( 7 "io" 8 "log" 9 "os" 10 11 "go.uber.org/zap" 12 "go.uber.org/zap/zapcore" 13 "gopkg.in/natefinch/lumberjack.v2" 14 ) 15 16 const ( 17 // Very verbose messages for debugging specific issues 18 LevelDebug = "debug" 19 // Default log level, informational 20 LevelInfo = "info" 21 // Warnings are messages about possible issues 22 LevelWarn = "warn" 23 // Errors are messages about things we know are problems 24 LevelError = "error" 25 ) 26 27 // Type and function aliases from zap to limit the libraries scope into MM code 28 type Field = zapcore.Field 29 30 var Int64 = zap.Int64 31 var Int32 = zap.Int32 32 var Int = zap.Int 33 var Uint32 = zap.Uint32 34 var String = zap.String 35 var Any = zap.Any 36 var Err = zap.Error 37 var NamedErr = zap.NamedError 38 var Bool = zap.Bool 39 var Duration = zap.Duration 40 41 type LoggerConfiguration struct { 42 EnableConsole bool 43 ConsoleJson bool 44 ConsoleLevel string 45 EnableFile bool 46 FileJson bool 47 FileLevel string 48 FileLocation string 49 } 50 51 type Logger struct { 52 zap *zap.Logger 53 consoleLevel zap.AtomicLevel 54 fileLevel zap.AtomicLevel 55 } 56 57 func getZapLevel(level string) zapcore.Level { 58 switch level { 59 case LevelInfo: 60 return zapcore.InfoLevel 61 case LevelWarn: 62 return zapcore.WarnLevel 63 case LevelDebug: 64 return zapcore.DebugLevel 65 case LevelError: 66 return zapcore.ErrorLevel 67 default: 68 return zapcore.InfoLevel 69 } 70 } 71 72 func makeEncoder(json bool) zapcore.Encoder { 73 encoderConfig := zap.NewProductionEncoderConfig() 74 if json { 75 return zapcore.NewJSONEncoder(encoderConfig) 76 } 77 78 encoderConfig.EncodeTime = zapcore.ISO8601TimeEncoder 79 return zapcore.NewConsoleEncoder(encoderConfig) 80 } 81 82 func NewLogger(config *LoggerConfiguration) *Logger { 83 cores := []zapcore.Core{} 84 logger := &Logger{ 85 consoleLevel: zap.NewAtomicLevelAt(getZapLevel(config.ConsoleLevel)), 86 fileLevel: zap.NewAtomicLevelAt(getZapLevel(config.FileLevel)), 87 } 88 89 if config.EnableConsole { 90 writer := zapcore.Lock(os.Stderr) 91 core := zapcore.NewCore(makeEncoder(config.ConsoleJson), writer, logger.consoleLevel) 92 cores = append(cores, core) 93 } 94 95 if config.EnableFile { 96 writer := zapcore.AddSync(&lumberjack.Logger{ 97 Filename: config.FileLocation, 98 MaxSize: 100, 99 Compress: true, 100 }) 101 core := zapcore.NewCore(makeEncoder(config.FileJson), writer, logger.fileLevel) 102 cores = append(cores, core) 103 } 104 105 combinedCore := zapcore.NewTee(cores...) 106 107 logger.zap = zap.New(combinedCore, 108 zap.AddCaller(), 109 ) 110 111 return logger 112 } 113 114 func (l *Logger) ChangeLevels(config *LoggerConfiguration) { 115 l.consoleLevel.SetLevel(getZapLevel(config.ConsoleLevel)) 116 l.fileLevel.SetLevel(getZapLevel(config.FileLevel)) 117 } 118 119 func (l *Logger) SetConsoleLevel(level string) { 120 l.consoleLevel.SetLevel(getZapLevel(level)) 121 } 122 123 func (l *Logger) With(fields ...Field) *Logger { 124 newlogger := *l 125 newlogger.zap = newlogger.zap.With(fields...) 126 return &newlogger 127 } 128 129 func (l *Logger) StdLog(fields ...Field) *log.Logger { 130 return zap.NewStdLog(l.With(fields...).zap.WithOptions(getStdLogOption())) 131 } 132 133 // StdLogAt returns *log.Logger which writes to supplied zap logger at required level. 134 func (l *Logger) StdLogAt(level string, fields ...Field) (*log.Logger, error) { 135 return zap.NewStdLogAt(l.With(fields...).zap.WithOptions(getStdLogOption()), getZapLevel(level)) 136 } 137 138 // StdLogWriter returns a writer that can be hooked up to the output of a golang standard logger 139 // anything written will be interpreted as log entries accordingly 140 func (l *Logger) StdLogWriter() io.Writer { 141 newLogger := *l 142 newLogger.zap = newLogger.zap.WithOptions(zap.AddCallerSkip(4), getStdLogOption()) 143 f := newLogger.Info 144 return &loggerWriter{f} 145 } 146 147 func (l *Logger) WithCallerSkip(skip int) *Logger { 148 newlogger := *l 149 newlogger.zap = newlogger.zap.WithOptions(zap.AddCallerSkip(skip)) 150 return &newlogger 151 } 152 153 // Made for the plugin interface, wraps mlog in a simpler interface 154 // at the cost of performance 155 func (l *Logger) Sugar() *SugarLogger { 156 return &SugarLogger{ 157 wrappedLogger: l, 158 zapSugar: l.zap.Sugar(), 159 } 160 } 161 162 func (l *Logger) Debug(message string, fields ...Field) { 163 l.zap.Debug(message, fields...) 164 } 165 166 func (l *Logger) Info(message string, fields ...Field) { 167 l.zap.Info(message, fields...) 168 } 169 170 func (l *Logger) Warn(message string, fields ...Field) { 171 l.zap.Warn(message, fields...) 172 } 173 174 func (l *Logger) Error(message string, fields ...Field) { 175 l.zap.Error(message, fields...) 176 } 177 178 func (l *Logger) Critical(message string, fields ...Field) { 179 l.zap.Error(message, fields...) 180 }