- Replace `interface{}` with `any` type alias across all packages
- Use built-in `min()`/`max()` for parameter clamping
- Use `slices.SortFunc`, `slices.Min`, `slices.Max` for cleaner code
- Use `strings.Cut()` for simpler string parsing in auth middleware
- Use `errors.Is()` for proper error comparison in handlers
- Update dependencies: golang.org/x/image 0.37.0 -> 0.38.0
- Add Wire code generation guidelines to ARCHITECTURE.md
- Disable Go cache in CI build workflow
206 lines
5.7 KiB
Go
206 lines
5.7 KiB
Go
package service
|
||
|
||
import (
|
||
"context"
|
||
"time"
|
||
|
||
"carrot_bbs/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
|
||
}
|