package logger import ( "go.uber.org/zap" "go.uber.org/zap/buffer" "go.uber.org/zap/zapcore" "gopkg.in/natefinch/lumberjack.v2" "os" "path" "strings" ) type ( LogConf struct { Path string // 日志路径 Encoder string // 编码器选择 Level *zapcore.Level // 日志级别 MaxSize int // 每个日志文件的最大大小(MB) MaxBackups int // 保留的旧日志文件个数 RotateDays int // 日志文件的最大保留天数 } logItem struct { FileName string Level zap.LevelEnablerFunc } Encoder interface { Config() zapcore.Encoder WithKey(key string) Encoder WithField(key, val string) Encoder Debug(msg string) Debugf(format string, v ...interface{}) Info(msg string) Infof(format string, v ...interface{}) Warn(msg string) Warnf(format string, v ...interface{}) Error(msg string) Errorf(format string, v ...interface{}) Fatal(msg string) Fatalf(format string, v ...interface{}) } ) var ( maxSize = 200 // 每个日志文件最大尺寸200M maxBackups = 2 // 日志文件最多保存20个备份 maxAge = 5 // 保留最大天数 logLevel = zapcore.WarnLevel _logger *zap.Logger _pool = buffer.NewPool() ConsoleEncoder = "console" // 控制台输出 JsonEncoder = "json" // json输出 ) // Init 初始化日志. func Init(conf LogConf) { if conf.Level == nil { conf.Level = &logLevel } if conf.Path == "" { conf.Path = "server.log" } if conf.RotateDays == 0 { conf.RotateDays = 15 } prefix, suffix := getFileSuffixPrefix(conf.Path) logPath := path.Join(prefix + suffix) items := []logItem{ { FileName: logPath, Level: func(level zapcore.Level) bool { return level >= *conf.Level }, }, } NewLogger(items, conf) } // NewLogger 日志. func NewLogger(items []logItem, conf LogConf) { var ( cfg zapcore.Encoder cores []zapcore.Core ) switch conf.Encoder { case JsonEncoder: cfg = NewJsonLog().Config() case ConsoleEncoder: cfg = NewConsoleLog().Config() default: cfg = NewConsoleLog().Config() } if conf.RotateDays == 0 { conf.RotateDays = maxAge } if conf.MaxBackups == 0 { conf.MaxBackups = maxBackups } if conf.MaxSize == 0 { conf.MaxSize = maxSize } for _, v := range items { hook := lumberjack.Logger{ Filename: v.FileName, MaxSize: conf.MaxSize, // 每个日志文件保存的最大尺寸 单位:M MaxBackups: conf.MaxBackups, // 日志文件最多保存多少个备份 MaxAge: conf.RotateDays, // 文件最多保存多少天 Compress: true, // 是否压缩 LocalTime: true, // 备份文件名本地/UTC时间 } core := zapcore.NewCore( cfg, // 编码器配置; zapcore.NewMultiWriteSyncer(zapcore.AddSync(os.Stdout), zapcore.AddSync(&hook)), // 打印到控制台和文件 v.Level, // 日志级别 ) cores = append(cores, core) } // 开启开发模式,堆栈跟踪 caller := zap.AddCaller() // 开发模式 development := zap.Development() // 二次封装 skip := zap.AddCallerSkip(1) // 构造日志 _logger = zap.New(zapcore.NewTee(cores...), caller, development, skip) return } // GetEncoder 获取自定义编码器. func GetEncoder(conf LogConf) Encoder { switch conf.Encoder { case JsonEncoder: return NewJsonLog() case ConsoleEncoder: return NewConsoleLog() default: return NewConsoleLog() } } // GetLogger 获取日志记录器. func GetLogger() *zap.Logger { return _logger } // getFileSuffixPrefix 文件路径切割 func getFileSuffixPrefix(fileName string) (prefix, suffix string) { paths, _ := path.Split(fileName) base := path.Base(fileName) suffix = path.Ext(fileName) prefix = strings.TrimSuffix(base, suffix) prefix = path.Join(paths, prefix) return } // getFilePath 自定义获取文件路径. func getFilePath(ec zapcore.EntryCaller) string { if !ec.Defined { return "undefined" } buf := _pool.Get() buf.AppendString(ec.Function) buf.AppendByte(':') buf.AppendInt(int64(ec.Line)) caller := buf.String() buf.Free() return caller }