165 lines
4.2 KiB
Go
165 lines
4.2 KiB
Go
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
|
||
}
|