package service import ( "context" "fmt" "gemini-balancer/internal/models" "strconv" "strings" "github.com/sirupsen/logrus" "gorm.io/gorm" ) type LogService struct { db *gorm.DB logger *logrus.Entry } func NewLogService(db *gorm.DB, logger *logrus.Logger) *LogService { return &LogService{ db: db, logger: logger.WithField("component", "LogService"), } } func (s *LogService) Record(ctx context.Context, log *models.RequestLog) error { return s.db.WithContext(ctx).Create(log).Error } // LogQueryParams 解耦 Gin,使用结构体传参 type LogQueryParams struct { Page int PageSize int ModelName string IsSuccess *bool // 使用指针区分"未设置"和"false" StatusCode *int KeyIDs []string GroupIDs []string Q string ErrorCodes []string StatusCodes []string } func (s *LogService) GetLogs(ctx context.Context, params LogQueryParams) ([]models.RequestLog, int64, error) { // 参数校验 if params.Page < 1 { params.Page = 1 } if params.PageSize < 1 || params.PageSize > 100 { params.PageSize = 20 } var logs []models.RequestLog var total int64 // 构建基础查询 query := s.db.WithContext(ctx).Model(&models.RequestLog{}) query = s.applyFilters(query, params) if err := query.Count(&total).Error; err != nil { return nil, 0, fmt.Errorf("failed to count logs: %w", err) } if total == 0 { return []models.RequestLog{}, 0, nil } offset := (params.Page - 1) * params.PageSize if err := query.Order("request_time DESC"). Limit(params.PageSize). Offset(offset). Find(&logs).Error; err != nil { return nil, 0, fmt.Errorf("failed to query logs: %w", err) } return logs, total, nil } func (s *LogService) applyFilters(query *gorm.DB, params LogQueryParams) *gorm.DB { if params.ModelName != "" { query = query.Where("model_name = ?", params.ModelName) } if params.IsSuccess != nil { query = query.Where("is_success = ?", *params.IsSuccess) } if params.StatusCode != nil { query = query.Where("status_code = ?", *params.StatusCode) } if len(params.KeyIDs) > 0 { query = query.Where("key_id IN (?)", params.KeyIDs) } if len(params.GroupIDs) > 0 { query = query.Where("group_id IN (?)", params.GroupIDs) } if len(params.ErrorCodes) > 0 { query = query.Where("error_code IN (?)", params.ErrorCodes) } if len(params.StatusCodes) > 0 { query = query.Where("status_code IN (?)", params.StatusCodes) } if params.Q != "" { searchQuery := "%" + params.Q + "%" query = query.Where( "model_name LIKE ? OR error_code LIKE ? OR error_message LIKE ? OR CAST(status_code AS CHAR) LIKE ?", searchQuery, searchQuery, searchQuery, searchQuery, ) } return query } // ParseLogQueryParams 在 Handler 层调用,解析 Gin 参数 func ParseLogQueryParams(queryParams map[string]string) (LogQueryParams, error) { params := LogQueryParams{ Page: 1, PageSize: 20, } if pageStr, ok := queryParams["page"]; ok { if page, err := strconv.Atoi(pageStr); err == nil && page > 0 { params.Page = page } } if pageSizeStr, ok := queryParams["page_size"]; ok { if pageSize, err := strconv.Atoi(pageSizeStr); err == nil && pageSize > 0 { params.PageSize = pageSize } } if modelName, ok := queryParams["model_name"]; ok { params.ModelName = modelName } if isSuccessStr, ok := queryParams["is_success"]; ok { if isSuccess, err := strconv.ParseBool(isSuccessStr); err == nil { params.IsSuccess = &isSuccess } else { return params, fmt.Errorf("invalid is_success parameter: %s", isSuccessStr) } } if statusCodeStr, ok := queryParams["status_code"]; ok { if statusCode, err := strconv.Atoi(statusCodeStr); err == nil { params.StatusCode = &statusCode } else { return params, fmt.Errorf("invalid status_code parameter: %s", statusCodeStr) } } if keyIDsStr, ok := queryParams["key_ids"]; ok { params.KeyIDs = strings.Split(keyIDsStr, ",") } if groupIDsStr, ok := queryParams["group_ids"]; ok { params.GroupIDs = strings.Split(groupIDsStr, ",") } if errorCodesStr, ok := queryParams["error_codes"]; ok { params.ErrorCodes = strings.Split(errorCodesStr, ",") } if statusCodesStr, ok := queryParams["status_codes"]; ok { params.StatusCodes = strings.Split(statusCodesStr, ",") } if q, ok := queryParams["q"]; ok { params.Q = q } return params, nil }