package core import ( "app/commons/config" "fmt" rotateLogs "github.com/lestrrat-go/file-rotatelogs" "github.com/spf13/viper" "go.uber.org/zap" "go.uber.org/zap/zapcore" "io" "os" "strings" "time" ) const ( DefaultLog LogTagName = "app" JobLogName LogTagName = "job" ) var loggerConfer *config.Zap func loggerConf() *config.Zap { if loggerConfer == nil { loggerInit() } return loggerConfer } var ( errorLoggerMap = make(map[LogTagName]*zap.Logger) Log *zap.SugaredLogger JobLog *zap.SugaredLogger ) func init() { tags := []LogTagName{DefaultLog, JobLogName} for _, lg := range tags { errorLoggerMap[lg] = newLogger(lg) } Log = errorLoggerMap[DefaultLog].Sugar() JobLog = errorLoggerMap[JobLogName].Sugar() } func loggerInit() { if config.EnvConf().Zap != nil { loggerConfer = config.EnvConf().Zap return } v := viper.New() v.SetDefault("prefix", "AppServer-") v.SetDefault("level", "LowercaseColorLevelEncoder") v.SetDefault("format", "_json") v.SetDefault("director", "logs") v.SetDefault("encode_level", "LowercaseLevelEncoder") v.SetDefault("stacktrace_key", "error") v.SetDefault("max_age", 3) v.SetDefault("rotation_size", 100) v.SetDefault("rotation_count", 3) v.SetDefault("show_line", true) v.SetDefault("log_in_console", true) v.SetDefault("log_output_file", true) if err := v.Unmarshal(&loggerConfer); err != nil { panic(fmt.Errorf("Fatal error config file: %s \n", err)) } } type LogTagName string type logConfTags struct { Tag LogTagName `json:"tag" yaml:"tag"` FileName string `json:"filename" yaml:"filename"` ErrFileName string `json:"errFileName" yaml:"errFileName"` } func getWriter(filename string) io.Writer { // 生成 rotate_logs 的Logger 实际生成的文件名 demo.log.YY mm dd HH hook, err := rotateLogs.New( strings.Replace(filename, ".log", "", -1)+".%Y%m%d%H.log", rotateLogs.WithLinkName(filename), // 根据文件大小切割日志 rotateLogs.WithRotationSize(1024*1024*loggerConf().LogSignSize()), // 每个日志文件大小设置:100M rotateLogs.WithRotationTime(time.Hour*24), // 日志轮询周期 默认1分钟:60秒 rotateLogs.WithRotationCount(loggerConf().LogSaveCount()), // 日志保留份数 // 根据时间分割日志 // rotateLogs.WithMaxAge(time.Hour*24*2), // 保存2天日志 ) if err != nil { panic(err) } return hook } // 设置日志格式 非json可进行堆栈跟踪 func getEncoder() zapcore.Encoder { if loggerConf().Format == "json" || loggerConf().Format == "" { return zapcore.NewJSONEncoder(getEncoderConfig()) } return zapcore.NewConsoleEncoder(getEncoderConfig()) } func getEncoderConfig() zapcore.EncoderConfig { return zapcore.EncoderConfig{ MessageKey: "message", LevelKey: "level", EncodeLevel: loggerConf().ZapEncodeLevel(), TimeKey: "time", NameKey: "logger", CallerKey: "caller", StacktraceKey: loggerConf().StacktraceKey, // "error" LineEnding: zapcore.DefaultLineEnding, EncodeTime: customTimeEncoder, EncodeDuration: zapcore.SecondsDurationEncoder, EncodeCaller: zapcore.ShortCallerEncoder, } } func customTimeEncoder(t time.Time, encoder zapcore.PrimitiveArrayEncoder) { encoder.AppendString(t.Format("2006/01/02-15:04:05.000")) } func NewLogger(tag LogTagName, args ...interface{}) *zap.Logger { if errorLoggerMap[tag] != nil { return errorLoggerMap[tag] } return newLogger(tag, args...) } func newLogger(tag LogTagName, args ...interface{}) *zap.Logger { savePath := fmt.Sprintf("./%s/", loggerConf().Director) if len(args) > 0 { savePath = fmt.Sprintf("./%s/", args[0]) } tagConf := logConfTags{Tag: tag, FileName: fmt.Sprintf("%s.log", tag), ErrFileName: fmt.Sprintf("%s_err.log", tag)} encoder := getEncoder() infoLevel := zap.LevelEnablerFunc(func(lvl zapcore.Level) bool { return lvl >= loggerConf().TransportLevel() }) errorLevel := zap.LevelEnablerFunc(func(lvl zapcore.Level) bool { return lvl >= zapcore.ErrorLevel }) // 获取 info、error日志文件的io.Writer 抽象 getWriter() 在下方实现 infoWriter := getWriter(savePath + tagConf.FileName) errorWriter := getWriter(savePath + tagConf.ErrFileName) cores := make([]zapcore.Core, 0) if loggerConf().LogOutputFile { cores = append(cores, zapcore.NewCore(encoder, zapcore.AddSync(infoWriter), infoLevel)) cores = append(cores, zapcore.NewCore(encoder, zapcore.AddSync(errorWriter), errorLevel)) } if loggerConf().LogInConsole { cores = append(cores, zapcore.NewCore(encoder, zapcore.AddSync(os.Stdout), infoLevel)) } // 最后创建具体的Logger core := zapcore.NewTee(cores...) // 开启开发模式,堆栈跟踪 caller := zap.AddCaller() development := zap.Development() filed := zap.Fields(zap.String("Tag", string(tagConf.Tag))) stackTrace := zap.AddStacktrace(zap.ErrorLevel) // 当错误等级error时 触发堆栈跟踪 log := zap.New(core, caller, stackTrace, development, filed) if loggerConf().ShowLine { log = log.WithOptions(zap.AddCaller()) } errorLoggerMap[tagConf.Tag] = log return errorLoggerMap[tagConf.Tag] }