package utils import ( "fmt" "os" "path/filepath" "time" "go.uber.org/zap" "go.uber.org/zap/zapcore" "gorm.io/gorm" "filestoragesystem/internal/model" ) var logger *zap.Logger // Logger 获取全局日志对象 func Logger() *zap.Logger { if logger == nil { logger, _ = zap.NewProduction() } return logger } // InitLogger 初始化zap日志(控制台 + 可选文件) func InitLogger(level, dir string) (*zap.Logger, error) { lvl := zapcore.InfoLevel _ = lvl.UnmarshalText([]byte(level)) encoderCfg := zap.NewProductionEncoderConfig() encoderCfg.EncodeTime = zapcore.ISO8601TimeEncoder encoderCfg.EncodeLevel = zapcore.CapitalLevelEncoder cores := make([]zapcore.Core, 0, 3) // 控制台 consoleSyncer := zapcore.AddSync(os.Stdout) consoleEncoder := zapcore.NewConsoleEncoder(encoderCfg) cores = append(cores, zapcore.NewCore(consoleEncoder, consoleSyncer, lvl)) // 文件 if dir != "" { if err := os.MkdirAll(dir, 0o755); err == nil { fileSyncer := zapcore.AddSync(&dateRollFile{dir: dir}) fileEncoder := zapcore.NewJSONEncoder(encoderCfg) cores = append(cores, zapcore.NewCore(fileEncoder, fileSyncer, lvl)) } } logger = zap.New(zapcore.NewTee(cores...), zap.AddCaller(), zap.AddCallerSkip(1)) return logger, nil } // dateRollFile 按天滚动的日志文件 type dateRollFile struct { dir string f *os.File day string } func (d *dateRollFile) Write(p []byte) (int, error) { today := time.Now().Format("2006-01-02") if d.f == nil || d.day != today { if d.f != nil { _ = d.f.Close() } path := filepath.Join(d.dir, "app-"+today+".log") f, err := os.OpenFile(path, os.O_CREATE|os.O_APPEND|os.O_WRONLY, 0o644) if err != nil { return 0, err } d.f, d.day = f, today } return d.f.Write(p) } func (d *dateRollFile) Sync() error { if d.f != nil { return d.f.Sync() } return nil } // ---- 系统日志异步落库 ---- var sysLogDB *gorm.DB var sysLogCh chan model.SystemLog // InitSystemLog 初始化系统日志异步写入器 func InitSystemLog(db *gorm.DB) { sysLogDB = db sysLogCh = make(chan model.SystemLog, 256) go func() { for entry := range sysLogCh { if err := sysLogDB.Create(&entry).Error; err != nil { Logger().Error("写入系统日志失败", zap.Error(err)) } } }() } // SystemLog 异步记录一条系统日志 func SystemLog(level, module, message string) { if sysLogCh == nil { return } select { case sysLogCh <- model.SystemLog{Level: level, Module: module, Message: message, CreatedAt: time.Now()}: default: // 队列满则丢弃,避免阻塞业务 } } // SystemLogDetail 异步记录带详情的系统日志 func SystemLogDetail(level, module, message, requestID, ip, extra string) { if sysLogCh == nil { return } select { case sysLogCh <- model.SystemLog{ Level: level, Module: module, Message: message, RequestID: requestID, IP: ip, ExtraData: extra, CreatedAt: time.Now(), }: default: } } // Info 记录info级别系统日志 func Info(module, format string, args ...interface{}) { SystemLog("info", module, fmt.Sprintf(format, args...)) } // Warn 记录warn级别系统日志 func Warn(module, format string, args ...interface{}) { SystemLog("warn", module, fmt.Sprintf(format, args...)) } // Error 记录error级别系统日志 func Error(module, format string, args ...interface{}) { SystemLog("error", module, fmt.Sprintf(format, args...)) }