feat: 添加日志管理和敏感词过滤功能

- 新增日志管理模块:操作日志、登录日志、数据变更日志
- 新增敏感词过滤器 (sanitizer)
- 新增日志异步写入管理器
- 新增日志定时清理服务
- 优化帖子相关服务和上传服务
This commit is contained in:
2026-03-15 02:25:10 +08:00
parent d3065b30cc
commit ebd9cb8b04
31 changed files with 2753 additions and 60 deletions

View File

@@ -27,6 +27,7 @@ var HandlerSet = wire.NewSet(
handler.NewAdminCommentHandler,
handler.NewAdminGroupHandler,
handler.NewAdminDashboardHandler,
handler.NewAdminLogHandler,
// 需要特殊处理的 Handler
ProvideUserHandler,
@@ -42,16 +43,47 @@ var HandlerSet = wire.NewSet(
func ProvideUserHandler(
userService service.UserService,
activityService service.UserActivityService,
postService service.PostService,
commentService *service.CommentService,
logService *service.LogService,
) *handler.UserHandler {
return handler.NewUserHandler(userService, activityService)
h := handler.NewUserHandler(userService, activityService)
h.SetLogService(logService)
// 同时设置到其他服务
if ps, ok := postService.(interface{ SetLogService(*service.LogService) }); ok {
ps.SetLogService(logService)
}
if commentService != nil {
commentService.SetLogService(logService)
}
return h
}
// ProvidePostHandler 提供帖子处理器
func ProvidePostHandler(
postService service.PostService,
userService service.UserService,
logService *service.LogService,
) *handler.PostHandler {
return handler.NewPostHandler(postService, userService)
h := handler.NewPostHandler(postService, userService)
if ps, ok := postService.(interface{ SetLogService(*service.LogService) }); ok {
ps.SetLogService(logService)
}
return h
}
// ProvideAdminPostHandler 提供管理端帖子处理器
func ProvideAdminPostHandler(
postService service.AdminPostService,
logService *service.LogService,
) *handler.AdminPostHandler {
h := handler.NewAdminPostHandler(postService)
if ps, ok := postService.(interface{ SetLogService(*service.LogService) }); ok {
ps.SetLogService(logService)
}
return h
}
// ProvideMessageHandler 提供消息处理器

View File

@@ -23,6 +23,11 @@ var RepositorySet = wire.NewSet(
repository.NewVoteRepository,
repository.NewScheduleRepository,
ProvideUserActivityRepository,
// 日志相关仓储
repository.NewOperationLogRepository,
repository.NewLoginLogRepository,
repository.NewDataChangeLogRepository,
)
// ProvideUserActivityRepository 提供用户活跃数据仓储

View File

@@ -1,6 +1,8 @@
package wire
import (
"time"
"carrot_bbs/internal/cache"
"carrot_bbs/internal/config"
"carrot_bbs/internal/grpc/runner"
@@ -48,6 +50,14 @@ var ServiceSet = wire.NewSet(
ProvideAdminCommentService,
ProvideAdminGroupService,
ProvideAdminDashboardService,
// 日志服务
ProvideAsyncLogManager,
ProvideOperationLogService,
ProvideLoginLogService,
ProvideDataChangeLogService,
ProvideLogCleanupService,
ProvideLogService,
)
// ProvideJWTService 提供 JWT 服务
@@ -254,3 +264,86 @@ func ProvideAdminDashboardService(
) service.AdminDashboardService {
return service.NewAdminDashboardService(db, userRepo, postRepo, commentRepo, groupRepo, activityRepo)
}
// ProvideAsyncLogManager 提供异步日志管理器
func ProvideAsyncLogManager(
db *gorm.DB,
operationRepo *repository.OperationLogRepository,
loginRepo *repository.LoginLogRepository,
dataChangeRepo *repository.DataChangeLogRepository,
logger *zap.Logger,
cfg *config.Config,
) *service.AsyncLogManager {
asyncCfg := &service.AsyncLogConfig{
BufferSize: cfg.Log.Async.BufferSize,
BatchSize: cfg.Log.Async.BatchSize,
WorkerCount: cfg.Log.Async.WorkerCount,
EnableFallback: cfg.Log.Async.EnableFallback,
FallbackPath: cfg.Log.Async.FallbackPath,
}
// 解析刷新间隔
if duration, err := parseDuration(cfg.Log.Async.FlushInterval); err == nil {
asyncCfg.FlushInterval = duration
} else {
asyncCfg.FlushInterval = 3 * time.Second
}
return service.NewAsyncLogManager(db, operationRepo, loginRepo, dataChangeRepo, logger, asyncCfg)
}
// ProvideOperationLogService 提供操作日志服务
func ProvideOperationLogService(
asyncManager *service.AsyncLogManager,
operationRepo *repository.OperationLogRepository,
) service.OperationLogService {
return service.NewOperationLogService(asyncManager, operationRepo)
}
// ProvideLoginLogService 提供登录日志服务
func ProvideLoginLogService(
asyncManager *service.AsyncLogManager,
loginRepo *repository.LoginLogRepository,
) service.LoginLogService {
return service.NewLoginLogService(asyncManager, loginRepo)
}
// ProvideDataChangeLogService 提供数据变更日志服务
func ProvideDataChangeLogService(
asyncManager *service.AsyncLogManager,
dataChangeRepo *repository.DataChangeLogRepository,
) service.DataChangeLogService {
return service.NewDataChangeLogService(asyncManager, dataChangeRepo)
}
// ProvideLogCleanupService 提供日志清理服务
func ProvideLogCleanupService(
operationRepo *repository.OperationLogRepository,
loginRepo *repository.LoginLogRepository,
dataChangeRepo *repository.DataChangeLogRepository,
logger *zap.Logger,
cfg *config.Config,
) service.LogCleanupService {
cleanupCfg := &service.LogCleanupConfig{
Enabled: true,
OperationLog: cfg.Log.Retention.OperationLog,
LoginLog: cfg.Log.Retention.LoginLog,
DataChangeLog: cfg.Log.Retention.DataChange,
CleanupTime: "02:00",
}
return service.NewLogCleanupService(operationRepo, loginRepo, dataChangeRepo, cleanupCfg, logger)
}
// ProvideLogService 提供日志服务组合
func ProvideLogService(
operationLogService service.OperationLogService,
loginLogService service.LoginLogService,
dataChangeLogService service.DataChangeLogService,
) *service.LogService {
return service.NewLogService(operationLogService, loginLogService, dataChangeLogService)
}
// parseDuration 解析时长字符串
func parseDuration(s string) (time.Duration, error) {
return time.ParseDuration(s)
}