Fix loglist
This commit is contained in:
@@ -84,26 +84,24 @@ func (s *AnalyticsService) eventListener() {
|
||||
}
|
||||
|
||||
func (s *AnalyticsService) handleAnalyticsEvent(event *models.RequestFinishedEvent) {
|
||||
if event.GroupID == 0 {
|
||||
if event.RequestLog.GroupID == nil {
|
||||
return
|
||||
}
|
||||
key := fmt.Sprintf("analytics:hourly:%s", time.Now().UTC().Format("2006-01-02T15"))
|
||||
fieldPrefix := fmt.Sprintf("%d:%s", event.GroupID, event.ModelName)
|
||||
|
||||
fieldPrefix := fmt.Sprintf("%d:%s", *event.RequestLog.GroupID, event.RequestLog.ModelName)
|
||||
pipe := s.store.Pipeline()
|
||||
pipe.HIncrBy(key, fieldPrefix+":requests", 1)
|
||||
if event.IsSuccess {
|
||||
if event.RequestLog.IsSuccess {
|
||||
pipe.HIncrBy(key, fieldPrefix+":success", 1)
|
||||
}
|
||||
if event.PromptTokens > 0 {
|
||||
pipe.HIncrBy(key, fieldPrefix+":prompt", int64(event.PromptTokens))
|
||||
if event.RequestLog.PromptTokens > 0 {
|
||||
pipe.HIncrBy(key, fieldPrefix+":prompt", int64(event.RequestLog.PromptTokens))
|
||||
}
|
||||
if event.CompletionTokens > 0 {
|
||||
pipe.HIncrBy(key, fieldPrefix+":completion", int64(event.CompletionTokens))
|
||||
if event.RequestLog.CompletionTokens > 0 {
|
||||
pipe.HIncrBy(key, fieldPrefix+":completion", int64(event.RequestLog.CompletionTokens))
|
||||
}
|
||||
|
||||
if err := pipe.Exec(); err != nil {
|
||||
s.logger.Warnf("[%s] Failed to record analytics event to store for group %d: %v", event.CorrelationID, event.GroupID, err)
|
||||
s.logger.Warnf("[%s] Failed to record analytics event to store for group %d: %v", event.CorrelationID, *event.RequestLog.GroupID, err)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -174,49 +174,40 @@ func (s *APIKeyService) Stop() {
|
||||
}
|
||||
|
||||
func (s *APIKeyService) handleKeyUsageEvent(event *models.RequestFinishedEvent) {
|
||||
if event.KeyID == 0 || event.GroupID == 0 {
|
||||
if event.RequestLog.KeyID == nil || event.RequestLog.GroupID == nil {
|
||||
return
|
||||
}
|
||||
// Handle success case: key recovery and timestamp update.
|
||||
if event.IsSuccess {
|
||||
mapping, err := s.keyRepo.GetMapping(event.GroupID, event.KeyID)
|
||||
if event.RequestLog.IsSuccess {
|
||||
mapping, err := s.keyRepo.GetMapping(*event.RequestLog.GroupID, *event.RequestLog.KeyID)
|
||||
if err != nil {
|
||||
// Log if mapping is not found, but don't proceed.
|
||||
s.logger.Warnf("[%s] Could not find mapping for G:%d K:%d on successful request: %v", event.CorrelationID, event.GroupID, event.KeyID, err)
|
||||
s.logger.Warnf("[%s] Could not find mapping for G:%d K:%d on successful request: %v", event.CorrelationID, *event.RequestLog.GroupID, *event.RequestLog.KeyID, err)
|
||||
return
|
||||
}
|
||||
|
||||
needsUpdate := false
|
||||
statusChanged := false
|
||||
oldStatus := mapping.Status
|
||||
|
||||
// If status was not active, it's a recovery.
|
||||
if mapping.Status != models.StatusActive {
|
||||
mapping.Status = models.StatusActive
|
||||
mapping.ConsecutiveErrorCount = 0
|
||||
mapping.LastError = ""
|
||||
needsUpdate = true
|
||||
statusChanged = true
|
||||
}
|
||||
// Always update LastUsedAt timestamp.
|
||||
|
||||
now := time.Now()
|
||||
mapping.LastUsedAt = &now
|
||||
needsUpdate = true
|
||||
|
||||
if needsUpdate {
|
||||
if err := s.keyRepo.UpdateMapping(mapping); err != nil {
|
||||
s.logger.Errorf("[%s] Failed to update mapping for G:%d K:%d after successful request: %v", event.CorrelationID, event.GroupID, event.KeyID, err)
|
||||
} else if oldStatus != models.StatusActive {
|
||||
// Only publish event if status actually changed.
|
||||
go s.publishStatusChangeEvent(event.GroupID, event.KeyID, oldStatus, models.StatusActive, "key_recovered_after_use")
|
||||
}
|
||||
if err := s.keyRepo.UpdateMapping(mapping); err != nil {
|
||||
s.logger.Errorf("[%s] Failed to update mapping for G:%d K:%d after successful request: %v", event.CorrelationID, *event.RequestLog.GroupID, *event.RequestLog.KeyID, err)
|
||||
return
|
||||
}
|
||||
if statusChanged {
|
||||
go s.publishStatusChangeEvent(*event.RequestLog.GroupID, *event.RequestLog.KeyID, oldStatus, models.StatusActive, "key_recovered_after_use")
|
||||
}
|
||||
return
|
||||
}
|
||||
// Handle failure case: delegate to the centralized judgment function.
|
||||
if event.Error != nil {
|
||||
s.judgeKeyErrors(
|
||||
event.CorrelationID,
|
||||
event.GroupID,
|
||||
event.KeyID,
|
||||
*event.RequestLog.GroupID,
|
||||
*event.RequestLog.KeyID,
|
||||
event.Error,
|
||||
event.IsPreciseRouting,
|
||||
)
|
||||
@@ -354,6 +345,10 @@ func (s *APIKeyService) ListAPIKeys(params *models.APIKeyQueryParams) (*Paginate
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (s *APIKeyService) GetKeysByIds(ids []uint) ([]models.APIKey, error) {
|
||||
return s.keyRepo.GetKeysByIDs(ids)
|
||||
}
|
||||
|
||||
func (s *APIKeyService) UpdateAPIKey(key *models.APIKey) error {
|
||||
go func() {
|
||||
var oldKey models.APIKey
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Filename: internal/service/db_log_writer_service.go (全新文件)
|
||||
// Filename: internal/service/db_log_writer_service.go
|
||||
|
||||
package service
|
||||
|
||||
|
||||
@@ -164,12 +164,15 @@ func (s *KeyValidationService) runTestKeysTask(taskID string, resourceID string,
|
||||
|
||||
var currentResult models.KeyTestResult
|
||||
event := models.RequestFinishedEvent{
|
||||
GroupID: groupID,
|
||||
KeyID: apiKeyModel.ID,
|
||||
RequestLog: models.RequestLog{
|
||||
// GroupID 和 KeyID 在 RequestLog 模型中是指针,需要取地址
|
||||
GroupID: &groupID,
|
||||
KeyID: &apiKeyModel.ID,
|
||||
},
|
||||
}
|
||||
if validationErr == nil {
|
||||
currentResult = models.KeyTestResult{Key: apiKeyModel.APIKey, Status: "valid", Message: "Validation successful."}
|
||||
event.IsSuccess = true
|
||||
event.RequestLog.IsSuccess = true
|
||||
} else {
|
||||
var apiErr *CustomErrors.APIError
|
||||
if CustomErrors.As(validationErr, &apiErr) {
|
||||
@@ -179,7 +182,7 @@ func (s *KeyValidationService) runTestKeysTask(taskID string, resourceID string,
|
||||
currentResult = models.KeyTestResult{Key: apiKeyModel.APIKey, Status: "error", Message: "Validation check failed: " + validationErr.Error()}
|
||||
event.Error = &CustomErrors.APIError{Message: validationErr.Error()}
|
||||
}
|
||||
event.IsSuccess = false
|
||||
event.RequestLog.IsSuccess = false
|
||||
}
|
||||
eventData, _ := json.Marshal(event)
|
||||
if err := s.store.Publish(models.TopicRequestFinished, eventData); err != nil {
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
// Filename: internal/service/log_service.go
|
||||
package service
|
||||
|
||||
import (
|
||||
@@ -16,28 +17,35 @@ func NewLogService(db *gorm.DB) *LogService {
|
||||
return &LogService{db: db}
|
||||
}
|
||||
|
||||
// Record 记录一条日志到数据库 (TODO 暂时保留简单实现,后续再重构为异步)
|
||||
func (s *LogService) Record(log *models.RequestLog) error {
|
||||
return s.db.Create(log).Error
|
||||
}
|
||||
|
||||
func (s *LogService) GetLogs(c *gin.Context) ([]models.RequestLog, error) {
|
||||
func (s *LogService) GetLogs(c *gin.Context) ([]models.RequestLog, int64, error) {
|
||||
var logs []models.RequestLog
|
||||
var total int64
|
||||
|
||||
query := s.db.Model(&models.RequestLog{}).Scopes(s.filtersScope(c)).Order("request_time desc")
|
||||
query := s.db.Model(&models.RequestLog{}).Scopes(s.filtersScope(c))
|
||||
|
||||
// 简单的分页 ( TODO 后续可以做得更复杂)
|
||||
// 先计算总数
|
||||
if err := query.Count(&total).Error; err != nil {
|
||||
return nil, 0, err
|
||||
}
|
||||
if total == 0 {
|
||||
return []models.RequestLog{}, 0, nil
|
||||
}
|
||||
|
||||
// 再执行分页查询
|
||||
page, _ := strconv.Atoi(c.DefaultQuery("page", "1"))
|
||||
pageSize, _ := strconv.Atoi(c.DefaultQuery("page_size", "20"))
|
||||
offset := (page - 1) * pageSize
|
||||
|
||||
// 执行查询
|
||||
err := query.Limit(pageSize).Offset(offset).Find(&logs).Error
|
||||
err := query.Order("request_time desc").Limit(pageSize).Offset(offset).Find(&logs).Error
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return nil, 0, err
|
||||
}
|
||||
|
||||
return logs, nil
|
||||
return logs, total, nil
|
||||
}
|
||||
|
||||
func (s *LogService) filtersScope(c *gin.Context) func(db *gorm.DB) *gorm.DB {
|
||||
@@ -60,6 +68,11 @@ func (s *LogService) filtersScope(c *gin.Context) func(db *gorm.DB) *gorm.DB {
|
||||
db = db.Where("key_id = ?", keyID)
|
||||
}
|
||||
}
|
||||
if groupIDStr := c.Query("group_id"); groupIDStr != "" {
|
||||
if groupID, err := strconv.ParseUint(groupIDStr, 10, 64); err == nil {
|
||||
db = db.Where("group_id = ?", groupID)
|
||||
}
|
||||
}
|
||||
return db
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user