feat: 日志列表接口调整

This commit is contained in:
tbphp
2025-07-12 10:45:05 +08:00
parent 87598befb7
commit b3b1769411

View File

@@ -1,7 +1,6 @@
package handler package handler
import ( import (
"net/http"
"strconv" "strconv"
"time" "time"
@@ -12,56 +11,136 @@ import (
"gpt-load/internal/response" "gpt-load/internal/response"
) )
// GetLogs godoc // LogResponse defines the structure for log entries in the API response,
func GetLogs(c *gin.Context) { // enriching the base log with related data.
page, _ := strconv.Atoi(c.DefaultQuery("page", "1")) type LogResponse struct {
size, _ := strconv.Atoi(c.DefaultQuery("size", "10")) models.RequestLog
offset := (page - 1) * size GroupName string `json:"group_name"`
KeyValue string `json:"key_value"`
}
// GetLogs Get request logs
func GetLogs(c *gin.Context) {
// --- 1. Build WHERE conditions ---
query := db.DB.Model(&models.RequestLog{}) query := db.DB.Model(&models.RequestLog{})
if groupIDStr := c.Query("group_id"); groupIDStr != "" { if groupName := c.Query("group_name"); groupName != "" {
groupID, err := strconv.Atoi(groupIDStr) var groupIDs []uint
if err == nil { db.DB.Model(&models.Group{}).Where("name LIKE ? OR display_name LIKE ?", "%"+groupName+"%", "%"+groupName+"%").Pluck("id", &groupIDs)
query = query.Where("group_id = ?", groupID) if len(groupIDs) == 0 {
response.Success(c, &response.PaginatedResponse{
Items: []LogResponse{},
Pagination: response.Pagination{TotalItems: 0, Page: 1, PageSize: response.DefaultPageSize},
})
return
}
query = query.Where("group_id IN ?", groupIDs)
}
if keyValue := c.Query("key_value"); keyValue != "" {
var keyIDs []uint
likePattern := "%" + keyValue[1:len(keyValue)-1] + "%"
db.DB.Model(&models.APIKey{}).Where("key_value LIKE ?", likePattern).Pluck("id", &keyIDs)
if len(keyIDs) == 0 {
response.Success(c, &response.PaginatedResponse{
Items: []LogResponse{},
Pagination: response.Pagination{TotalItems: 0, Page: 1, PageSize: response.DefaultPageSize},
})
return
}
query = query.Where("key_id IN ?", keyIDs)
}
if isSuccessStr := c.Query("is_success"); isSuccessStr != "" {
if isSuccess, err := strconv.ParseBool(isSuccessStr); err == nil {
query = query.Where("is_success = ?", isSuccess)
} }
} }
if statusCodeStr := c.Query("status_code"); statusCodeStr != "" {
if statusCode, err := strconv.Atoi(statusCodeStr); err == nil {
query = query.Where("status_code = ?", statusCode)
}
}
if sourceIP := c.Query("source_ip"); sourceIP != "" {
query = query.Where("source_ip = ?", sourceIP)
}
if errorContains := c.Query("error_contains"); errorContains != "" {
query = query.Where("error_message LIKE ?", "%"+errorContains+"%")
}
if startTimeStr := c.Query("start_time"); startTimeStr != "" { if startTimeStr := c.Query("start_time"); startTimeStr != "" {
startTime, err := time.Parse(time.RFC3339, startTimeStr) if startTime, err := time.Parse(time.RFC3339, startTimeStr); err == nil {
if err == nil {
query = query.Where("timestamp >= ?", startTime) query = query.Where("timestamp >= ?", startTime)
} }
} }
if endTimeStr := c.Query("end_time"); endTimeStr != "" { if endTimeStr := c.Query("end_time"); endTimeStr != "" {
endTime, err := time.Parse(time.RFC3339, endTimeStr) if endTime, err := time.Parse(time.RFC3339, endTimeStr); err == nil {
if err == nil {
query = query.Where("timestamp <= ?", endTime) query = query.Where("timestamp <= ?", endTime)
} }
} }
if statusCodeStr := c.Query("status_code"); statusCodeStr != "" { // --- 2. Get Paginated Logs ---
statusCode, err := strconv.Atoi(statusCodeStr)
if err == nil {
query = query.Where("status_code = ?", statusCode)
}
}
var logs []models.RequestLog var logs []models.RequestLog
var total int64 query = query.Order("timestamp desc") // Apply ordering before pagination
pagination, err := response.Paginate(c, query, &logs)
query.Count(&total)
err := query.Order("timestamp desc").Offset(offset).Limit(size).Find(&logs).Error
if err != nil { if err != nil {
response.Error(c, app_errors.ParseDBError(err)) response.Error(c, app_errors.ParseDBError(err))
return return
} }
c.JSON(http.StatusOK, gin.H{ // --- 3. Enrich Logs with GroupName and KeyValue ---
"total": total, if len(logs) == 0 {
"page": page, response.Success(c, pagination) // Return empty pagination response
"size": size, return
"data": logs, }
})
// Collect IDs for enrichment
groupIds := make(map[uint]bool)
keyIds := make(map[uint]bool)
for _, log := range logs {
if log.GroupID != 0 {
groupIds[log.GroupID] = true
}
if log.KeyID != 0 {
keyIds[log.KeyID] = true
}
}
// Fetch enrichment data
groupMap := make(map[uint]string)
if len(groupIds) > 0 {
var groups []models.Group
var ids []uint
for id := range groupIds {
ids = append(ids, id)
}
db.DB.Where("id IN ?", ids).Find(&groups)
for _, group := range groups {
groupMap[group.ID] = group.Name
}
}
keyMap := make(map[uint]string)
if len(keyIds) > 0 {
var keys []models.APIKey
var ids []uint
for id := range keyIds {
ids = append(ids, id)
}
db.DB.Where("id IN ?", ids).Find(&keys)
for _, key := range keys {
keyMap[key.ID] = key.KeyValue
}
}
// Build final response
logResponses := make([]LogResponse, len(logs))
for i, log := range logs {
logResponses[i] = LogResponse{
RequestLog: log,
GroupName: groupMap[log.GroupID],
KeyValue: keyMap[log.KeyID],
}
}
// --- 4. Send Response ---
pagination.Items = logResponses
response.Success(c, pagination)
} }