package service import ( "context" "time" "with_you/internal/repository" "go.uber.org/zap" ) // LogCleanupConfig 日志清理配置 type LogCleanupConfig struct { Enabled bool OperationLog int // 保留天数 LoginLog int DataChangeLog int CleanupTime string // 清理时间,如 "02:00" } // LogCleanupService 日志清理服务接口 type LogCleanupService interface { Start() Stop() CleanupOldLogs(ctx context.Context) error CleanupOperationLogs(ctx context.Context, beforeDate string) error CleanupLoginLogs(ctx context.Context, beforeDate string) error CleanupDataChangeLogs(ctx context.Context, beforeDate string) error } // logCleanupServiceImpl 日志清理服务实现 type logCleanupServiceImpl struct { operationRepo repository.OperationLogRepository loginRepo repository.LoginLogRepository dataChangeRepo repository.DataChangeLogRepository cfg *LogCleanupConfig logger *zap.Logger ctx context.Context cancel context.CancelFunc } // NewLogCleanupService 创建日志清理服务 func NewLogCleanupService( operationRepo repository.OperationLogRepository, loginRepo repository.LoginLogRepository, dataChangeRepo repository.DataChangeLogRepository, cfg *LogCleanupConfig, logger *zap.Logger, ) LogCleanupService { return &logCleanupServiceImpl{ operationRepo: operationRepo, loginRepo: loginRepo, dataChangeRepo: dataChangeRepo, cfg: cfg, logger: logger, } } // Start 启动日志清理服务 func (s *logCleanupServiceImpl) Start() { if !s.cfg.Enabled { s.logger.Info("log cleanup service disabled") return } s.ctx, s.cancel = context.WithCancel(context.Background()) go s.scheduleCleanup() s.logger.Info("log cleanup service started", zap.Int("operation_log_days", s.cfg.OperationLog), zap.Int("login_log_days", s.cfg.LoginLog), zap.Int("data_change_log_days", s.cfg.DataChangeLog), ) } // Stop 停止日志清理服务 func (s *logCleanupServiceImpl) Stop() { if s.cancel != nil { s.cancel() s.logger.Info("log cleanup service stopped") } } // scheduleCleanup 定时调度清理任务 func (s *logCleanupServiceImpl) scheduleCleanup() { for { select { case <-s.ctx.Done(): return default: now := time.Now() nextCleanup := s.getNextCleanupTime(now) duration := nextCleanup.Sub(now) s.logger.Info("next log cleanup scheduled", zap.Time("time", nextCleanup), zap.Duration("in", duration), ) timer := time.NewTimer(duration) select { case <-s.ctx.Done(): timer.Stop() return case <-timer.C: if err := s.CleanupOldLogs(s.ctx); err != nil { s.logger.Error("failed to cleanup old logs", zap.Error(err)) } } } } } // getNextCleanupTime 计算下次清理时间 func (s *logCleanupServiceImpl) getNextCleanupTime(now time.Time) time.Time { cleanupTime, err := time.Parse("15:04", s.cfg.CleanupTime) if err != nil { cleanupTime = time.Date(now.Year(), now.Month(), now.Day(), 2, 0, 0, 0, now.Location()) } nextCleanup := time.Date(now.Year(), now.Month(), now.Day(), cleanupTime.Hour(), cleanupTime.Minute(), 0, 0, now.Location()) if nextCleanup.Before(now) { nextCleanup = nextCleanup.Add(24 * time.Hour) } return nextCleanup } // CleanupOldLogs 清理旧日志 func (s *logCleanupServiceImpl) CleanupOldLogs(ctx context.Context) error { s.logger.Info("starting log cleanup") // 清理操作日志 if err := s.CleanupOperationLogs(ctx, s.getBeforeDate(s.cfg.OperationLog)); err != nil { s.logger.Error("failed to cleanup operation logs", zap.Error(err)) } // 清理登录日志 if err := s.CleanupLoginLogs(ctx, s.getBeforeDate(s.cfg.LoginLog)); err != nil { s.logger.Error("failed to cleanup login logs", zap.Error(err)) } // 清理数据变更日志 if err := s.CleanupDataChangeLogs(ctx, s.getBeforeDate(s.cfg.DataChangeLog)); err != nil { s.logger.Error("failed to cleanup data change logs", zap.Error(err)) } s.logger.Info("log cleanup completed") return nil } // CleanupOperationLogs 清理操作日志 func (s *logCleanupServiceImpl) CleanupOperationLogs(ctx context.Context, beforeDate string) error { result := s.operationRepo.DeleteOldLogs(ctx, beforeDate) s.logger.Info("cleanup operation logs", zap.String("before_date", beforeDate)) return result } // CleanupLoginLogs 清理登录日志 func (s *logCleanupServiceImpl) CleanupLoginLogs(ctx context.Context, beforeDate string) error { result := s.loginRepo.DeleteOldLogs(ctx, beforeDate) s.logger.Info("cleanup login logs", zap.String("before_date", beforeDate)) return result } // CleanupDataChangeLogs 清理数据变更日志 func (s *logCleanupServiceImpl) CleanupDataChangeLogs(ctx context.Context, beforeDate string) error { result := s.dataChangeRepo.DeleteOldLogs(ctx, beforeDate) s.logger.Info("cleanup data change logs", zap.String("before_date", beforeDate)) return result } // getBeforeDate 计算截止日期 func (s *logCleanupServiceImpl) getBeforeDate(days int) string { return time.Now().AddDate(0, 0, -days).Format("2006-01-02") } // LogService 日志服务组合 type LogService struct { OperationLog OperationLogService LoginLog LoginLogService DataChangeLog DataChangeLogService } // NewLogService 创建日志服务组合 func NewLogService( operationLogService OperationLogService, loginLogService LoginLogService, dataChangeLogService DataChangeLogService, ) *LogService { return &LogService{ OperationLog: operationLogService, LoginLog: loginLogService, DataChangeLog: dataChangeLogService, } } // GetLogCleanupServiceFromApp 从应用中获取日志清理服务 func GetLogCleanupServiceFromApp(app any) LogCleanupService { // 这里需要根据实际的app结构来获取 // 暂时返回nil,实际使用时需要实现 return nil }