From 2a9d1efba1ffd74286858252a6c73232839df0c7 Mon Sep 17 00:00:00 2001 From: wangjian Date: Wed, 13 Jul 2022 13:24:44 +0800 Subject: [PATCH] init --- go.mod | 14 ++++ logger.go | 266 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 280 insertions(+) create mode 100644 go.mod create mode 100644 logger.go diff --git a/go.mod b/go.mod new file mode 100644 index 0000000..6687895 --- /dev/null +++ b/go.mod @@ -0,0 +1,14 @@ +module logging + +go 1.17 + +require ( + go.uber.org/zap v1.21.0 + gopkg.in/natefinch/lumberjack.v2 v2.0.0 +) + +require ( + github.com/BurntSushi/toml v1.1.0 // indirect + go.uber.org/atomic v1.7.0 // indirect + go.uber.org/multierr v1.6.0 // indirect +) diff --git a/logger.go b/logger.go new file mode 100644 index 0000000..4cde38e --- /dev/null +++ b/logger.go @@ -0,0 +1,266 @@ +package logging + +import ( + "os" + "path/filepath" + "sync" + "time" + + "go.uber.org/zap" + "go.uber.org/zap/zapcore" + "gopkg.in/natefinch/lumberjack.v2" +) + +type ModOptions func(options *Options) + +// Options 日志文件配置选项 +type Options struct { + Path string // 文件保存地方 + Prefix string // 日志文件前缀 + ErrorFileSuffix string // error日志文件后缀 + WarnFileSuffix string // warn日志文件后缀 + InfoFileSuffix string // info日志文件后缀 + DebugFileSuffix string // debug日志文件后缀 + Level zapcore.Level // 日志等级 + MaxSize int // 日志文件大小(M) + MaxBackups int // 最多存在多少个切片文件 + MaxAge int // 保存的最大天数 + Development bool // 是否是开发模式 + zap.Config +} + +var ( + logger *Logger + sp = string(filepath.Separator) + errWS, warnWS, infoWS, debugWS zapcore.WriteSyncer // IO输出 + debugConsoleWS = zapcore.Lock(os.Stdout) // 控制台标准输出 + errorConsoleWS = zapcore.Lock(os.Stderr) +) + +type Logger struct { + *zap.Logger + sync.RWMutex + Opts *Options `json:"opts"` + zapConfig zap.Config + initialized bool +} + +func NewLogger(mod ...ModOptions) *zap.Logger { + logger = &Logger{} + logger.Lock() + defer logger.Unlock() + if logger.initialized { + logger.Info("[NewLogger] logger initEd") + return nil + } + logger.Opts = &Options{ + Path: "", + Prefix: "app", + ErrorFileSuffix: "error.log", + WarnFileSuffix: "warn.log", + InfoFileSuffix: "info.log", + DebugFileSuffix: "debug.log", + Level: zapcore.DebugLevel, + MaxSize: 100, + MaxBackups: 60, + MaxAge: 30, + } + + if logger.Opts.Path == "" { + logger.Opts.Path, _ = filepath.Abs(filepath.Dir(filepath.Join("."))) + logger.Opts.Path += sp + "logs" + sp + } + if logger.Opts.Development { + logger.zapConfig = zap.NewDevelopmentConfig() + logger.zapConfig.EncoderConfig.EncodeTime = timeEncoder + } else { + logger.zapConfig = zap.NewProductionConfig() + logger.zapConfig.EncoderConfig.EncodeTime = timeEncoder + } + if logger.Opts.OutputPaths == nil || len(logger.Opts.OutputPaths) == 0 { + logger.zapConfig.OutputPaths = []string{"stdout"} + } + if logger.Opts.ErrorOutputPaths == nil || len(logger.Opts.ErrorOutputPaths) == 0 { + logger.zapConfig.OutputPaths = []string{"stderr"} + } + for _, fn := range mod { + fn(logger.Opts) + } + logger.zapConfig.Level.SetLevel(logger.Opts.Level) + logger.init() + logger.initialized = true + return logger.Logger +} + +func (logger *Logger) init() { + logger.setSyncs() + var err error + logger.Logger, err = logger.zapConfig.Build(logger.cores()) + if err != nil { + panic(err) + } + defer logger.Logger.Sync() +} + +func (logger *Logger) setSyncs() { + f := func(fN string) zapcore.WriteSyncer { + return zapcore.AddSync(&lumberjack.Logger{ + Filename: logger.Opts.Path + sp + logger.Opts.Prefix + "-" + fN, + MaxSize: logger.Opts.MaxSize, + MaxBackups: logger.Opts.MaxBackups, + MaxAge: logger.Opts.MaxAge, + Compress: true, + LocalTime: true, + }) + } + errWS = f(logger.Opts.ErrorFileSuffix) + warnWS = f(logger.Opts.WarnFileSuffix) + infoWS = f(logger.Opts.InfoFileSuffix) + debugWS = f(logger.Opts.DebugFileSuffix) +} + +func SetMaxSize(MaxSize int) ModOptions { + return func(option *Options) { + option.MaxSize = MaxSize + } +} + +func SetMaxBackups(MaxBackups int) ModOptions { + return func(option *Options) { + option.MaxBackups = MaxBackups + } +} + +func SetMaxAge(MaxAge int) ModOptions { + return func(option *Options) { + option.MaxAge = MaxAge + } +} + +func SetPath(Path string) ModOptions { + return func(option *Options) { + option.Path = Path + } +} + +func SetPrefix(Prefix string) ModOptions { + return func(option *Options) { + option.Prefix = Prefix + } +} + +func SetLevel(Level zapcore.Level) ModOptions { + return func(option *Options) { + option.Level = Level + } +} + +func SetErrorFileSuffix(ErrorFileSuffix string) ModOptions { + return func(option *Options) { + option.ErrorFileSuffix = ErrorFileSuffix + } +} + +func SetWarnFileSuffix(WarnFileSuffix string) ModOptions { + return func(option *Options) { + option.WarnFileSuffix = WarnFileSuffix + } +} + +func SetInfoFileSuffix(InfoFileSuffix string) ModOptions { + return func(option *Options) { + option.InfoFileSuffix = InfoFileSuffix + } +} + +func SetDebugFileSuffix(DebugFileSuffix string) ModOptions { + return func(option *Options) { + option.DebugFileSuffix = DebugFileSuffix + } +} + +func SetDevelopment(Development bool) ModOptions { + return func(option *Options) { + option.Development = Development + } +} + +// getDefaultLogger returns the default logger. +func getDefaultLogger() *Logger { + return logger +} + +// L returns the default logger. +func L() *Logger { + return getDefaultLogger() +} + +func (logger *Logger) cores() zap.Option { + fileEncoder := zapcore.NewJSONEncoder(logger.zapConfig.EncoderConfig) + encoderConfig := zap.NewDevelopmentEncoderConfig() + encoderConfig.EncodeTime = timeEncoder + encoderConfig.EncodeLevel = zapcore.CapitalColorLevelEncoder + consoleEncoder := zapcore.NewConsoleEncoder(zapcore.EncoderConfig{ + TimeKey: "ts", + LevelKey: "level", + NameKey: "logger", + CallerKey: "caller_line", + FunctionKey: zapcore.OmitKey, + MessageKey: "msg", + StacktraceKey: "stacktrace", + LineEnding: " ", + EncodeLevel: encodeLevel, + EncodeTime: encodeTime, + EncodeDuration: zapcore.SecondsDurationEncoder, + EncodeCaller: encodeCaller, + }) + + errPriority := zap.LevelEnablerFunc(func(lvl zapcore.Level) bool { + return lvl == zapcore.ErrorLevel && zapcore.ErrorLevel-logger.zapConfig.Level.Level() > -1 + }) + warnPriority := zap.LevelEnablerFunc(func(lvl zapcore.Level) bool { + return lvl == zapcore.WarnLevel && zapcore.WarnLevel-logger.zapConfig.Level.Level() > -1 + }) + infoPriority := zap.LevelEnablerFunc(func(lvl zapcore.Level) bool { + return lvl == zapcore.InfoLevel && zapcore.InfoLevel-logger.zapConfig.Level.Level() > -1 + }) + debugPriority := zap.LevelEnablerFunc(func(lvl zapcore.Level) bool { + return lvl == zapcore.DebugLevel && zapcore.DebugLevel-logger.zapConfig.Level.Level() > -1 + }) + cores := []zapcore.Core{ + zapcore.NewCore(fileEncoder, errWS, errPriority), + zapcore.NewCore(fileEncoder, warnWS, warnPriority), + zapcore.NewCore(fileEncoder, infoWS, infoPriority), + zapcore.NewCore(fileEncoder, debugWS, debugPriority), + } + if logger.Opts.Development { + cores = append(cores, []zapcore.Core{ + zapcore.NewCore(consoleEncoder, errorConsoleWS, errPriority), + zapcore.NewCore(consoleEncoder, debugConsoleWS, warnPriority), + zapcore.NewCore(consoleEncoder, debugConsoleWS, infoPriority), + zapcore.NewCore(consoleEncoder, debugConsoleWS, debugPriority), + }...) + } + return zap.WrapCore(func(c zapcore.Core) zapcore.Core { + return zapcore.NewTee(cores...) + }) +} + +func timeEncoder(t time.Time, enc zapcore.PrimitiveArrayEncoder) { + enc.AppendString(t.Format("2006-01-02 15:04:05.000")) +} + +// encodeLevel 自定义日志级别显示 +func encodeLevel(level zapcore.Level, enc zapcore.PrimitiveArrayEncoder) { + enc.AppendString("[" + level.CapitalString() + "]") +} + +// encodeTime 自定义时间格式显示 +func encodeTime(t time.Time, enc zapcore.PrimitiveArrayEncoder) { + enc.AppendString("[" + t.Format("2006-01-02 15:04:05.000") + "]") +} + +// encodeCaller 自定义行号显示 +func encodeCaller(caller zapcore.EntryCaller, enc zapcore.PrimitiveArrayEncoder) { + enc.AppendString("[" + caller.TrimmedPath() + "]") +}