package logger import ( "os" "path/filepath" "sync" "time" "go.uber.org/zap" "go.uber.org/zap/zapcore" ) var Log *zap.Logger var ( currentDate string mu sync.Mutex envMode string ) // ====================== // 初始化 // ====================== func Init(env string) error { envMode = env logger := buildLogger() Log = logger return nil } // ====================== // 构建 logger // ====================== func buildLogger() *zap.Logger { currentDate = getToday() level := zap.InfoLevel if envMode == "dev" { level = zap.DebugLevel } encoderConfig := zapcore.EncoderConfig{ TimeKey: "time", LevelKey: "level", MessageKey: "msg", CallerKey: "caller", EncodeLevel: zapcore.CapitalLevelEncoder, EncodeTime: timeEncoder, EncodeCaller: zapcore.ShortCallerEncoder, } encoder := zapcore.NewJSONEncoder(encoderConfig) consoleWriter := zapcore.AddSync(os.Stdout) infoWriter := zapcore.AddSync(&dailyWriter{ level: "info", }) errorWriter := zapcore.AddSync(&dailyWriter{ level: "error", }) infoCore := zapcore.NewCore( encoder, zapcore.NewMultiWriteSyncer(consoleWriter, infoWriter), zap.LevelEnablerFunc(func(lvl zapcore.Level) bool { return lvl < zapcore.ErrorLevel && lvl >= level }), ) errorCore := zapcore.NewCore( encoder, zapcore.NewMultiWriteSyncer(consoleWriter, errorWriter), zap.LevelEnablerFunc(func(lvl zapcore.Level) bool { return lvl >= zapcore.ErrorLevel }), ) core := zapcore.NewTee(infoCore, errorCore) return zap.New(core, zap.AddCaller(), zap.AddCallerSkip(1)) } // ====================== // 自定义 Writer(核心) // ====================== type dailyWriter struct { level string file *os.File } func (w *dailyWriter) Write(p []byte) (n int, err error) { mu.Lock() defer mu.Unlock() today := getToday() // 跨天切换 if w.file == nil || today != currentDate { if w.file != nil { _ = w.file.Close() } currentDate = today filename := getLogFilePath(w.level, today) file, err := os.OpenFile(filename, os.O_CREATE|os.O_APPEND|os.O_WRONLY, 0644) if err != nil { return 0, err } w.file = file } return w.file.Write(p) } func (w *dailyWriter) Sync() error { return nil } // ====================== // 工具函数 // ====================== // 获取当天 func getToday() string { return time.Now().Format("2006-01-02") } // 获取日志路径 func getLogFilePath(level, date string) string { dir := filepath.Join("logs", level) // 自动创建目录 _ = os.MkdirAll(dir, os.ModePerm) return filepath.Join(dir, date+".log") } // 时间格式 func timeEncoder(t time.Time, enc zapcore.PrimitiveArrayEncoder) { enc.AppendString(t.Format("2006-01-02 15:04:05")) }