mirror of
https://github.com/ctwj/urldb.git
synced 2025-11-25 03:15:04 +08:00
update: 日志优化
This commit is contained in:
@@ -128,6 +128,11 @@ PORT=8080
|
|||||||
|
|
||||||
# 时区配置
|
# 时区配置
|
||||||
TIMEZONE=Asia/Shanghai
|
TIMEZONE=Asia/Shanghai
|
||||||
|
|
||||||
|
# 日志配置
|
||||||
|
LOG_LEVEL=INFO # 日志级别 (DEBUG, INFO, WARN, ERROR, FATAL)
|
||||||
|
DEBUG=false # 调试模式开关
|
||||||
|
STRUCTURED_LOG=false # 结构化日志开关 (JSON格式)
|
||||||
```
|
```
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,10 @@
|
|||||||
package repo
|
package repo
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"time"
|
||||||
|
|
||||||
"github.com/ctwj/urldb/db/entity"
|
"github.com/ctwj/urldb/db/entity"
|
||||||
|
"github.com/ctwj/urldb/utils"
|
||||||
|
|
||||||
"gorm.io/gorm"
|
"gorm.io/gorm"
|
||||||
)
|
)
|
||||||
@@ -66,20 +69,28 @@ func (r *CksRepositoryImpl) FindAll() ([]entity.Cks, error) {
|
|||||||
|
|
||||||
// FindByID 根据ID查找Cks,预加载Pan关联数据
|
// FindByID 根据ID查找Cks,预加载Pan关联数据
|
||||||
func (r *CksRepositoryImpl) FindByID(id uint) (*entity.Cks, error) {
|
func (r *CksRepositoryImpl) FindByID(id uint) (*entity.Cks, error) {
|
||||||
|
startTime := utils.GetCurrentTime()
|
||||||
var cks entity.Cks
|
var cks entity.Cks
|
||||||
err := r.db.Preload("Pan").First(&cks, id).Error
|
err := r.db.Preload("Pan").First(&cks, id).Error
|
||||||
|
queryDuration := time.Since(startTime)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
utils.Debug("FindByID失败: ID=%d, 错误=%v, 查询耗时=%v", id, err, queryDuration)
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
utils.Debug("FindByID成功: ID=%d, 查询耗时=%v", id, queryDuration)
|
||||||
return &cks, nil
|
return &cks, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *CksRepositoryImpl) FindByIds(ids []uint) ([]*entity.Cks, error) {
|
func (r *CksRepositoryImpl) FindByIds(ids []uint) ([]*entity.Cks, error) {
|
||||||
|
startTime := utils.GetCurrentTime()
|
||||||
var cks []*entity.Cks
|
var cks []*entity.Cks
|
||||||
err := r.db.Preload("Pan").Where("id IN ?", ids).Find(&cks).Error
|
err := r.db.Preload("Pan").Where("id IN ?", ids).Find(&cks).Error
|
||||||
|
queryDuration := time.Since(startTime)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
utils.Debug("FindByIds失败: IDs数量=%d, 错误=%v, 查询耗时=%v", len(ids), err, queryDuration)
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
utils.Debug("FindByIds成功: 找到%d个账号,查询耗时=%v", len(cks), queryDuration)
|
||||||
return cks, nil
|
return cks, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/ctwj/urldb/db/entity"
|
"github.com/ctwj/urldb/db/entity"
|
||||||
|
"github.com/ctwj/urldb/utils"
|
||||||
"gorm.io/gorm"
|
"gorm.io/gorm"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -201,6 +202,7 @@ func (r *ResourceRepositoryImpl) SearchByPanID(query string, panID uint, page, l
|
|||||||
|
|
||||||
// SearchWithFilters 根据参数进行搜索
|
// SearchWithFilters 根据参数进行搜索
|
||||||
func (r *ResourceRepositoryImpl) SearchWithFilters(params map[string]interface{}) ([]entity.Resource, int64, error) {
|
func (r *ResourceRepositoryImpl) SearchWithFilters(params map[string]interface{}) ([]entity.Resource, int64, error) {
|
||||||
|
startTime := utils.GetCurrentTime()
|
||||||
var resources []entity.Resource
|
var resources []entity.Resource
|
||||||
var total int64
|
var total int64
|
||||||
|
|
||||||
@@ -318,8 +320,11 @@ func (r *ResourceRepositoryImpl) SearchWithFilters(params map[string]interface{}
|
|||||||
offset := (page - 1) * pageSize
|
offset := (page - 1) * pageSize
|
||||||
|
|
||||||
// 获取分页数据,按更新时间倒序
|
// 获取分页数据,按更新时间倒序
|
||||||
|
queryStart := utils.GetCurrentTime()
|
||||||
err := db.Order("updated_at DESC").Offset(offset).Limit(pageSize).Find(&resources).Error
|
err := db.Order("updated_at DESC").Offset(offset).Limit(pageSize).Find(&resources).Error
|
||||||
fmt.Printf("查询结果: 总数=%d, 当前页数据量=%d, pageSize=%d\n", total, len(resources), pageSize)
|
queryDuration := time.Since(queryStart)
|
||||||
|
totalDuration := time.Since(startTime)
|
||||||
|
utils.Debug("SearchWithFilters完成: 总数=%d, 当前页数据量=%d, 查询耗时=%v, 总耗时=%v", total, len(resources), queryDuration, totalDuration)
|
||||||
return resources, total, err
|
return resources, total, err
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -452,11 +457,15 @@ func (r *ResourceRepositoryImpl) GetResourcesForTransfer(panID uint, sinceTime t
|
|||||||
|
|
||||||
// GetByURL 根据URL获取资源
|
// GetByURL 根据URL获取资源
|
||||||
func (r *ResourceRepositoryImpl) GetByURL(url string) (*entity.Resource, error) {
|
func (r *ResourceRepositoryImpl) GetByURL(url string) (*entity.Resource, error) {
|
||||||
|
startTime := utils.GetCurrentTime()
|
||||||
var resource entity.Resource
|
var resource entity.Resource
|
||||||
err := r.db.Where("url = ?", url).First(&resource).Error
|
err := r.db.Where("url = ?", url).First(&resource).Error
|
||||||
|
queryDuration := time.Since(startTime)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
utils.Debug("GetByURL失败: URL=%s, 错误=%v, 查询耗时=%v", url, err, queryDuration)
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
utils.Debug("GetByURL成功: URL=%s, 查询耗时=%v", url, queryDuration)
|
||||||
return &resource, nil
|
return &resource, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ package repo
|
|||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"sync"
|
"sync"
|
||||||
|
"time"
|
||||||
|
|
||||||
"github.com/ctwj/urldb/db/entity"
|
"github.com/ctwj/urldb/db/entity"
|
||||||
"github.com/ctwj/urldb/utils"
|
"github.com/ctwj/urldb/utils"
|
||||||
@@ -100,8 +101,11 @@ func (r *SystemConfigRepositoryImpl) UpsertConfigs(configs []entity.SystemConfig
|
|||||||
|
|
||||||
// GetOrCreateDefault 获取配置或创建默认配置
|
// GetOrCreateDefault 获取配置或创建默认配置
|
||||||
func (r *SystemConfigRepositoryImpl) GetOrCreateDefault() ([]entity.SystemConfig, error) {
|
func (r *SystemConfigRepositoryImpl) GetOrCreateDefault() ([]entity.SystemConfig, error) {
|
||||||
|
startTime := utils.GetCurrentTime()
|
||||||
configs, err := r.FindAll()
|
configs, err := r.FindAll()
|
||||||
|
initialQueryDuration := time.Since(startTime)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
utils.Error("获取所有系统配置失败: %v,耗时: %v", err, initialQueryDuration)
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -141,11 +145,16 @@ func (r *SystemConfigRepositoryImpl) GetOrCreateDefault() ([]entity.SystemConfig
|
|||||||
{Key: entity.ConfigKeyQrCodeStyle, Value: entity.ConfigDefaultQrCodeStyle, Type: entity.ConfigTypeString},
|
{Key: entity.ConfigKeyQrCodeStyle, Value: entity.ConfigDefaultQrCodeStyle, Type: entity.ConfigTypeString},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
createStart := utils.GetCurrentTime()
|
||||||
err = r.UpsertConfigs(defaultConfigs)
|
err = r.UpsertConfigs(defaultConfigs)
|
||||||
|
createDuration := time.Since(createStart)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
utils.Error("创建默认系统配置失败: %v,耗时: %v", err, createDuration)
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
totalDuration := time.Since(startTime)
|
||||||
|
utils.Info("创建默认系统配置成功,数量: %d,总耗时: %v", len(defaultConfigs), totalDuration)
|
||||||
return defaultConfigs, nil
|
return defaultConfigs, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -198,17 +207,24 @@ func (r *SystemConfigRepositoryImpl) GetOrCreateDefault() ([]entity.SystemConfig
|
|||||||
|
|
||||||
// 如果有缺失的配置项,则添加它们
|
// 如果有缺失的配置项,则添加它们
|
||||||
if len(missingConfigs) > 0 {
|
if len(missingConfigs) > 0 {
|
||||||
|
upsertStart := utils.GetCurrentTime()
|
||||||
err = r.UpsertConfigs(missingConfigs)
|
err = r.UpsertConfigs(missingConfigs)
|
||||||
|
upsertDuration := time.Since(upsertStart)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
utils.Error("添加缺失的系统配置失败: %v,耗时: %v", err, upsertDuration)
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
utils.Debug("添加缺失的系统配置完成,数量: %d,耗时: %v", len(missingConfigs), upsertDuration)
|
||||||
// 重新获取所有配置
|
// 重新获取所有配置
|
||||||
configs, err = r.FindAll()
|
configs, err = r.FindAll()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
utils.Error("重新获取所有系统配置失败: %v", err)
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
totalDuration := time.Since(startTime)
|
||||||
|
utils.Debug("GetOrCreateDefault完成,总数: %d,总耗时: %v", len(configs), totalDuration)
|
||||||
return configs, nil
|
return configs, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,10 @@
|
|||||||
package repo
|
package repo
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"time"
|
||||||
|
|
||||||
"github.com/ctwj/urldb/db/entity"
|
"github.com/ctwj/urldb/db/entity"
|
||||||
|
"github.com/ctwj/urldb/utils"
|
||||||
"gorm.io/gorm"
|
"gorm.io/gorm"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -58,8 +61,15 @@ func (r *TaskItemRepositoryImpl) DeleteByTaskID(taskID uint) error {
|
|||||||
|
|
||||||
// GetByTaskIDAndStatus 根据任务ID和状态获取任务项
|
// GetByTaskIDAndStatus 根据任务ID和状态获取任务项
|
||||||
func (r *TaskItemRepositoryImpl) GetByTaskIDAndStatus(taskID uint, status string) ([]*entity.TaskItem, error) {
|
func (r *TaskItemRepositoryImpl) GetByTaskIDAndStatus(taskID uint, status string) ([]*entity.TaskItem, error) {
|
||||||
|
startTime := utils.GetCurrentTime()
|
||||||
var items []*entity.TaskItem
|
var items []*entity.TaskItem
|
||||||
err := r.db.Where("task_id = ? AND status = ?", taskID, status).Order("id ASC").Find(&items).Error
|
err := r.db.Where("task_id = ? AND status = ?", taskID, status).Order("id ASC").Find(&items).Error
|
||||||
|
queryDuration := time.Since(startTime)
|
||||||
|
if err != nil {
|
||||||
|
utils.Error("GetByTaskIDAndStatus失败: 任务ID=%d, 状态=%s, 错误=%v, 查询耗时=%v", taskID, status, err, queryDuration)
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
utils.Debug("GetByTaskIDAndStatus成功: 任务ID=%d, 状态=%s, 数量=%d, 查询耗时=%v", taskID, status, len(items), queryDuration)
|
||||||
return items, err
|
return items, err
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -93,19 +103,36 @@ func (r *TaskItemRepositoryImpl) GetListByTaskID(taskID uint, page, pageSize int
|
|||||||
|
|
||||||
// UpdateStatus 更新任务项状态
|
// UpdateStatus 更新任务项状态
|
||||||
func (r *TaskItemRepositoryImpl) UpdateStatus(id uint, status string) error {
|
func (r *TaskItemRepositoryImpl) UpdateStatus(id uint, status string) error {
|
||||||
return r.db.Model(&entity.TaskItem{}).Where("id = ?", id).Update("status", status).Error
|
startTime := utils.GetCurrentTime()
|
||||||
|
err := r.db.Model(&entity.TaskItem{}).Where("id = ?", id).Update("status", status).Error
|
||||||
|
updateDuration := time.Since(startTime)
|
||||||
|
if err != nil {
|
||||||
|
utils.Error("UpdateStatus失败: ID=%d, 状态=%s, 错误=%v, 更新耗时=%v", id, status, err, updateDuration)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
utils.Debug("UpdateStatus成功: ID=%d, 状态=%s, 更新耗时=%v", id, status, updateDuration)
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// UpdateStatusAndOutput 更新任务项状态和输出数据
|
// UpdateStatusAndOutput 更新任务项状态和输出数据
|
||||||
func (r *TaskItemRepositoryImpl) UpdateStatusAndOutput(id uint, status, outputData string) error {
|
func (r *TaskItemRepositoryImpl) UpdateStatusAndOutput(id uint, status, outputData string) error {
|
||||||
return r.db.Model(&entity.TaskItem{}).Where("id = ?", id).Updates(map[string]interface{}{
|
startTime := utils.GetCurrentTime()
|
||||||
|
err := r.db.Model(&entity.TaskItem{}).Where("id = ?", id).Updates(map[string]interface{}{
|
||||||
"status": status,
|
"status": status,
|
||||||
"output_data": outputData,
|
"output_data": outputData,
|
||||||
}).Error
|
}).Error
|
||||||
|
updateDuration := time.Since(startTime)
|
||||||
|
if err != nil {
|
||||||
|
utils.Error("UpdateStatusAndOutput失败: ID=%d, 状态=%s, 错误=%v, 更新耗时=%v", id, status, err, updateDuration)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
utils.Debug("UpdateStatusAndOutput成功: ID=%d, 状态=%s, 更新耗时=%v", id, status, updateDuration)
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetStatsByTaskID 获取任务项统计信息
|
// GetStatsByTaskID 获取任务项统计信息
|
||||||
func (r *TaskItemRepositoryImpl) GetStatsByTaskID(taskID uint) (map[string]int, error) {
|
func (r *TaskItemRepositoryImpl) GetStatsByTaskID(taskID uint) (map[string]int, error) {
|
||||||
|
startTime := utils.GetCurrentTime()
|
||||||
var results []struct {
|
var results []struct {
|
||||||
Status string
|
Status string
|
||||||
Count int
|
Count int
|
||||||
@@ -117,7 +144,9 @@ func (r *TaskItemRepositoryImpl) GetStatsByTaskID(taskID uint) (map[string]int,
|
|||||||
Group("status").
|
Group("status").
|
||||||
Find(&results).Error
|
Find(&results).Error
|
||||||
|
|
||||||
|
queryDuration := time.Since(startTime)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
utils.Error("GetStatsByTaskID失败: 任务ID=%d, 错误=%v, 查询耗时=%v", taskID, err, queryDuration)
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -134,12 +163,22 @@ func (r *TaskItemRepositoryImpl) GetStatsByTaskID(taskID uint) (map[string]int,
|
|||||||
stats["total"] += result.Count
|
stats["total"] += result.Count
|
||||||
}
|
}
|
||||||
|
|
||||||
|
totalDuration := time.Since(startTime)
|
||||||
|
utils.Debug("GetStatsByTaskID成功: 任务ID=%d, 统计信息=%v, 查询耗时=%v, 总耗时=%v", taskID, stats, queryDuration, totalDuration)
|
||||||
return stats, nil
|
return stats, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// ResetProcessingItems 重置处理中的任务项为pending状态
|
// ResetProcessingItems 重置处理中的任务项为pending状态
|
||||||
func (r *TaskItemRepositoryImpl) ResetProcessingItems(taskID uint) error {
|
func (r *TaskItemRepositoryImpl) ResetProcessingItems(taskID uint) error {
|
||||||
return r.db.Model(&entity.TaskItem{}).
|
startTime := utils.GetCurrentTime()
|
||||||
|
err := r.db.Model(&entity.TaskItem{}).
|
||||||
Where("task_id = ? AND status = ?", taskID, "processing").
|
Where("task_id = ? AND status = ?", taskID, "processing").
|
||||||
Update("status", "pending").Error
|
Update("status", "pending").Error
|
||||||
|
updateDuration := time.Since(startTime)
|
||||||
|
if err != nil {
|
||||||
|
utils.Error("ResetProcessingItems失败: 任务ID=%d, 错误=%v, 更新耗时=%v", taskID, err, updateDuration)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
utils.Debug("ResetProcessingItems成功: 任务ID=%d, 更新耗时=%v", taskID, updateDuration)
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/ctwj/urldb/db/entity"
|
"github.com/ctwj/urldb/db/entity"
|
||||||
|
"github.com/ctwj/urldb/utils"
|
||||||
"gorm.io/gorm"
|
"gorm.io/gorm"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -35,11 +36,15 @@ func NewTaskRepository(db *gorm.DB) TaskRepository {
|
|||||||
|
|
||||||
// GetByID 根据ID获取任务
|
// GetByID 根据ID获取任务
|
||||||
func (r *TaskRepositoryImpl) GetByID(id uint) (*entity.Task, error) {
|
func (r *TaskRepositoryImpl) GetByID(id uint) (*entity.Task, error) {
|
||||||
|
startTime := utils.GetCurrentTime()
|
||||||
var task entity.Task
|
var task entity.Task
|
||||||
err := r.db.First(&task, id).Error
|
err := r.db.First(&task, id).Error
|
||||||
|
queryDuration := time.Since(startTime)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
utils.Debug("GetByID失败: ID=%d, 错误=%v, 查询耗时=%v", id, err, queryDuration)
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
utils.Debug("GetByID成功: ID=%d, 查询耗时=%v", id, queryDuration)
|
||||||
return &task, nil
|
return &task, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -55,6 +60,7 @@ func (r *TaskRepositoryImpl) Delete(id uint) error {
|
|||||||
|
|
||||||
// GetList 获取任务列表
|
// GetList 获取任务列表
|
||||||
func (r *TaskRepositoryImpl) GetList(page, pageSize int, taskType, status string) ([]*entity.Task, int64, error) {
|
func (r *TaskRepositoryImpl) GetList(page, pageSize int, taskType, status string) ([]*entity.Task, int64, error) {
|
||||||
|
startTime := utils.GetCurrentTime()
|
||||||
var tasks []*entity.Task
|
var tasks []*entity.Task
|
||||||
var total int64
|
var total int64
|
||||||
|
|
||||||
@@ -69,84 +75,171 @@ func (r *TaskRepositoryImpl) GetList(page, pageSize int, taskType, status string
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 获取总数
|
// 获取总数
|
||||||
|
countStart := utils.GetCurrentTime()
|
||||||
err := query.Count(&total).Error
|
err := query.Count(&total).Error
|
||||||
|
countDuration := time.Since(countStart)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
utils.Error("GetList获取总数失败: 错误=%v, 查询耗时=%v", err, countDuration)
|
||||||
return nil, 0, err
|
return nil, 0, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// 分页查询
|
// 分页查询
|
||||||
offset := (page - 1) * pageSize
|
offset := (page - 1) * pageSize
|
||||||
|
queryStart := utils.GetCurrentTime()
|
||||||
err = query.Offset(offset).Limit(pageSize).Order("created_at DESC").Find(&tasks).Error
|
err = query.Offset(offset).Limit(pageSize).Order("created_at DESC").Find(&tasks).Error
|
||||||
|
queryDuration := time.Since(queryStart)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
utils.Error("GetList查询失败: 错误=%v, 查询耗时=%v", err, queryDuration)
|
||||||
return nil, 0, err
|
return nil, 0, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
totalDuration := time.Since(startTime)
|
||||||
|
utils.Debug("GetList完成: 任务类型=%s, 状态=%s, 页码=%d, 页面大小=%d, 总数=%d, 结果数=%d, 总耗时=%v", taskType, status, page, pageSize, total, len(tasks), totalDuration)
|
||||||
return tasks, total, nil
|
return tasks, total, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// UpdateStatus 更新任务状态
|
// UpdateStatus 更新任务状态
|
||||||
func (r *TaskRepositoryImpl) UpdateStatus(id uint, status string) error {
|
func (r *TaskRepositoryImpl) UpdateStatus(id uint, status string) error {
|
||||||
return r.db.Model(&entity.Task{}).Where("id = ?", id).Update("status", status).Error
|
startTime := utils.GetCurrentTime()
|
||||||
|
err := r.db.Model(&entity.Task{}).Where("id = ?", id).Update("status", status).Error
|
||||||
|
updateDuration := time.Since(startTime)
|
||||||
|
if err != nil {
|
||||||
|
utils.Error("UpdateStatus失败: ID=%d, 状态=%s, 错误=%v, 更新耗时=%v", id, status, err, updateDuration)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
utils.Debug("UpdateStatus成功: ID=%d, 状态=%s, 更新耗时=%v", id, status, updateDuration)
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// UpdateProgress 更新任务进度
|
// UpdateProgress 更新任务进度
|
||||||
func (r *TaskRepositoryImpl) UpdateProgress(id uint, progress float64, progressData string) error {
|
func (r *TaskRepositoryImpl) UpdateProgress(id uint, progress float64, progressData string) error {
|
||||||
|
startTime := utils.GetCurrentTime()
|
||||||
// 检查progress和progress_data字段是否存在
|
// 检查progress和progress_data字段是否存在
|
||||||
var count int64
|
var count int64
|
||||||
err := r.db.Raw("SELECT COUNT(*) FROM information_schema.columns WHERE table_name = 'tasks' AND column_name = 'progress'").Count(&count).Error
|
err := r.db.Raw("SELECT COUNT(*) FROM information_schema.columns WHERE table_name = 'tasks' AND column_name = 'progress'").Count(&count).Error
|
||||||
if err != nil || count == 0 {
|
if err != nil || count == 0 {
|
||||||
// 如果检查失败或字段不存在,只更新processed_items等现有字段
|
// 如果检查失败或字段不存在,只更新processed_items等现有字段
|
||||||
return r.db.Model(&entity.Task{}).Where("id = ?", id).Updates(map[string]interface{}{
|
updateStart := utils.GetCurrentTime()
|
||||||
|
err := r.db.Model(&entity.Task{}).Where("id = ?", id).Updates(map[string]interface{}{
|
||||||
"processed_items": progress, // 使用progress作为processed_items的近似值
|
"processed_items": progress, // 使用progress作为processed_items的近似值
|
||||||
}).Error
|
}).Error
|
||||||
|
updateDuration := time.Since(updateStart)
|
||||||
|
totalDuration := time.Since(startTime)
|
||||||
|
if err != nil {
|
||||||
|
utils.Error("UpdateProgress失败(字段不存在): ID=%d, 进度=%f, 错误=%v, 更新耗时=%v, 总耗时=%v", id, progress, err, updateDuration, totalDuration)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
utils.Debug("UpdateProgress成功(字段不存在): ID=%d, 进度=%f, 更新耗时=%v, 总耗时=%v", id, progress, updateDuration, totalDuration)
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// 字段存在,正常更新
|
// 字段存在,正常更新
|
||||||
return r.db.Model(&entity.Task{}).Where("id = ?", id).Updates(map[string]interface{}{
|
updateStart := utils.GetCurrentTime()
|
||||||
|
err = r.db.Model(&entity.Task{}).Where("id = ?", id).Updates(map[string]interface{}{
|
||||||
"progress": progress,
|
"progress": progress,
|
||||||
"progress_data": progressData,
|
"progress_data": progressData,
|
||||||
}).Error
|
}).Error
|
||||||
|
updateDuration := time.Since(updateStart)
|
||||||
|
totalDuration := time.Since(startTime)
|
||||||
|
if err != nil {
|
||||||
|
utils.Error("UpdateProgress失败: ID=%d, 进度=%f, 错误=%v, 更新耗时=%v, 总耗时=%v", id, progress, err, updateDuration, totalDuration)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
utils.Debug("UpdateProgress成功: ID=%d, 进度=%f, 更新耗时=%v, 总耗时=%v", id, progress, updateDuration, totalDuration)
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// UpdateStatusAndMessage 更新任务状态和消息
|
// UpdateStatusAndMessage 更新任务状态和消息
|
||||||
func (r *TaskRepositoryImpl) UpdateStatusAndMessage(id uint, status, message string) error {
|
func (r *TaskRepositoryImpl) UpdateStatusAndMessage(id uint, status, message string) error {
|
||||||
|
startTime := utils.GetCurrentTime()
|
||||||
// 检查message字段是否存在
|
// 检查message字段是否存在
|
||||||
var count int64
|
var count int64
|
||||||
err := r.db.Raw("SELECT COUNT(*) FROM information_schema.columns WHERE table_name = 'tasks' AND column_name = 'message'").Count(&count).Error
|
err := r.db.Raw("SELECT COUNT(*) FROM information_schema.columns WHERE table_name = 'tasks' AND column_name = 'message'").Count(&count).Error
|
||||||
if err != nil {
|
if err != nil {
|
||||||
// 如果检查失败,只更新状态
|
// 如果检查失败,只更新状态
|
||||||
return r.db.Model(&entity.Task{}).Where("id = ?", id).Update("status", status).Error
|
updateStart := utils.GetCurrentTime()
|
||||||
|
err := r.db.Model(&entity.Task{}).Where("id = ?", id).Update("status", status).Error
|
||||||
|
updateDuration := time.Since(updateStart)
|
||||||
|
totalDuration := time.Since(startTime)
|
||||||
|
if err != nil {
|
||||||
|
utils.Error("UpdateStatusAndMessage失败(检查失败): ID=%d, 状态=%s, 错误=%v, 更新耗时=%v, 总耗时=%v", id, status, err, updateDuration, totalDuration)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
utils.Debug("UpdateStatusAndMessage成功(检查失败): ID=%d, 状态=%s, 更新耗时=%v, 总耗时=%v", id, status, updateDuration, totalDuration)
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
if count > 0 {
|
if count > 0 {
|
||||||
// message字段存在,更新状态和消息
|
// message字段存在,更新状态和消息
|
||||||
return r.db.Model(&entity.Task{}).Where("id = ?", id).Updates(map[string]interface{}{
|
updateStart := utils.GetCurrentTime()
|
||||||
|
err := r.db.Model(&entity.Task{}).Where("id = ?", id).Updates(map[string]interface{}{
|
||||||
"status": status,
|
"status": status,
|
||||||
"message": message,
|
"message": message,
|
||||||
}).Error
|
}).Error
|
||||||
|
updateDuration := time.Since(updateStart)
|
||||||
|
totalDuration := time.Since(startTime)
|
||||||
|
if err != nil {
|
||||||
|
utils.Error("UpdateStatusAndMessage失败(字段存在): ID=%d, 状态=%s, 错误=%v, 更新耗时=%v, 总耗时=%v", id, status, err, updateDuration, totalDuration)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
utils.Debug("UpdateStatusAndMessage成功(字段存在): ID=%d, 状态=%s, 更新耗时=%v, 总耗时=%v", id, status, updateDuration, totalDuration)
|
||||||
|
return nil
|
||||||
} else {
|
} else {
|
||||||
// message字段不存在,只更新状态
|
// message字段不存在,只更新状态
|
||||||
return r.db.Model(&entity.Task{}).Where("id = ?", id).Update("status", status).Error
|
updateStart := utils.GetCurrentTime()
|
||||||
|
err := r.db.Model(&entity.Task{}).Where("id = ?", id).Update("status", status).Error
|
||||||
|
updateDuration := time.Since(updateStart)
|
||||||
|
totalDuration := time.Since(startTime)
|
||||||
|
if err != nil {
|
||||||
|
utils.Error("UpdateStatusAndMessage失败(字段不存在): ID=%d, 状态=%s, 错误=%v, 更新耗时=%v, 总耗时=%v", id, status, err, updateDuration, totalDuration)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
utils.Debug("UpdateStatusAndMessage成功(字段不存在): ID=%d, 状态=%s, 更新耗时=%v, 总耗时=%v", id, status, updateDuration, totalDuration)
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// UpdateTaskStats 更新任务统计信息
|
// UpdateTaskStats 更新任务统计信息
|
||||||
func (r *TaskRepositoryImpl) UpdateTaskStats(id uint, processed, success, failed int) error {
|
func (r *TaskRepositoryImpl) UpdateTaskStats(id uint, processed, success, failed int) error {
|
||||||
return r.db.Model(&entity.Task{}).Where("id = ?", id).Updates(map[string]interface{}{
|
startTime := utils.GetCurrentTime()
|
||||||
|
err := r.db.Model(&entity.Task{}).Where("id = ?", id).Updates(map[string]interface{}{
|
||||||
"processed_items": processed,
|
"processed_items": processed,
|
||||||
"success_items": success,
|
"success_items": success,
|
||||||
"failed_items": failed,
|
"failed_items": failed,
|
||||||
}).Error
|
}).Error
|
||||||
|
updateDuration := time.Since(startTime)
|
||||||
|
if err != nil {
|
||||||
|
utils.Error("UpdateTaskStats失败: ID=%d, 处理数=%d, 成功数=%d, 失败数=%d, 错误=%v, 更新耗时=%v", id, processed, success, failed, err, updateDuration)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
utils.Debug("UpdateTaskStats成功: ID=%d, 处理数=%d, 成功数=%d, 失败数=%d, 更新耗时=%v", id, processed, success, failed, updateDuration)
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// UpdateStartedAt 更新任务开始时间
|
// UpdateStartedAt 更新任务开始时间
|
||||||
func (r *TaskRepositoryImpl) UpdateStartedAt(id uint) error {
|
func (r *TaskRepositoryImpl) UpdateStartedAt(id uint) error {
|
||||||
|
startTime := utils.GetCurrentTime()
|
||||||
now := time.Now()
|
now := time.Now()
|
||||||
return r.db.Model(&entity.Task{}).Where("id = ?", id).Update("started_at", now).Error
|
err := r.db.Model(&entity.Task{}).Where("id = ?", id).Update("started_at", now).Error
|
||||||
|
updateDuration := time.Since(startTime)
|
||||||
|
if err != nil {
|
||||||
|
utils.Error("UpdateStartedAt失败: ID=%d, 错误=%v, 更新耗时=%v", id, err, updateDuration)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
utils.Debug("UpdateStartedAt成功: ID=%d, 更新耗时=%v", id, updateDuration)
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// UpdateCompletedAt 更新任务完成时间
|
// UpdateCompletedAt 更新任务完成时间
|
||||||
func (r *TaskRepositoryImpl) UpdateCompletedAt(id uint) error {
|
func (r *TaskRepositoryImpl) UpdateCompletedAt(id uint) error {
|
||||||
|
startTime := utils.GetCurrentTime()
|
||||||
now := time.Now()
|
now := time.Now()
|
||||||
return r.db.Model(&entity.Task{}).Where("id = ?", id).Update("completed_at", now).Error
|
err := r.db.Model(&entity.Task{}).Where("id = ?", id).Update("completed_at", now).Error
|
||||||
|
updateDuration := time.Since(startTime)
|
||||||
|
if err != nil {
|
||||||
|
utils.Error("UpdateCompletedAt失败: ID=%d, 错误=%v, 更新耗时=%v", id, err, updateDuration)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
utils.Debug("UpdateCompletedAt成功: ID=%d, 更新耗时=%v", id, updateDuration)
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|||||||
132
docs/logging.md
Normal file
132
docs/logging.md
Normal file
@@ -0,0 +1,132 @@
|
|||||||
|
# 日志系统说明
|
||||||
|
|
||||||
|
## 概述
|
||||||
|
|
||||||
|
本项目使用自定义的日志系统,支持多种日志级别、环境差异化配置和结构化日志记录。
|
||||||
|
|
||||||
|
## 日志级别
|
||||||
|
|
||||||
|
日志系统支持以下级别(按严重程度递增):
|
||||||
|
|
||||||
|
1. **DEBUG** - 调试信息,用于开发和故障排除
|
||||||
|
2. **INFO** - 一般信息,记录系统正常运行状态
|
||||||
|
3. **WARN** - 警告信息,表示可能的问题但不影响系统运行
|
||||||
|
4. **ERROR** - 错误信息,表示系统错误但可以继续运行
|
||||||
|
5. **FATAL** - 致命错误,系统将退出
|
||||||
|
|
||||||
|
## 环境配置
|
||||||
|
|
||||||
|
### 日志级别配置
|
||||||
|
|
||||||
|
可以通过环境变量配置日志级别:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# 设置日志级别(DEBUG, INFO, WARN, ERROR, FATAL)
|
||||||
|
LOG_LEVEL=DEBUG
|
||||||
|
|
||||||
|
# 或者启用调试模式(等同于DEBUG级别)
|
||||||
|
DEBUG=true
|
||||||
|
```
|
||||||
|
|
||||||
|
默认情况下,开发环境使用DEBUG级别,生产环境使用INFO级别。
|
||||||
|
|
||||||
|
### 结构化日志
|
||||||
|
|
||||||
|
可以通过环境变量启用结构化日志(JSON格式):
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# 启用结构化日志
|
||||||
|
STRUCTURED_LOG=true
|
||||||
|
```
|
||||||
|
|
||||||
|
## 使用方法
|
||||||
|
|
||||||
|
### 基本日志记录
|
||||||
|
|
||||||
|
```go
|
||||||
|
import "github.com/ctwj/urldb/utils"
|
||||||
|
|
||||||
|
// 基本日志记录
|
||||||
|
utils.Debug("调试信息: %s", debugInfo)
|
||||||
|
utils.Info("一般信息: %s", info)
|
||||||
|
utils.Warn("警告信息: %s", warning)
|
||||||
|
utils.Error("错误信息: %s", err)
|
||||||
|
utils.Fatal("致命错误: %s", fatalErr) // 程序将退出
|
||||||
|
```
|
||||||
|
|
||||||
|
### 结构化日志记录
|
||||||
|
|
||||||
|
结构化日志允许添加额外的字段信息,便于日志分析:
|
||||||
|
|
||||||
|
```go
|
||||||
|
// 带字段的结构化日志
|
||||||
|
utils.DebugWithFields(map[string]interface{}{
|
||||||
|
"user_id": 123,
|
||||||
|
"action": "login",
|
||||||
|
"ip": "192.168.1.1",
|
||||||
|
}, "用户登录调试信息")
|
||||||
|
|
||||||
|
utils.InfoWithFields(map[string]interface{}{
|
||||||
|
"task_id": 456,
|
||||||
|
"status": "completed",
|
||||||
|
"duration_ms": 1250,
|
||||||
|
}, "任务处理完成")
|
||||||
|
|
||||||
|
utils.ErrorWithFields(map[string]interface{}{
|
||||||
|
"error_code": 500,
|
||||||
|
"error": "database connection failed",
|
||||||
|
"component": "database",
|
||||||
|
}, "数据库连接失败: %v", err)
|
||||||
|
```
|
||||||
|
|
||||||
|
## 日志输出
|
||||||
|
|
||||||
|
日志默认输出到:
|
||||||
|
- 控制台(标准输出)
|
||||||
|
- 文件(logs目录下的app_日期.log文件)
|
||||||
|
|
||||||
|
日志文件支持轮转,单个文件最大100MB,最多保留5个备份文件,日志文件最长保留30天。
|
||||||
|
|
||||||
|
## 最佳实践
|
||||||
|
|
||||||
|
1. **选择合适的日志级别**:
|
||||||
|
- DEBUG:详细的调试信息,仅在开发和故障排除时使用
|
||||||
|
- INFO:重要的业务流程和状态变更
|
||||||
|
- WARN:可预期的问题和异常情况
|
||||||
|
- ERROR:系统错误和异常
|
||||||
|
- FATAL:系统无法继续运行的致命错误
|
||||||
|
|
||||||
|
2. **使用结构化日志**:
|
||||||
|
- 对于需要后续分析的日志,使用结构化日志
|
||||||
|
- 添加有意义的字段,如用户ID、任务ID、请求ID等
|
||||||
|
- 避免在字段中包含敏感信息
|
||||||
|
|
||||||
|
3. **性能监控**:
|
||||||
|
- 记录关键操作的执行时间
|
||||||
|
- 使用duration_ms字段记录毫秒级耗时
|
||||||
|
|
||||||
|
4. **安全日志**:
|
||||||
|
- 记录所有认证和授权相关的操作
|
||||||
|
- 包含客户端IP和用户信息
|
||||||
|
- 记录失败的访问尝试
|
||||||
|
|
||||||
|
## 示例
|
||||||
|
|
||||||
|
```go
|
||||||
|
// 性能监控示例
|
||||||
|
startTime := time.Now()
|
||||||
|
// 执行操作...
|
||||||
|
duration := time.Since(startTime)
|
||||||
|
utils.DebugWithFields(map[string]interface{}{
|
||||||
|
"operation": "database_query",
|
||||||
|
"duration_ms": duration.Milliseconds(),
|
||||||
|
}, "数据库查询完成,耗时: %v", duration)
|
||||||
|
|
||||||
|
// 安全日志示例
|
||||||
|
utils.InfoWithFields(map[string]interface{}{
|
||||||
|
"user_id": userID,
|
||||||
|
"ip": clientIP,
|
||||||
|
"action": "login",
|
||||||
|
"status": "success",
|
||||||
|
}, "用户登录成功 - 用户ID: %d, IP: %s", userID, clientIP)
|
||||||
|
```
|
||||||
@@ -15,3 +15,8 @@ TIMEZONE=Asia/Shanghai
|
|||||||
# 文件上传配置
|
# 文件上传配置
|
||||||
UPLOAD_DIR=./uploads
|
UPLOAD_DIR=./uploads
|
||||||
MAX_FILE_SIZE=5MB
|
MAX_FILE_SIZE=5MB
|
||||||
|
|
||||||
|
# 日志配置
|
||||||
|
LOG_LEVEL=INFO # 日志级别 (DEBUG, INFO, WARN, ERROR, FATAL)
|
||||||
|
DEBUG=false # 调试模式开关
|
||||||
|
STRUCTURED_LOG=false
|
||||||
@@ -148,6 +148,11 @@ func (h *PublicAPIHandler) AddBatchResources(c *gin.Context) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 记录API访问安全日志
|
||||||
|
clientIP := c.ClientIP()
|
||||||
|
userAgent := c.GetHeader("User-Agent")
|
||||||
|
utils.Info("PublicAPI.AddBatchResources - API访问 - IP: %s, UserAgent: %s, 资源数量: %d", clientIP, userAgent, len(req.Resources))
|
||||||
|
|
||||||
// 收集所有待提交的URL,去重
|
// 收集所有待提交的URL,去重
|
||||||
urlSet := make(map[string]struct{})
|
urlSet := make(map[string]struct{})
|
||||||
for _, resource := range req.Resources {
|
for _, resource := range req.Resources {
|
||||||
@@ -238,7 +243,9 @@ func (h *PublicAPIHandler) AddBatchResources(c *gin.Context) {
|
|||||||
func (h *PublicAPIHandler) SearchResources(c *gin.Context) {
|
func (h *PublicAPIHandler) SearchResources(c *gin.Context) {
|
||||||
startTime := time.Now()
|
startTime := time.Now()
|
||||||
|
|
||||||
// 获取查询参数
|
// 记录API访问安全日志
|
||||||
|
clientIP := c.ClientIP()
|
||||||
|
userAgent := c.GetHeader("User-Agent")
|
||||||
keyword := c.Query("keyword")
|
keyword := c.Query("keyword")
|
||||||
tag := c.Query("tag")
|
tag := c.Query("tag")
|
||||||
category := c.Query("category")
|
category := c.Query("category")
|
||||||
@@ -246,6 +253,9 @@ func (h *PublicAPIHandler) SearchResources(c *gin.Context) {
|
|||||||
pageStr := c.DefaultQuery("page", "1")
|
pageStr := c.DefaultQuery("page", "1")
|
||||||
pageSizeStr := c.DefaultQuery("page_size", "20")
|
pageSizeStr := c.DefaultQuery("page_size", "20")
|
||||||
|
|
||||||
|
utils.Info("PublicAPI.SearchResources - API访问 - IP: %s, UserAgent: %s, Keyword: %s, Tag: %s, Category: %s, PanID: %s",
|
||||||
|
clientIP, userAgent, keyword, tag, category, panID)
|
||||||
|
|
||||||
page, err := strconv.Atoi(pageStr)
|
page, err := strconv.Atoi(pageStr)
|
||||||
if err != nil || page < 1 {
|
if err != nil || page < 1 {
|
||||||
page = 1
|
page = 1
|
||||||
@@ -402,9 +412,14 @@ func (h *PublicAPIHandler) SearchResources(c *gin.Context) {
|
|||||||
func (h *PublicAPIHandler) GetHotDramas(c *gin.Context) {
|
func (h *PublicAPIHandler) GetHotDramas(c *gin.Context) {
|
||||||
startTime := time.Now()
|
startTime := time.Now()
|
||||||
|
|
||||||
|
// 记录API访问安全日志
|
||||||
|
clientIP := c.ClientIP()
|
||||||
|
userAgent := c.GetHeader("User-Agent")
|
||||||
pageStr := c.DefaultQuery("page", "1")
|
pageStr := c.DefaultQuery("page", "1")
|
||||||
pageSizeStr := c.DefaultQuery("page_size", "20")
|
pageSizeStr := c.DefaultQuery("page_size", "20")
|
||||||
|
|
||||||
|
utils.Info("PublicAPI.GetHotDramas - API访问 - IP: %s, UserAgent: %s", clientIP, userAgent)
|
||||||
|
|
||||||
page, err := strconv.Atoi(pageStr)
|
page, err := strconv.Atoi(pageStr)
|
||||||
if err != nil || page < 1 {
|
if err != nil || page < 1 {
|
||||||
page = 1
|
page = 1
|
||||||
|
|||||||
@@ -130,6 +130,10 @@ func UpdateSystemConfig(c *gin.Context) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
adminUsername, _ := c.Get("username")
|
||||||
|
clientIP, _ := c.Get("client_ip")
|
||||||
|
utils.Info("UpdateSystemConfig - 管理员更新系统配置 - 管理员: %s, IP: %s", adminUsername, clientIP)
|
||||||
|
|
||||||
// 调试信息
|
// 调试信息
|
||||||
utils.Info("接收到的配置请求: %+v", req)
|
utils.Info("接收到的配置请求: %+v", req)
|
||||||
|
|
||||||
@@ -320,6 +324,10 @@ func ToggleAutoProcess(c *gin.Context) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
adminUsername, _ := c.Get("username")
|
||||||
|
clientIP, _ := c.Get("client_ip")
|
||||||
|
utils.Info("ToggleAutoProcess - 管理员切换自动处理配置 - 管理员: %s, 启用: %t, IP: %s", adminUsername, req.AutoProcessReadyResources, clientIP)
|
||||||
|
|
||||||
// 获取当前配置
|
// 获取当前配置
|
||||||
configs, err := repoManager.SystemConfigRepository.GetOrCreateDefault()
|
configs, err := repoManager.SystemConfigRepository.GetOrCreateDefault()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|||||||
@@ -51,6 +51,10 @@ func (h *TaskHandler) CreateBatchTransferTask(c *gin.Context) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
username, _ := c.Get("username")
|
||||||
|
clientIP, _ := c.Get("client_ip")
|
||||||
|
utils.Info("CreateBatchTransferTask - 用户创建批量转存任务 - 用户: %s, 任务标题: %s, 资源数量: %d, IP: %s", username, req.Title, len(req.Resources), clientIP)
|
||||||
|
|
||||||
utils.Debug("创建批量转存任务: %s,资源数量: %d,选择账号数量: %d", req.Title, len(req.Resources), len(req.SelectedAccounts))
|
utils.Debug("创建批量转存任务: %s,资源数量: %d,选择账号数量: %d", req.Title, len(req.Resources), len(req.SelectedAccounts))
|
||||||
|
|
||||||
// 构建任务配置
|
// 构建任务配置
|
||||||
@@ -124,6 +128,10 @@ func (h *TaskHandler) StartTask(c *gin.Context) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
username, _ := c.Get("username")
|
||||||
|
clientIP, _ := c.Get("client_ip")
|
||||||
|
utils.Info("StartTask - 用户启动任务 - 用户: %s, 任务ID: %d, IP: %s", username, taskID, clientIP)
|
||||||
|
|
||||||
err = h.taskManager.StartTask(uint(taskID))
|
err = h.taskManager.StartTask(uint(taskID))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
utils.Error("启动任务失败: %v", err)
|
utils.Error("启动任务失败: %v", err)
|
||||||
@@ -147,6 +155,10 @@ func (h *TaskHandler) StopTask(c *gin.Context) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
username, _ := c.Get("username")
|
||||||
|
clientIP, _ := c.Get("client_ip")
|
||||||
|
utils.Info("StopTask - 用户停止任务 - 用户: %s, 任务ID: %d, IP: %s", username, taskID, clientIP)
|
||||||
|
|
||||||
err = h.taskManager.StopTask(uint(taskID))
|
err = h.taskManager.StopTask(uint(taskID))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
utils.Error("停止任务失败: %v", err)
|
utils.Error("停止任务失败: %v", err)
|
||||||
@@ -170,6 +182,10 @@ func (h *TaskHandler) PauseTask(c *gin.Context) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
username, _ := c.Get("username")
|
||||||
|
clientIP, _ := c.Get("client_ip")
|
||||||
|
utils.Info("PauseTask - 用户暂停任务 - 用户: %s, 任务ID: %d, IP: %s", username, taskID, clientIP)
|
||||||
|
|
||||||
err = h.taskManager.PauseTask(uint(taskID))
|
err = h.taskManager.PauseTask(uint(taskID))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
utils.Error("暂停任务失败: %v", err)
|
utils.Error("暂停任务失败: %v", err)
|
||||||
@@ -360,8 +376,13 @@ func (h *TaskHandler) DeleteTask(c *gin.Context) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
username, _ := c.Get("username")
|
||||||
|
clientIP, _ := c.Get("client_ip")
|
||||||
|
utils.Info("DeleteTask - 用户删除任务 - 用户: %s, 任务ID: %d, IP: %s", username, taskID, clientIP)
|
||||||
|
|
||||||
// 检查任务是否在运行
|
// 检查任务是否在运行
|
||||||
if h.taskManager.IsTaskRunning(uint(taskID)) {
|
if h.taskManager.IsTaskRunning(uint(taskID)) {
|
||||||
|
utils.Warn("DeleteTask - 尝试删除正在运行的任务 - 用户: %s, 任务ID: %d, IP: %s", username, taskID, clientIP)
|
||||||
ErrorResponse(c, "任务正在运行中,无法删除", http.StatusBadRequest)
|
ErrorResponse(c, "任务正在运行中,无法删除", http.StatusBadRequest)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -383,6 +404,7 @@ func (h *TaskHandler) DeleteTask(c *gin.Context) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
utils.Debug("任务删除成功: %d", taskID)
|
utils.Debug("任务删除成功: %d", taskID)
|
||||||
|
utils.Info("DeleteTask - 任务删除成功 - 用户: %s, 任务ID: %d, IP: %s", username, taskID, clientIP)
|
||||||
|
|
||||||
SuccessResponse(c, gin.H{
|
SuccessResponse(c, gin.H{
|
||||||
"message": "任务删除成功",
|
"message": "任务删除成功",
|
||||||
@@ -402,6 +424,10 @@ func (h *TaskHandler) CreateExpansionTask(c *gin.Context) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
username, _ := c.Get("username")
|
||||||
|
clientIP, _ := c.Get("client_ip")
|
||||||
|
utils.Info("CreateExpansionTask - 用户创建扩容任务 - 用户: %s, 账号ID: %d, IP: %s", username, req.PanAccountID, clientIP)
|
||||||
|
|
||||||
utils.Debug("创建扩容任务: 账号ID %d", req.PanAccountID)
|
utils.Debug("创建扩容任务: 账号ID %d", req.PanAccountID)
|
||||||
|
|
||||||
// 获取账号信息,用于构建任务标题
|
// 获取账号信息,用于构建任务标题
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
package handlers
|
package handlers
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"fmt"
|
||||||
"net/http"
|
"net/http"
|
||||||
"strconv"
|
"strconv"
|
||||||
|
|
||||||
@@ -8,6 +9,7 @@ import (
|
|||||||
"github.com/ctwj/urldb/db/dto"
|
"github.com/ctwj/urldb/db/dto"
|
||||||
"github.com/ctwj/urldb/db/entity"
|
"github.com/ctwj/urldb/db/entity"
|
||||||
"github.com/ctwj/urldb/middleware"
|
"github.com/ctwj/urldb/middleware"
|
||||||
|
"github.com/ctwj/urldb/utils"
|
||||||
|
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
)
|
)
|
||||||
@@ -20,18 +22,24 @@ func Login(c *gin.Context) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
clientIP, _ := c.Get("client_ip")
|
||||||
|
utils.Info("Login - 尝试登录 - 用户名: %s, IP: %s", req.Username, clientIP)
|
||||||
|
|
||||||
user, err := repoManager.UserRepository.FindByUsername(req.Username)
|
user, err := repoManager.UserRepository.FindByUsername(req.Username)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
utils.Warn("Login - 用户不存在或密码错误 - 用户名: %s, IP: %s", req.Username, clientIP)
|
||||||
ErrorResponse(c, "用户名或密码错误", http.StatusUnauthorized)
|
ErrorResponse(c, "用户名或密码错误", http.StatusUnauthorized)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if !user.IsActive {
|
if !user.IsActive {
|
||||||
|
utils.Warn("Login - 账户已被禁用 - 用户名: %s, IP: %s", req.Username, clientIP)
|
||||||
ErrorResponse(c, "账户已被禁用", http.StatusUnauthorized)
|
ErrorResponse(c, "账户已被禁用", http.StatusUnauthorized)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if !middleware.CheckPassword(req.Password, user.Password) {
|
if !middleware.CheckPassword(req.Password, user.Password) {
|
||||||
|
utils.Warn("Login - 密码错误 - 用户名: %s, IP: %s", req.Username, clientIP)
|
||||||
ErrorResponse(c, "用户名或密码错误", http.StatusUnauthorized)
|
ErrorResponse(c, "用户名或密码错误", http.StatusUnauthorized)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -42,10 +50,13 @@ func Login(c *gin.Context) {
|
|||||||
// 生成JWT令牌
|
// 生成JWT令牌
|
||||||
token, err := middleware.GenerateToken(user)
|
token, err := middleware.GenerateToken(user)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
utils.Error("Login - 生成令牌失败 - 用户名: %s, IP: %s, Error: %v", req.Username, clientIP, err)
|
||||||
ErrorResponse(c, "生成令牌失败", http.StatusInternalServerError)
|
ErrorResponse(c, "生成令牌失败", http.StatusInternalServerError)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
utils.Info("Login - 登录成功 - 用户名: %s(ID:%d), IP: %s", req.Username, user.ID, clientIP)
|
||||||
|
|
||||||
response := dto.LoginResponse{
|
response := dto.LoginResponse{
|
||||||
Token: token,
|
Token: token,
|
||||||
User: converter.ToUserResponse(user),
|
User: converter.ToUserResponse(user),
|
||||||
@@ -62,9 +73,13 @@ func Register(c *gin.Context) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
clientIP, _ := c.Get("client_ip")
|
||||||
|
utils.Info("Register - 尝试注册 - 用户名: %s, 邮箱: %s, IP: %s", req.Username, req.Email, clientIP)
|
||||||
|
|
||||||
// 检查用户名是否已存在
|
// 检查用户名是否已存在
|
||||||
existingUser, _ := repoManager.UserRepository.FindByUsername(req.Username)
|
existingUser, _ := repoManager.UserRepository.FindByUsername(req.Username)
|
||||||
if existingUser != nil {
|
if existingUser != nil {
|
||||||
|
utils.Warn("Register - 用户名已存在 - 用户名: %s, IP: %s", req.Username, clientIP)
|
||||||
ErrorResponse(c, "用户名已存在", http.StatusBadRequest)
|
ErrorResponse(c, "用户名已存在", http.StatusBadRequest)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -72,6 +87,7 @@ func Register(c *gin.Context) {
|
|||||||
// 检查邮箱是否已存在
|
// 检查邮箱是否已存在
|
||||||
existingEmail, _ := repoManager.UserRepository.FindByEmail(req.Email)
|
existingEmail, _ := repoManager.UserRepository.FindByEmail(req.Email)
|
||||||
if existingEmail != nil {
|
if existingEmail != nil {
|
||||||
|
utils.Warn("Register - 邮箱已存在 - 邮箱: %s, IP: %s", req.Email, clientIP)
|
||||||
ErrorResponse(c, "邮箱已存在", http.StatusBadRequest)
|
ErrorResponse(c, "邮箱已存在", http.StatusBadRequest)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -79,6 +95,7 @@ func Register(c *gin.Context) {
|
|||||||
// 哈希密码
|
// 哈希密码
|
||||||
hashedPassword, err := middleware.HashPassword(req.Password)
|
hashedPassword, err := middleware.HashPassword(req.Password)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
utils.Error("Register - 密码加密失败 - 用户名: %s, IP: %s, Error: %v", req.Username, clientIP, err)
|
||||||
ErrorResponse(c, "密码加密失败", http.StatusInternalServerError)
|
ErrorResponse(c, "密码加密失败", http.StatusInternalServerError)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -93,10 +110,13 @@ func Register(c *gin.Context) {
|
|||||||
|
|
||||||
err = repoManager.UserRepository.Create(user)
|
err = repoManager.UserRepository.Create(user)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
utils.Error("Register - 创建用户失败 - 用户名: %s, IP: %s, Error: %v", req.Username, clientIP, err)
|
||||||
ErrorResponse(c, err.Error(), http.StatusInternalServerError)
|
ErrorResponse(c, err.Error(), http.StatusInternalServerError)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
utils.Info("Register - 注册成功 - 用户名: %s(ID:%d), 邮箱: %s, IP: %s", req.Username, user.ID, req.Email, clientIP)
|
||||||
|
|
||||||
SuccessResponse(c, gin.H{
|
SuccessResponse(c, gin.H{
|
||||||
"message": "注册成功",
|
"message": "注册成功",
|
||||||
"user": converter.ToUserResponse(user),
|
"user": converter.ToUserResponse(user),
|
||||||
@@ -123,9 +143,14 @@ func CreateUser(c *gin.Context) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
adminUsername, _ := c.Get("username")
|
||||||
|
clientIP, _ := c.Get("client_ip")
|
||||||
|
utils.Info("CreateUser - 管理员创建用户 - 管理员: %s, 新用户名: %s, IP: %s", adminUsername, req.Username, clientIP)
|
||||||
|
|
||||||
// 检查用户名是否已存在
|
// 检查用户名是否已存在
|
||||||
existingUser, _ := repoManager.UserRepository.FindByUsername(req.Username)
|
existingUser, _ := repoManager.UserRepository.FindByUsername(req.Username)
|
||||||
if existingUser != nil {
|
if existingUser != nil {
|
||||||
|
utils.Warn("CreateUser - 用户名已存在 - 管理员: %s, 用户名: %s, IP: %s", adminUsername, req.Username, clientIP)
|
||||||
ErrorResponse(c, "用户名已存在", http.StatusBadRequest)
|
ErrorResponse(c, "用户名已存在", http.StatusBadRequest)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -133,6 +158,7 @@ func CreateUser(c *gin.Context) {
|
|||||||
// 检查邮箱是否已存在
|
// 检查邮箱是否已存在
|
||||||
existingEmail, _ := repoManager.UserRepository.FindByEmail(req.Email)
|
existingEmail, _ := repoManager.UserRepository.FindByEmail(req.Email)
|
||||||
if existingEmail != nil {
|
if existingEmail != nil {
|
||||||
|
utils.Warn("CreateUser - 邮箱已存在 - 管理员: %s, 邮箱: %s, IP: %s", adminUsername, req.Email, clientIP)
|
||||||
ErrorResponse(c, "邮箱已存在", http.StatusBadRequest)
|
ErrorResponse(c, "邮箱已存在", http.StatusBadRequest)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -140,6 +166,7 @@ func CreateUser(c *gin.Context) {
|
|||||||
// 哈希密码
|
// 哈希密码
|
||||||
hashedPassword, err := middleware.HashPassword(req.Password)
|
hashedPassword, err := middleware.HashPassword(req.Password)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
utils.Error("CreateUser - 密码加密失败 - 管理员: %s, 用户名: %s, IP: %s, Error: %v", adminUsername, req.Username, clientIP, err)
|
||||||
ErrorResponse(c, "密码加密失败", http.StatusInternalServerError)
|
ErrorResponse(c, "密码加密失败", http.StatusInternalServerError)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -154,10 +181,13 @@ func CreateUser(c *gin.Context) {
|
|||||||
|
|
||||||
err = repoManager.UserRepository.Create(user)
|
err = repoManager.UserRepository.Create(user)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
utils.Error("CreateUser - 创建用户失败 - 管理员: %s, 用户名: %s, IP: %s, Error: %v", adminUsername, req.Username, clientIP, err)
|
||||||
ErrorResponse(c, err.Error(), http.StatusInternalServerError)
|
ErrorResponse(c, err.Error(), http.StatusInternalServerError)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
utils.Info("CreateUser - 用户创建成功 - 管理员: %s, 用户名: %s(ID:%d), 角色: %s, IP: %s", adminUsername, req.Username, user.ID, req.Role, clientIP)
|
||||||
|
|
||||||
SuccessResponse(c, gin.H{
|
SuccessResponse(c, gin.H{
|
||||||
"message": "用户创建成功",
|
"message": "用户创建成功",
|
||||||
"user": converter.ToUserResponse(user),
|
"user": converter.ToUserResponse(user),
|
||||||
@@ -179,12 +209,21 @@ func UpdateUser(c *gin.Context) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
adminUsername, _ := c.Get("username")
|
||||||
|
clientIP, _ := c.Get("client_ip")
|
||||||
|
utils.Info("UpdateUser - 管理员更新用户 - 管理员: %s, 目标用户ID: %d, IP: %s", adminUsername, id, clientIP)
|
||||||
|
|
||||||
user, err := repoManager.UserRepository.FindByID(uint(id))
|
user, err := repoManager.UserRepository.FindByID(uint(id))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
utils.Warn("UpdateUser - 目标用户不存在 - 管理员: %s, 用户ID: %d, IP: %s", adminUsername, id, clientIP)
|
||||||
ErrorResponse(c, "用户不存在", http.StatusNotFound)
|
ErrorResponse(c, "用户不存在", http.StatusNotFound)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 记录变更前的信息
|
||||||
|
oldInfo := fmt.Sprintf("用户名:%s,邮箱:%s,角色:%s,状态:%t", user.Username, user.Email, user.Role, user.IsActive)
|
||||||
|
utils.Debug("UpdateUser - 更新前用户信息 - 管理员: %s, 用户ID: %d, 信息: %s", adminUsername, id, oldInfo)
|
||||||
|
|
||||||
if req.Username != "" {
|
if req.Username != "" {
|
||||||
user.Username = req.Username
|
user.Username = req.Username
|
||||||
}
|
}
|
||||||
@@ -198,10 +237,15 @@ func UpdateUser(c *gin.Context) {
|
|||||||
|
|
||||||
err = repoManager.UserRepository.Update(user)
|
err = repoManager.UserRepository.Update(user)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
utils.Error("UpdateUser - 更新用户失败 - 管理员: %s, 用户ID: %d, IP: %s, Error: %v", adminUsername, id, clientIP, err)
|
||||||
ErrorResponse(c, err.Error(), http.StatusInternalServerError)
|
ErrorResponse(c, err.Error(), http.StatusInternalServerError)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 记录变更后信息
|
||||||
|
newInfo := fmt.Sprintf("用户名:%s,邮箱:%s,角色:%s,状态:%t", user.Username, user.Email, user.Role, user.IsActive)
|
||||||
|
utils.Info("UpdateUser - 用户更新成功 - 管理员: %s, 用户ID: %d, 更新前: %s, 更新后: %s, IP: %s", adminUsername, id, oldInfo, newInfo, clientIP)
|
||||||
|
|
||||||
SuccessResponse(c, gin.H{"message": "用户更新成功"})
|
SuccessResponse(c, gin.H{"message": "用户更新成功"})
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -220,8 +264,13 @@ func ChangePassword(c *gin.Context) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
adminUsername, _ := c.Get("username")
|
||||||
|
clientIP, _ := c.Get("client_ip")
|
||||||
|
utils.Info("ChangePassword - 管理员修改用户密码 - 管理员: %s, 目标用户ID: %d, IP: %s", adminUsername, id, clientIP)
|
||||||
|
|
||||||
user, err := repoManager.UserRepository.FindByID(uint(id))
|
user, err := repoManager.UserRepository.FindByID(uint(id))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
utils.Warn("ChangePassword - 目标用户不存在 - 管理员: %s, 用户ID: %d, IP: %s", adminUsername, id, clientIP)
|
||||||
ErrorResponse(c, "用户不存在", http.StatusNotFound)
|
ErrorResponse(c, "用户不存在", http.StatusNotFound)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -229,6 +278,7 @@ func ChangePassword(c *gin.Context) {
|
|||||||
// 哈希新密码
|
// 哈希新密码
|
||||||
hashedPassword, err := middleware.HashPassword(req.NewPassword)
|
hashedPassword, err := middleware.HashPassword(req.NewPassword)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
utils.Error("ChangePassword - 密码加密失败 - 管理员: %s, 用户ID: %d, IP: %s, Error: %v", adminUsername, id, clientIP, err)
|
||||||
ErrorResponse(c, "密码加密失败", http.StatusInternalServerError)
|
ErrorResponse(c, "密码加密失败", http.StatusInternalServerError)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -236,10 +286,13 @@ func ChangePassword(c *gin.Context) {
|
|||||||
user.Password = hashedPassword
|
user.Password = hashedPassword
|
||||||
err = repoManager.UserRepository.Update(user)
|
err = repoManager.UserRepository.Update(user)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
utils.Error("ChangePassword - 更新密码失败 - 管理员: %s, 用户ID: %d, IP: %s, Error: %v", adminUsername, id, clientIP, err)
|
||||||
ErrorResponse(c, err.Error(), http.StatusInternalServerError)
|
ErrorResponse(c, err.Error(), http.StatusInternalServerError)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
utils.Info("ChangePassword - 密码修改成功 - 管理员: %s, 用户名: %s(ID:%d), IP: %s", adminUsername, user.Username, id, clientIP)
|
||||||
|
|
||||||
SuccessResponse(c, gin.H{"message": "密码修改成功"})
|
SuccessResponse(c, gin.H{"message": "密码修改成功"})
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -252,12 +305,27 @@ func DeleteUser(c *gin.Context) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
adminUsername, _ := c.Get("username")
|
||||||
|
clientIP, _ := c.Get("client_ip")
|
||||||
|
utils.Info("DeleteUser - 管理员删除用户 - 管理员: %s, 目标用户ID: %d, IP: %s", adminUsername, id, clientIP)
|
||||||
|
|
||||||
|
// 先获取用户信息用于日志记录
|
||||||
|
user, err := repoManager.UserRepository.FindByID(uint(id))
|
||||||
|
if err != nil {
|
||||||
|
utils.Warn("DeleteUser - 目标用户不存在 - 管理员: %s, 用户ID: %d, IP: %s", adminUsername, id, clientIP)
|
||||||
|
ErrorResponse(c, "用户不存在", http.StatusNotFound)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
err = repoManager.UserRepository.Delete(uint(id))
|
err = repoManager.UserRepository.Delete(uint(id))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
utils.Error("DeleteUser - 删除用户失败 - 管理员: %s, 用户ID: %d, IP: %s, Error: %v", adminUsername, id, clientIP, err)
|
||||||
ErrorResponse(c, err.Error(), http.StatusInternalServerError)
|
ErrorResponse(c, err.Error(), http.StatusInternalServerError)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
utils.Info("DeleteUser - 用户删除成功 - 管理员: %s, 用户名: %s(ID:%d), IP: %s", adminUsername, user.Username, id, clientIP)
|
||||||
|
|
||||||
SuccessResponse(c, gin.H{"message": "用户删除成功"})
|
SuccessResponse(c, gin.H{"message": "用户删除成功"})
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -269,12 +337,18 @@ func GetProfile(c *gin.Context) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
username, _ := c.Get("username")
|
||||||
|
clientIP, _ := c.Get("client_ip")
|
||||||
|
utils.Info("GetProfile - 用户获取个人资料 - 用户名: %s(ID:%d), IP: %s", username, userID, clientIP)
|
||||||
|
|
||||||
user, err := repoManager.UserRepository.FindByID(userID.(uint))
|
user, err := repoManager.UserRepository.FindByID(userID.(uint))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
utils.Warn("GetProfile - 用户不存在 - 用户名: %s(ID:%d), IP: %s", username, userID, clientIP)
|
||||||
ErrorResponse(c, "用户不存在", http.StatusNotFound)
|
ErrorResponse(c, "用户不存在", http.StatusNotFound)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
response := converter.ToUserResponse(user)
|
response := converter.ToUserResponse(user)
|
||||||
|
utils.Debug("GetProfile - 成功获取个人资料 - 用户名: %s(ID:%d), IP: %s", username, userID, clientIP)
|
||||||
SuccessResponse(c, response)
|
SuccessResponse(c, response)
|
||||||
}
|
}
|
||||||
|
|||||||
1
main.go
1
main.go
@@ -41,7 +41,6 @@ func main() {
|
|||||||
if err := utils.InitLogger(nil); err != nil {
|
if err := utils.InitLogger(nil); err != nil {
|
||||||
log.Fatal("初始化日志系统失败:", err)
|
log.Fatal("初始化日志系统失败:", err)
|
||||||
}
|
}
|
||||||
defer utils.GetLogger().Close()
|
|
||||||
|
|
||||||
// 加载环境变量
|
// 加载环境变量
|
||||||
if err := godotenv.Load(); err != nil {
|
if err := godotenv.Load(); err != nil {
|
||||||
|
|||||||
@@ -27,11 +27,14 @@ type Claims struct {
|
|||||||
func AuthMiddleware() gin.HandlerFunc {
|
func AuthMiddleware() gin.HandlerFunc {
|
||||||
return func(c *gin.Context) {
|
return func(c *gin.Context) {
|
||||||
authHeader := c.GetHeader("Authorization")
|
authHeader := c.GetHeader("Authorization")
|
||||||
// utils.Info("AuthMiddleware - 收到请求: %s %s", c.Request.Method, c.Request.URL.Path)
|
clientIP := c.ClientIP()
|
||||||
// utils.Info("AuthMiddleware - Authorization头: %s", authHeader)
|
userAgent := c.Request.UserAgent()
|
||||||
|
|
||||||
|
utils.Debug("AuthMiddleware - 认证请求: %s %s, IP: %s, UserAgent: %s",
|
||||||
|
c.Request.Method, c.Request.URL.Path, clientIP, userAgent)
|
||||||
|
|
||||||
if authHeader == "" {
|
if authHeader == "" {
|
||||||
utils.Error("AuthMiddleware - 未提供认证令牌")
|
utils.Warn("AuthMiddleware - 未提供认证令牌 - IP: %s, Path: %s", clientIP, c.Request.URL.Path)
|
||||||
c.JSON(http.StatusUnauthorized, gin.H{"error": "未提供认证令牌"})
|
c.JSON(http.StatusUnauthorized, gin.H{"error": "未提供认证令牌"})
|
||||||
c.Abort()
|
c.Abort()
|
||||||
return
|
return
|
||||||
@@ -39,29 +42,31 @@ func AuthMiddleware() gin.HandlerFunc {
|
|||||||
|
|
||||||
// 检查Bearer前缀
|
// 检查Bearer前缀
|
||||||
if !strings.HasPrefix(authHeader, "Bearer ") {
|
if !strings.HasPrefix(authHeader, "Bearer ") {
|
||||||
// utils.Error("AuthMiddleware - 无效的认证格式: %s", authHeader)
|
utils.Warn("AuthMiddleware - 无效的认证格式 - IP: %s, Header: %s", clientIP, authHeader)
|
||||||
c.JSON(http.StatusUnauthorized, gin.H{"error": "无效的认证格式"})
|
c.JSON(http.StatusUnauthorized, gin.H{"error": "无效的认证格式"})
|
||||||
c.Abort()
|
c.Abort()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
tokenString := strings.TrimPrefix(authHeader, "Bearer ")
|
tokenString := strings.TrimPrefix(authHeader, "Bearer ")
|
||||||
// utils.Info("AuthMiddleware - 解析令牌: %s", tokenString[:10]+"...")
|
utils.Debug("AuthMiddleware - 解析令牌: %s...", tokenString[:utils.Min(len(tokenString), 10)])
|
||||||
|
|
||||||
claims, err := parseToken(tokenString)
|
claims, err := parseToken(tokenString)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
// utils.Error("AuthMiddleware - 令牌解析失败: %v", err)
|
utils.Warn("AuthMiddleware - 令牌解析失败 - IP: %s, Error: %v", clientIP, err)
|
||||||
c.JSON(http.StatusUnauthorized, gin.H{"error": "无效的令牌"})
|
c.JSON(http.StatusUnauthorized, gin.H{"error": "无效的令牌"})
|
||||||
c.Abort()
|
c.Abort()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// utils.Info("AuthMiddleware - 令牌验证成功,用户: %s, 角色: %s", claims.Username, claims.Role)
|
utils.Info("AuthMiddleware - 认证成功 - 用户: %s(ID:%d), 角色: %s, IP: %s",
|
||||||
|
claims.Username, claims.UserID, claims.Role, clientIP)
|
||||||
|
|
||||||
// 将用户信息存储到上下文中
|
// 将用户信息存储到上下文中
|
||||||
c.Set("user_id", claims.UserID)
|
c.Set("user_id", claims.UserID)
|
||||||
c.Set("username", claims.Username)
|
c.Set("username", claims.Username)
|
||||||
c.Set("role", claims.Role)
|
c.Set("role", claims.Role)
|
||||||
|
c.Set("client_ip", clientIP)
|
||||||
|
|
||||||
c.Next()
|
c.Next()
|
||||||
}
|
}
|
||||||
@@ -71,18 +76,23 @@ func AuthMiddleware() gin.HandlerFunc {
|
|||||||
func AdminMiddleware() gin.HandlerFunc {
|
func AdminMiddleware() gin.HandlerFunc {
|
||||||
return func(c *gin.Context) {
|
return func(c *gin.Context) {
|
||||||
role, exists := c.Get("role")
|
role, exists := c.Get("role")
|
||||||
|
username, _ := c.Get("username")
|
||||||
|
clientIP, _ := c.Get("client_ip")
|
||||||
|
|
||||||
if !exists {
|
if !exists {
|
||||||
// c.JSON(http.StatusUnauthorized, gin.H{"error": "未认证"})
|
utils.Warn("AdminMiddleware - 未认证访问管理员接口 - IP: %s, Path: %s", clientIP, c.Request.URL.Path)
|
||||||
c.Abort()
|
c.Abort()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if role != "admin" {
|
if role != "admin" {
|
||||||
// c.JSON(http.StatusForbidden, gin.H{"error": "需要管理员权限"})
|
utils.Warn("AdminMiddleware - 非管理员用户尝试访问管理员接口 - 用户: %s, 角色: %s, IP: %s, Path: %s",
|
||||||
|
username, role, clientIP, c.Request.URL.Path)
|
||||||
c.Abort()
|
c.Abort()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
utils.Debug("AdminMiddleware - 管理员访问接口 - 用户: %s, IP: %s, Path: %s", username, clientIP, c.Request.URL.Path)
|
||||||
c.Next()
|
c.Next()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -53,25 +53,47 @@ type ExpansionOutput struct {
|
|||||||
|
|
||||||
// Process 处理扩容任务项
|
// Process 处理扩容任务项
|
||||||
func (ep *ExpansionProcessor) Process(ctx context.Context, taskID uint, item *entity.TaskItem) error {
|
func (ep *ExpansionProcessor) Process(ctx context.Context, taskID uint, item *entity.TaskItem) error {
|
||||||
utils.Info("开始处理扩容任务项: %d", item.ID)
|
startTime := utils.GetCurrentTime()
|
||||||
|
utils.InfoWithFields(map[string]interface{}{
|
||||||
|
"task_item_id": item.ID,
|
||||||
|
"task_id": taskID,
|
||||||
|
}, "开始处理扩容任务项: %d", item.ID)
|
||||||
|
|
||||||
// 解析输入数据
|
// 解析输入数据
|
||||||
|
parseStart := utils.GetCurrentTime()
|
||||||
var input ExpansionInput
|
var input ExpansionInput
|
||||||
if err := json.Unmarshal([]byte(item.InputData), &input); err != nil {
|
if err := json.Unmarshal([]byte(item.InputData), &input); err != nil {
|
||||||
|
parseDuration := time.Since(parseStart)
|
||||||
|
utils.ErrorWithFields(map[string]interface{}{
|
||||||
|
"error": err.Error(),
|
||||||
|
"duration_ms": parseDuration.Milliseconds(),
|
||||||
|
}, "解析输入数据失败: %v,耗时: %v", err, parseDuration)
|
||||||
return fmt.Errorf("解析输入数据失败: %v", err)
|
return fmt.Errorf("解析输入数据失败: %v", err)
|
||||||
}
|
}
|
||||||
|
parseDuration := time.Since(parseStart)
|
||||||
|
utils.DebugWithFields(map[string]interface{}{
|
||||||
|
"duration_ms": parseDuration.Milliseconds(),
|
||||||
|
}, "解析输入数据完成,耗时: %v", parseDuration)
|
||||||
|
|
||||||
// 验证输入数据
|
// 验证输入数据
|
||||||
|
validateStart := utils.GetCurrentTime()
|
||||||
if err := ep.validateInput(&input); err != nil {
|
if err := ep.validateInput(&input); err != nil {
|
||||||
|
validateDuration := time.Since(validateStart)
|
||||||
|
utils.Error("输入数据验证失败: %v,耗时: %v", err, validateDuration)
|
||||||
return fmt.Errorf("输入数据验证失败: %v", err)
|
return fmt.Errorf("输入数据验证失败: %v", err)
|
||||||
}
|
}
|
||||||
|
validateDuration := time.Since(validateStart)
|
||||||
|
utils.Debug("输入数据验证完成,耗时: %v", validateDuration)
|
||||||
|
|
||||||
// 检查账号是否已经扩容过
|
// 检查账号是否已经扩容过
|
||||||
|
checkExpansionStart := utils.GetCurrentTime()
|
||||||
exists, err := ep.checkExpansionExists(input.PanAccountID)
|
exists, err := ep.checkExpansionExists(input.PanAccountID)
|
||||||
|
checkExpansionDuration := time.Since(checkExpansionStart)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
utils.Error("检查扩容记录失败: %v", err)
|
utils.Error("检查扩容记录失败: %v,耗时: %v", err, checkExpansionDuration)
|
||||||
return fmt.Errorf("检查扩容记录失败: %v", err)
|
return fmt.Errorf("检查扩容记录失败: %v", err)
|
||||||
}
|
}
|
||||||
|
utils.Debug("检查扩容记录完成,耗时: %v", checkExpansionDuration)
|
||||||
|
|
||||||
if exists {
|
if exists {
|
||||||
output := ExpansionOutput{
|
output := ExpansionOutput{
|
||||||
@@ -89,7 +111,9 @@ func (ep *ExpansionProcessor) Process(ctx context.Context, taskID uint, item *en
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 检查账号类型(只支持quark账号)
|
// 检查账号类型(只支持quark账号)
|
||||||
|
checkAccountTypeStart := utils.GetCurrentTime()
|
||||||
if err := ep.checkAccountType(input.PanAccountID); err != nil {
|
if err := ep.checkAccountType(input.PanAccountID); err != nil {
|
||||||
|
checkAccountTypeDuration := time.Since(checkAccountTypeStart)
|
||||||
output := ExpansionOutput{
|
output := ExpansionOutput{
|
||||||
Success: false,
|
Success: false,
|
||||||
Message: "账号类型不支持扩容",
|
Message: "账号类型不支持扩容",
|
||||||
@@ -100,12 +124,16 @@ func (ep *ExpansionProcessor) Process(ctx context.Context, taskID uint, item *en
|
|||||||
outputJSON, _ := json.Marshal(output)
|
outputJSON, _ := json.Marshal(output)
|
||||||
item.OutputData = string(outputJSON)
|
item.OutputData = string(outputJSON)
|
||||||
|
|
||||||
utils.Error("账号类型不支持扩容: %v", err)
|
utils.Error("账号类型不支持扩容: %v,耗时: %v", err, checkAccountTypeDuration)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
checkAccountTypeDuration := time.Since(checkAccountTypeStart)
|
||||||
|
utils.Debug("检查账号类型完成,耗时: %v", checkAccountTypeDuration)
|
||||||
|
|
||||||
// 执行扩容操作(传入数据源)
|
// 执行扩容操作(传入数据源)
|
||||||
|
expansionStart := utils.GetCurrentTime()
|
||||||
transferred, err := ep.performExpansion(ctx, input.PanAccountID, input.DataSource)
|
transferred, err := ep.performExpansion(ctx, input.PanAccountID, input.DataSource)
|
||||||
|
expansionDuration := time.Since(expansionStart)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
output := ExpansionOutput{
|
output := ExpansionOutput{
|
||||||
Success: false,
|
Success: false,
|
||||||
@@ -117,9 +145,10 @@ func (ep *ExpansionProcessor) Process(ctx context.Context, taskID uint, item *en
|
|||||||
outputJSON, _ := json.Marshal(output)
|
outputJSON, _ := json.Marshal(output)
|
||||||
item.OutputData = string(outputJSON)
|
item.OutputData = string(outputJSON)
|
||||||
|
|
||||||
utils.Error("扩容任务项处理失败: %d, 错误: %v", item.ID, err)
|
utils.Error("扩容任务项处理失败: %d, 错误: %v,总耗时: %v", item.ID, err, expansionDuration)
|
||||||
return fmt.Errorf("扩容失败: %v", err)
|
return fmt.Errorf("扩容失败: %v", err)
|
||||||
}
|
}
|
||||||
|
utils.Debug("扩容操作完成,耗时: %v", expansionDuration)
|
||||||
|
|
||||||
// 扩容成功
|
// 扩容成功
|
||||||
output := ExpansionOutput{
|
output := ExpansionOutput{
|
||||||
@@ -132,27 +161,44 @@ func (ep *ExpansionProcessor) Process(ctx context.Context, taskID uint, item *en
|
|||||||
outputJSON, _ := json.Marshal(output)
|
outputJSON, _ := json.Marshal(output)
|
||||||
item.OutputData = string(outputJSON)
|
item.OutputData = string(outputJSON)
|
||||||
|
|
||||||
utils.Info("扩容任务项处理完成: %d, 账号ID: %d", item.ID, input.PanAccountID)
|
elapsedTime := time.Since(startTime)
|
||||||
|
utils.InfoWithFields(map[string]interface{}{
|
||||||
|
"task_item_id": item.ID,
|
||||||
|
"account_id": input.PanAccountID,
|
||||||
|
"duration_ms": elapsedTime.Milliseconds(),
|
||||||
|
}, "扩容任务项处理完成: %d, 账号ID: %d, 总耗时: %v", item.ID, input.PanAccountID, elapsedTime)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// validateInput 验证输入数据
|
// validateInput 验证输入数据
|
||||||
func (ep *ExpansionProcessor) validateInput(input *ExpansionInput) error {
|
func (ep *ExpansionProcessor) validateInput(input *ExpansionInput) error {
|
||||||
|
startTime := utils.GetCurrentTime()
|
||||||
|
|
||||||
if input.PanAccountID == 0 {
|
if input.PanAccountID == 0 {
|
||||||
|
utils.Error("账号ID验证失败,账号ID不能为空,耗时: %v", time.Since(startTime))
|
||||||
return fmt.Errorf("账号ID不能为空")
|
return fmt.Errorf("账号ID不能为空")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
utils.Debug("输入数据验证完成,耗时: %v", time.Since(startTime))
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// checkExpansionExists 检查账号是否已经扩容过
|
// checkExpansionExists 检查账号是否已经扩容过
|
||||||
func (ep *ExpansionProcessor) checkExpansionExists(panAccountID uint) (bool, error) {
|
func (ep *ExpansionProcessor) checkExpansionExists(panAccountID uint) (bool, error) {
|
||||||
|
startTime := utils.GetCurrentTime()
|
||||||
|
|
||||||
// 查询所有expansion类型的任务
|
// 查询所有expansion类型的任务
|
||||||
|
tasksStart := utils.GetCurrentTime()
|
||||||
tasks, _, err := ep.repoMgr.TaskRepository.GetList(1, 1000, "expansion", "completed")
|
tasks, _, err := ep.repoMgr.TaskRepository.GetList(1, 1000, "expansion", "completed")
|
||||||
|
tasksDuration := time.Since(tasksStart)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
utils.Error("获取扩容任务列表失败: %v,耗时: %v", err, tasksDuration)
|
||||||
return false, fmt.Errorf("获取扩容任务列表失败: %v", err)
|
return false, fmt.Errorf("获取扩容任务列表失败: %v", err)
|
||||||
}
|
}
|
||||||
|
utils.Debug("获取扩容任务列表完成,找到 %d 个任务,耗时: %v", len(tasks), tasksDuration)
|
||||||
|
|
||||||
// 检查每个任务的配置中是否包含该账号ID
|
// 检查每个任务的配置中是否包含该账号ID
|
||||||
|
checkStart := utils.GetCurrentTime()
|
||||||
for _, task := range tasks {
|
for _, task := range tasks {
|
||||||
if task.Config != "" {
|
if task.Config != "" {
|
||||||
var taskConfig map[string]interface{}
|
var taskConfig map[string]interface{}
|
||||||
@@ -162,6 +208,8 @@ func (ep *ExpansionProcessor) checkExpansionExists(panAccountID uint) (bool, err
|
|||||||
// 找到了该账号的扩容任务,检查任务状态
|
// 找到了该账号的扩容任务,检查任务状态
|
||||||
if task.Status == "completed" {
|
if task.Status == "completed" {
|
||||||
// 如果任务已完成,说明已经扩容过
|
// 如果任务已完成,说明已经扩容过
|
||||||
|
checkDuration := time.Since(checkStart)
|
||||||
|
utils.Debug("检查扩容记录完成,账号已扩容,耗时: %v", checkDuration)
|
||||||
return true, nil
|
return true, nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -169,40 +217,63 @@ func (ep *ExpansionProcessor) checkExpansionExists(panAccountID uint) (bool, err
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
checkDuration := time.Since(checkStart)
|
||||||
|
utils.Debug("检查扩容记录完成,账号未扩容,耗时: %v", checkDuration)
|
||||||
|
|
||||||
|
totalDuration := time.Since(startTime)
|
||||||
|
utils.Debug("检查扩容记录完成,账号未扩容,总耗时: %v", totalDuration)
|
||||||
return false, nil
|
return false, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// checkAccountType 检查账号类型(只支持quark账号)
|
// checkAccountType 检查账号类型(只支持quark账号)
|
||||||
func (ep *ExpansionProcessor) checkAccountType(panAccountID uint) error {
|
func (ep *ExpansionProcessor) checkAccountType(panAccountID uint) error {
|
||||||
|
startTime := utils.GetCurrentTime()
|
||||||
|
|
||||||
// 获取账号信息
|
// 获取账号信息
|
||||||
|
accountStart := utils.GetCurrentTime()
|
||||||
cks, err := ep.repoMgr.CksRepository.FindByID(panAccountID)
|
cks, err := ep.repoMgr.CksRepository.FindByID(panAccountID)
|
||||||
|
accountDuration := time.Since(accountStart)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
utils.Error("获取账号信息失败: %v,耗时: %v", err, accountDuration)
|
||||||
return fmt.Errorf("获取账号信息失败: %v", err)
|
return fmt.Errorf("获取账号信息失败: %v", err)
|
||||||
}
|
}
|
||||||
|
utils.Debug("获取账号信息完成,耗时: %v", accountDuration)
|
||||||
|
|
||||||
// 检查是否为quark账号
|
// 检查是否为quark账号
|
||||||
|
serviceCheckStart := utils.GetCurrentTime()
|
||||||
if cks.ServiceType != "quark" {
|
if cks.ServiceType != "quark" {
|
||||||
|
serviceCheckDuration := time.Since(serviceCheckStart)
|
||||||
|
utils.Error("账号类型检查失败,当前账号类型: %s,耗时: %v", cks.ServiceType, serviceCheckDuration)
|
||||||
return fmt.Errorf("只支持quark账号扩容,当前账号类型: %s", cks.ServiceType)
|
return fmt.Errorf("只支持quark账号扩容,当前账号类型: %s", cks.ServiceType)
|
||||||
}
|
}
|
||||||
|
serviceCheckDuration := time.Since(serviceCheckStart)
|
||||||
|
utils.Debug("账号类型检查完成,为quark账号,耗时: %v", serviceCheckDuration)
|
||||||
|
|
||||||
|
totalDuration := time.Since(startTime)
|
||||||
|
utils.Debug("账号类型检查完成,总耗时: %v", totalDuration)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// performExpansion 执行扩容操作
|
// performExpansion 执行扩容操作
|
||||||
func (ep *ExpansionProcessor) performExpansion(ctx context.Context, panAccountID uint, dataSource map[string]interface{}) ([]TransferredResource, error) {
|
func (ep *ExpansionProcessor) performExpansion(ctx context.Context, panAccountID uint, dataSource map[string]interface{}) ([]TransferredResource, error) {
|
||||||
rand.Seed(time.Now().UnixNano())
|
rand.Seed(time.Now().UnixNano())
|
||||||
|
startTime := utils.GetCurrentTime()
|
||||||
utils.Info("执行扩容操作,账号ID: %d, 数据源: %v", panAccountID, dataSource)
|
utils.Info("执行扩容操作,账号ID: %d, 数据源: %v", panAccountID, dataSource)
|
||||||
|
|
||||||
transferred := []TransferredResource{}
|
transferred := []TransferredResource{}
|
||||||
|
|
||||||
// 获取账号信息
|
// 获取账号信息
|
||||||
|
accountStart := utils.GetCurrentTime()
|
||||||
account, err := ep.repoMgr.CksRepository.FindByID(panAccountID)
|
account, err := ep.repoMgr.CksRepository.FindByID(panAccountID)
|
||||||
|
accountDuration := time.Since(accountStart)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
utils.Error("获取账号信息失败: %v,耗时: %v", err, accountDuration)
|
||||||
return nil, fmt.Errorf("获取账号信息失败: %v", err)
|
return nil, fmt.Errorf("获取账号信息失败: %v", err)
|
||||||
}
|
}
|
||||||
|
utils.Debug("获取账号信息完成,耗时: %v", accountDuration)
|
||||||
|
|
||||||
// 创建网盘服务工厂
|
// 创建网盘服务工厂
|
||||||
|
serviceStart := utils.GetCurrentTime()
|
||||||
factory := pan.NewPanFactory()
|
factory := pan.NewPanFactory()
|
||||||
service, err := factory.CreatePanServiceByType(pan.Quark, &pan.PanConfig{
|
service, err := factory.CreatePanServiceByType(pan.Quark, &pan.PanConfig{
|
||||||
URL: "",
|
URL: "",
|
||||||
@@ -210,10 +281,13 @@ func (ep *ExpansionProcessor) performExpansion(ctx context.Context, panAccountID
|
|||||||
IsType: 0,
|
IsType: 0,
|
||||||
Cookie: account.Ck,
|
Cookie: account.Ck,
|
||||||
})
|
})
|
||||||
|
serviceDuration := time.Since(serviceStart)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
utils.Error("创建网盘服务失败: %v,耗时: %v", err, serviceDuration)
|
||||||
return nil, fmt.Errorf("创建网盘服务失败: %v", err)
|
return nil, fmt.Errorf("创建网盘服务失败: %v", err)
|
||||||
}
|
}
|
||||||
service.SetCKSRepository(ep.repoMgr.CksRepository, *account)
|
service.SetCKSRepository(ep.repoMgr.CksRepository, *account)
|
||||||
|
utils.Debug("创建网盘服务完成,耗时: %v", serviceDuration)
|
||||||
|
|
||||||
// 定义扩容分类列表(按优先级排序)
|
// 定义扩容分类列表(按优先级排序)
|
||||||
categories := []string{
|
categories := []string{
|
||||||
@@ -246,11 +320,14 @@ func (ep *ExpansionProcessor) performExpansion(ctx context.Context, panAccountID
|
|||||||
utils.Info("开始处理分类: %s", category)
|
utils.Info("开始处理分类: %s", category)
|
||||||
|
|
||||||
// 获取该分类的资源
|
// 获取该分类的资源
|
||||||
|
resourcesStart := utils.GetCurrentTime()
|
||||||
resources, err := ep.getHotResources(category)
|
resources, err := ep.getHotResources(category)
|
||||||
|
resourcesDuration := time.Since(resourcesStart)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
utils.Error("获取分类 %s 的资源失败: %v", category, err)
|
utils.Error("获取分类 %s 的资源失败: %v,耗时: %v", category, err, resourcesDuration)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
utils.Debug("获取分类 %s 的资源完成,耗时: %v", category, resourcesDuration)
|
||||||
|
|
||||||
if len(resources) == 0 {
|
if len(resources) == 0 {
|
||||||
utils.Info("分类 %s 没有可用资源,跳过", category)
|
utils.Info("分类 %s 没有可用资源,跳过", category)
|
||||||
@@ -269,11 +346,14 @@ func (ep *ExpansionProcessor) performExpansion(ctx context.Context, panAccountID
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 检查是否还有存储空间
|
// 检查是否还有存储空间
|
||||||
|
storageCheckStart := utils.GetCurrentTime()
|
||||||
hasSpace, err := ep.checkStorageSpace(service, &account.Ck)
|
hasSpace, err := ep.checkStorageSpace(service, &account.Ck)
|
||||||
|
storageCheckDuration := time.Since(storageCheckStart)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
utils.Error("检查存储空间失败: %v", err)
|
utils.Error("检查存储空间失败: %v,耗时: %v", err, storageCheckDuration)
|
||||||
return transferred, fmt.Errorf("检查存储空间失败: %v", err)
|
return transferred, fmt.Errorf("检查存储空间失败: %v", err)
|
||||||
}
|
}
|
||||||
|
utils.Debug("检查存储空间完成,耗时: %v", storageCheckDuration)
|
||||||
|
|
||||||
if !hasSpace {
|
if !hasSpace {
|
||||||
utils.Info("存储空间不足,停止扩容,但保存已转存的资源")
|
utils.Info("存储空间不足,停止扩容,但保存已转存的资源")
|
||||||
@@ -282,24 +362,30 @@ func (ep *ExpansionProcessor) performExpansion(ctx context.Context, panAccountID
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 获取资源 , dataSourceType, thirdPartyURL
|
// 获取资源 , dataSourceType, thirdPartyURL
|
||||||
|
resourceGetStart := utils.GetCurrentTime()
|
||||||
resource, err := ep.getResourcesByHot(resource, dataSourceType, thirdPartyURL, *account, service)
|
resource, err := ep.getResourcesByHot(resource, dataSourceType, thirdPartyURL, *account, service)
|
||||||
|
resourceGetDuration := time.Since(resourceGetStart)
|
||||||
if resource == nil || err != nil {
|
if resource == nil || err != nil {
|
||||||
if resource != nil {
|
if resource != nil {
|
||||||
utils.Error("获取资源失败: %s, 错误: %v", resource.Title, err)
|
utils.Error("获取资源失败: %s, 错误: %v,耗时: %v", resource.Title, err, resourceGetDuration)
|
||||||
} else {
|
} else {
|
||||||
utils.Error("获取资源失败, 错误: %v", err)
|
utils.Error("获取资源失败, 错误: %v,耗时: %v", err, resourceGetDuration)
|
||||||
}
|
}
|
||||||
totalFailed++
|
totalFailed++
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
utils.Debug("获取资源完成,耗时: %v", resourceGetDuration)
|
||||||
|
|
||||||
// 执行转存
|
// 执行转存
|
||||||
|
transferStart := utils.GetCurrentTime()
|
||||||
saveURL, err := ep.transferResource(ctx, service, resource, *account)
|
saveURL, err := ep.transferResource(ctx, service, resource, *account)
|
||||||
|
transferDuration := time.Since(transferStart)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
utils.Error("转存资源失败: %s, 错误: %v", resource.Title, err)
|
utils.Error("转存资源失败: %s, 错误: %v,耗时: %v", resource.Title, err, transferDuration)
|
||||||
totalFailed++
|
totalFailed++
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
utils.Debug("转存资源完成,耗时: %v", transferDuration)
|
||||||
|
|
||||||
// 随机休眠1-3秒,避免请求过于频繁
|
// 随机休眠1-3秒,避免请求过于频繁
|
||||||
sleepDuration := time.Duration(rand.Intn(3)+1) * time.Second
|
sleepDuration := time.Duration(rand.Intn(3)+1) * time.Second
|
||||||
@@ -324,7 +410,8 @@ func (ep *ExpansionProcessor) performExpansion(ctx context.Context, panAccountID
|
|||||||
utils.Info("分类 %s 处理完成,转存 %d 个资源", category, transferredCount)
|
utils.Info("分类 %s 处理完成,转存 %d 个资源", category, transferredCount)
|
||||||
}
|
}
|
||||||
|
|
||||||
utils.Info("扩容完成,总共转存: %d 个资源,失败: %d 个资源", totalTransferred, totalFailed)
|
elapsedTime := time.Since(startTime)
|
||||||
|
utils.Info("扩容完成,总共转存: %d 个资源,失败: %d 个资源,总耗时: %v", totalTransferred, totalFailed, elapsedTime)
|
||||||
return transferred, nil
|
return transferred, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -335,27 +422,45 @@ func (ep *ExpansionProcessor) getResourcesByHot(
|
|||||||
entity entity.Cks,
|
entity entity.Cks,
|
||||||
service pan.PanService,
|
service pan.PanService,
|
||||||
) (*entity.Resource, error) {
|
) (*entity.Resource, error) {
|
||||||
|
startTime := utils.GetCurrentTime()
|
||||||
|
|
||||||
if dataSourceType == "third-party" && thirdPartyURL != "" {
|
if dataSourceType == "third-party" && thirdPartyURL != "" {
|
||||||
// 从第三方API获取资源
|
// 从第三方API获取资源
|
||||||
return ep.getResourcesFromThirdPartyAPI(resource, thirdPartyURL)
|
thirdPartyStart := utils.GetCurrentTime()
|
||||||
|
result, err := ep.getResourcesFromThirdPartyAPI(resource, thirdPartyURL)
|
||||||
|
thirdPartyDuration := time.Since(thirdPartyStart)
|
||||||
|
utils.Debug("从第三方API获取资源完成,耗时: %v", thirdPartyDuration)
|
||||||
|
return result, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// 从内部数据库获取资源
|
// 从内部数据库获取资源
|
||||||
return ep.getResourcesFromInternalDB(resource, entity, service)
|
internalStart := utils.GetCurrentTime()
|
||||||
|
result, err := ep.getResourcesFromInternalDB(resource, entity, service)
|
||||||
|
internalDuration := time.Since(internalStart)
|
||||||
|
utils.Debug("从内部数据库获取资源完成,耗时: %v", internalDuration)
|
||||||
|
|
||||||
|
totalDuration := time.Since(startTime)
|
||||||
|
utils.Debug("获取资源完成: %s,总耗时: %v", resource.Title, totalDuration)
|
||||||
|
return result, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// getResourcesFromInternalDB 根据 HotDrama 的title 获取数据库中资源,并且资源的类型和 account 的资源类型一致
|
// getResourcesFromInternalDB 根据 HotDrama 的title 获取数据库中资源,并且资源的类型和 account 的资源类型一致
|
||||||
func (ep *ExpansionProcessor) getResourcesFromInternalDB(HotDrama *entity.HotDrama, account entity.Cks, service pan.PanService) (*entity.Resource, error) {
|
func (ep *ExpansionProcessor) getResourcesFromInternalDB(HotDrama *entity.HotDrama, account entity.Cks, service pan.PanService) (*entity.Resource, error) {
|
||||||
|
startTime := utils.GetCurrentTime()
|
||||||
|
|
||||||
// 修改配置 isType = 1 只检测,不转存
|
// 修改配置 isType = 1 只检测,不转存
|
||||||
|
configStart := utils.GetCurrentTime()
|
||||||
service.UpdateConfig(&pan.PanConfig{
|
service.UpdateConfig(&pan.PanConfig{
|
||||||
URL: "",
|
URL: "",
|
||||||
ExpiredType: 0,
|
ExpiredType: 0,
|
||||||
IsType: 1,
|
IsType: 1,
|
||||||
Cookie: account.Ck,
|
Cookie: account.Ck,
|
||||||
})
|
})
|
||||||
|
utils.Debug("更新服务配置完成,耗时: %v", time.Since(configStart))
|
||||||
panID := account.PanID
|
panID := account.PanID
|
||||||
|
|
||||||
// 1. 搜索标题
|
// 1. 搜索标题
|
||||||
|
searchStart := utils.GetCurrentTime()
|
||||||
params := map[string]interface{}{
|
params := map[string]interface{}{
|
||||||
"search": HotDrama.Title,
|
"search": HotDrama.Title,
|
||||||
"pan_id": panID,
|
"pan_id": panID,
|
||||||
@@ -364,11 +469,15 @@ func (ep *ExpansionProcessor) getResourcesFromInternalDB(HotDrama *entity.HotDra
|
|||||||
"page_size": 10,
|
"page_size": 10,
|
||||||
}
|
}
|
||||||
resources, _, err := ep.repoMgr.ResourceRepository.SearchWithFilters(params)
|
resources, _, err := ep.repoMgr.ResourceRepository.SearchWithFilters(params)
|
||||||
|
searchDuration := time.Since(searchStart)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
utils.Error("搜索资源失败: %v,耗时: %v", err, searchDuration)
|
||||||
return nil, fmt.Errorf("搜索资源失败: %v", err)
|
return nil, fmt.Errorf("搜索资源失败: %v", err)
|
||||||
}
|
}
|
||||||
|
utils.Debug("搜索资源完成,找到 %d 个资源,耗时: %v", len(resources), searchDuration)
|
||||||
|
|
||||||
// 检查结果是否有效,通过服务验证
|
// 检查结果是否有效,通过服务验证
|
||||||
|
validateStart := utils.GetCurrentTime()
|
||||||
for _, res := range resources {
|
for _, res := range resources {
|
||||||
if res.IsValid && res.URL != "" {
|
if res.IsValid && res.URL != "" {
|
||||||
// 使用服务验证资源是否可转存
|
// 使用服务验证资源是否可转存
|
||||||
@@ -376,38 +485,59 @@ func (ep *ExpansionProcessor) getResourcesFromInternalDB(HotDrama *entity.HotDra
|
|||||||
if shareID != "" {
|
if shareID != "" {
|
||||||
result, err := service.Transfer(shareID)
|
result, err := service.Transfer(shareID)
|
||||||
if err == nil && result != nil && result.Success {
|
if err == nil && result != nil && result.Success {
|
||||||
|
validateDuration := time.Since(validateStart)
|
||||||
|
utils.Debug("验证资源成功: %s,耗时: %v", res.Title, validateDuration)
|
||||||
return &res, nil
|
return &res, nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
validateDuration := time.Since(validateStart)
|
||||||
|
utils.Debug("验证资源完成,未找到有效资源,耗时: %v", validateDuration)
|
||||||
|
|
||||||
|
totalDuration := time.Since(startTime)
|
||||||
|
utils.Debug("从内部数据库获取资源完成: %s,总耗时: %v", HotDrama.Title, totalDuration)
|
||||||
// 3. 没有有效资源,返回错误信息
|
// 3. 没有有效资源,返回错误信息
|
||||||
return nil, fmt.Errorf("未找到有效的资源")
|
return nil, fmt.Errorf("未找到有效的资源")
|
||||||
}
|
}
|
||||||
|
|
||||||
// getResourcesFromInternalDB 从内部数据库获取资源
|
// getResourcesFromInternalDB 从内部数据库获取资源
|
||||||
func (ep *ExpansionProcessor) getHotResources(category string) ([]*entity.HotDrama, error) {
|
func (ep *ExpansionProcessor) getHotResources(category string) ([]*entity.HotDrama, error) {
|
||||||
|
startTime := utils.GetCurrentTime()
|
||||||
|
|
||||||
// 获取该分类下sub_type为"排行"的资源
|
// 获取该分类下sub_type为"排行"的资源
|
||||||
|
rankedStart := utils.GetCurrentTime()
|
||||||
dramas, _, err := ep.repoMgr.HotDramaRepository.FindByCategoryAndSubType(category, "排行", 1, 20)
|
dramas, _, err := ep.repoMgr.HotDramaRepository.FindByCategoryAndSubType(category, "排行", 1, 20)
|
||||||
|
rankedDuration := time.Since(rankedStart)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
utils.Error("获取分类 %s 的排行资源失败: %v,耗时: %v", category, err, rankedDuration)
|
||||||
return nil, fmt.Errorf("获取分类 %s 的资源失败: %v", category, err)
|
return nil, fmt.Errorf("获取分类 %s 的资源失败: %v", category, err)
|
||||||
}
|
}
|
||||||
|
utils.Debug("获取分类 %s 的排行资源完成,找到 %d 个资源,耗时: %v", category, len(dramas), rankedDuration)
|
||||||
|
|
||||||
// 如果没有找到"排行"类型的资源,尝试获取该分类下的所有资源
|
// 如果没有找到"排行"类型的资源,尝试获取该分类下的所有资源
|
||||||
if len(dramas) == 0 {
|
if len(dramas) == 0 {
|
||||||
|
allStart := utils.GetCurrentTime()
|
||||||
dramas, _, err = ep.repoMgr.HotDramaRepository.FindByCategory(category, 1, 20)
|
dramas, _, err = ep.repoMgr.HotDramaRepository.FindByCategory(category, 1, 20)
|
||||||
|
allDuration := time.Since(allStart)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
utils.Error("获取分类 %s 的所有资源失败: %v,耗时: %v", category, err, allDuration)
|
||||||
return nil, fmt.Errorf("获取分类 %s 的资源失败: %v", category, err)
|
return nil, fmt.Errorf("获取分类 %s 的资源失败: %v", category, err)
|
||||||
}
|
}
|
||||||
|
utils.Debug("获取分类 %s 的所有资源完成,找到 %d 个资源,耗时: %v", category, len(dramas), allDuration)
|
||||||
}
|
}
|
||||||
|
|
||||||
// 转换为指针数组
|
// 转换为指针数组
|
||||||
|
convertStart := utils.GetCurrentTime()
|
||||||
result := make([]*entity.HotDrama, len(dramas))
|
result := make([]*entity.HotDrama, len(dramas))
|
||||||
for i := range dramas {
|
for i := range dramas {
|
||||||
result[i] = &dramas[i]
|
result[i] = &dramas[i]
|
||||||
}
|
}
|
||||||
|
convertDuration := time.Since(convertStart)
|
||||||
|
utils.Debug("转换资源数组完成,耗时: %v", convertDuration)
|
||||||
|
|
||||||
|
totalDuration := time.Since(startTime)
|
||||||
|
utils.Debug("获取热门资源完成: 分类 %s,总数 %d,总耗时: %v", category, len(result), totalDuration)
|
||||||
return result, nil
|
return result, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -423,50 +553,69 @@ func (ep *ExpansionProcessor) getResourcesFromThirdPartyAPI(resource *entity.Hot
|
|||||||
|
|
||||||
// checkStorageSpace 检查存储空间是否足够
|
// checkStorageSpace 检查存储空间是否足够
|
||||||
func (ep *ExpansionProcessor) checkStorageSpace(service pan.PanService, ck *string) (bool, error) {
|
func (ep *ExpansionProcessor) checkStorageSpace(service pan.PanService, ck *string) (bool, error) {
|
||||||
|
startTime := utils.GetCurrentTime()
|
||||||
|
|
||||||
|
userInfoStart := utils.GetCurrentTime()
|
||||||
userInfo, err := service.GetUserInfo(ck)
|
userInfo, err := service.GetUserInfo(ck)
|
||||||
|
userInfoDuration := time.Since(userInfoStart)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
utils.Error("获取用户信息失败: %v", err)
|
utils.Error("获取用户信息失败: %v,耗时: %v", err, userInfoDuration)
|
||||||
// 如果无法获取用户信息,假设还有空间继续
|
// 如果无法获取用户信息,假设还有空间继续
|
||||||
return true, nil
|
return true, nil
|
||||||
}
|
}
|
||||||
|
utils.Debug("获取用户信息完成,耗时: %v", userInfoDuration)
|
||||||
|
|
||||||
// 检查是否还有足够的空间(保留至少10GB空间)
|
// 检查是否还有足够的空间(保留至少10GB空间)
|
||||||
const reservedSpaceGB = 100
|
const reservedSpaceGB = 100
|
||||||
reservedSpaceBytes := int64(reservedSpaceGB * 1024 * 1024 * 1024)
|
reservedSpaceBytes := int64(reservedSpaceGB * 1024 * 1024 * 1024)
|
||||||
|
|
||||||
if userInfo.TotalSpace-userInfo.UsedSpace <= reservedSpaceBytes {
|
if userInfo.TotalSpace-userInfo.UsedSpace <= reservedSpaceBytes {
|
||||||
utils.Info("存储空间不足,已使用: %d bytes,总容量: %d bytes",
|
utils.Info("存储空间不足,已使用: %d bytes,总容量: %d bytes,检查耗时: %v",
|
||||||
userInfo.UsedSpace, userInfo.TotalSpace)
|
userInfo.UsedSpace, userInfo.TotalSpace, time.Since(startTime))
|
||||||
return false, nil
|
return false, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
totalDuration := time.Since(startTime)
|
||||||
|
utils.Debug("存储空间检查完成,有足够空间,耗时: %v", totalDuration)
|
||||||
return true, nil
|
return true, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// transferResource 执行单个资源的转存
|
// transferResource 执行单个资源的转存
|
||||||
func (ep *ExpansionProcessor) transferResource(ctx context.Context, service pan.PanService, res *entity.Resource, account entity.Cks) (string, error) {
|
func (ep *ExpansionProcessor) transferResource(ctx context.Context, service pan.PanService, res *entity.Resource, account entity.Cks) (string, error) {
|
||||||
|
startTime := utils.GetCurrentTime()
|
||||||
|
|
||||||
// 修改配置 isType = 0 转存
|
// 修改配置 isType = 0 转存
|
||||||
|
configStart := utils.GetCurrentTime()
|
||||||
service.UpdateConfig(&pan.PanConfig{
|
service.UpdateConfig(&pan.PanConfig{
|
||||||
URL: "",
|
URL: "",
|
||||||
ExpiredType: 0,
|
ExpiredType: 0,
|
||||||
IsType: 0,
|
IsType: 0,
|
||||||
Cookie: account.Ck,
|
Cookie: account.Ck,
|
||||||
})
|
})
|
||||||
|
utils.Debug("更新服务配置完成,耗时: %v", time.Since(configStart))
|
||||||
|
|
||||||
// 如果没有URL,跳过转存
|
// 如果没有URL,跳过转存
|
||||||
if res.URL == "" {
|
if res.URL == "" {
|
||||||
|
utils.Error("资源 %s 没有有效的URL", res.URL)
|
||||||
return "", fmt.Errorf("资源 %s 没有有效的URL", res.URL)
|
return "", fmt.Errorf("资源 %s 没有有效的URL", res.URL)
|
||||||
}
|
}
|
||||||
|
|
||||||
// 提取分享ID
|
// 提取分享ID
|
||||||
|
extractStart := utils.GetCurrentTime()
|
||||||
shareID, _ := pan.ExtractShareId(res.URL)
|
shareID, _ := pan.ExtractShareId(res.URL)
|
||||||
|
extractDuration := time.Since(extractStart)
|
||||||
if shareID == "" {
|
if shareID == "" {
|
||||||
|
utils.Error("无法从URL %s 提取分享ID,耗时: %v", res.URL, extractDuration)
|
||||||
return "", fmt.Errorf("无法从URL %s 提取分享ID", res.URL)
|
return "", fmt.Errorf("无法从URL %s 提取分享ID", res.URL)
|
||||||
}
|
}
|
||||||
|
utils.Debug("提取分享ID完成: %s,耗时: %v", shareID, extractDuration)
|
||||||
|
|
||||||
// 执行转存
|
// 执行转存
|
||||||
|
transferStart := utils.GetCurrentTime()
|
||||||
result, err := service.Transfer(shareID)
|
result, err := service.Transfer(shareID)
|
||||||
|
transferDuration := time.Since(transferStart)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
utils.Error("转存失败: %v,耗时: %v", err, transferDuration)
|
||||||
return "", fmt.Errorf("转存失败: %v", err)
|
return "", fmt.Errorf("转存失败: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -475,10 +624,12 @@ func (ep *ExpansionProcessor) transferResource(ctx context.Context, service pan.
|
|||||||
if result != nil {
|
if result != nil {
|
||||||
errorMsg = result.Message
|
errorMsg = result.Message
|
||||||
}
|
}
|
||||||
|
utils.Error("转存结果失败: %s,耗时: %v", errorMsg, time.Since(transferStart))
|
||||||
return "", fmt.Errorf("转存失败: %s", errorMsg)
|
return "", fmt.Errorf("转存失败: %s", errorMsg)
|
||||||
}
|
}
|
||||||
|
|
||||||
// 提取转存链接
|
// 提取转存链接
|
||||||
|
extractURLStart := utils.GetCurrentTime()
|
||||||
var saveURL string
|
var saveURL string
|
||||||
if result.Data != nil {
|
if result.Data != nil {
|
||||||
if data, ok := result.Data.(map[string]interface{}); ok {
|
if data, ok := result.Data.(map[string]interface{}); ok {
|
||||||
@@ -490,11 +641,14 @@ func (ep *ExpansionProcessor) transferResource(ctx context.Context, service pan.
|
|||||||
if saveURL == "" {
|
if saveURL == "" {
|
||||||
saveURL = result.ShareURL
|
saveURL = result.ShareURL
|
||||||
}
|
}
|
||||||
|
|
||||||
if saveURL == "" {
|
if saveURL == "" {
|
||||||
|
extractURLDuration := time.Since(extractURLStart)
|
||||||
|
utils.Error("转存成功但未获取到分享链接,耗时: %v", extractURLDuration)
|
||||||
return "", fmt.Errorf("转存成功但未获取到分享链接")
|
return "", fmt.Errorf("转存成功但未获取到分享链接")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
totalDuration := time.Since(startTime)
|
||||||
|
utils.Debug("转存资源完成: %s -> %s,总耗时: %v", res.Title, saveURL, totalDuration)
|
||||||
return saveURL, nil
|
return saveURL, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ import (
|
|||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
"sync"
|
"sync"
|
||||||
|
"time"
|
||||||
|
|
||||||
"github.com/ctwj/urldb/db/entity"
|
"github.com/ctwj/urldb/db/entity"
|
||||||
"github.com/ctwj/urldb/db/repo"
|
"github.com/ctwj/urldb/db/repo"
|
||||||
@@ -90,7 +91,9 @@ func (tm *TaskManager) StartTask(taskID uint) error {
|
|||||||
// 启动后台任务
|
// 启动后台任务
|
||||||
go tm.processTask(ctx, task, processor)
|
go tm.processTask(ctx, task, processor)
|
||||||
|
|
||||||
utils.Info("StartTask: 任务 %d 启动成功", taskID)
|
utils.InfoWithFields(map[string]interface{}{
|
||||||
|
"task_id": taskID,
|
||||||
|
}, "StartTask: 任务 %d 启动成功", taskID)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -185,14 +188,19 @@ func (tm *TaskManager) StopTask(taskID uint) error {
|
|||||||
|
|
||||||
// processTask 处理任务
|
// processTask 处理任务
|
||||||
func (tm *TaskManager) processTask(ctx context.Context, task *entity.Task, processor TaskProcessor) {
|
func (tm *TaskManager) processTask(ctx context.Context, task *entity.Task, processor TaskProcessor) {
|
||||||
|
startTime := utils.GetCurrentTime()
|
||||||
defer func() {
|
defer func() {
|
||||||
tm.mu.Lock()
|
tm.mu.Lock()
|
||||||
delete(tm.running, task.ID)
|
delete(tm.running, task.ID)
|
||||||
tm.mu.Unlock()
|
tm.mu.Unlock()
|
||||||
utils.Debug("processTask: 任务 %d 处理完成,清理资源", task.ID)
|
elapsedTime := time.Since(startTime)
|
||||||
|
utils.Info("processTask: 任务 %d 处理完成,耗时: %v,清理资源", task.ID, elapsedTime)
|
||||||
}()
|
}()
|
||||||
|
|
||||||
utils.Debug("processTask: 开始处理任务: %d, 类型: %s", task.ID, task.Type)
|
utils.InfoWithFields(map[string]interface{}{
|
||||||
|
"task_id": task.ID,
|
||||||
|
"task_type": task.Type,
|
||||||
|
}, "processTask: 开始处理任务: %d, 类型: %s", task.ID, task.Type)
|
||||||
|
|
||||||
// 更新任务状态为运行中
|
// 更新任务状态为运行中
|
||||||
err := tm.repoMgr.TaskRepository.UpdateStatus(task.ID, "running")
|
err := tm.repoMgr.TaskRepository.UpdateStatus(task.ID, "running")
|
||||||
@@ -208,7 +216,9 @@ func (tm *TaskManager) processTask(ctx context.Context, task *entity.Task, proce
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 获取任务项统计信息,用于计算正确的进度
|
// 获取任务项统计信息,用于计算正确的进度
|
||||||
|
statsStart := utils.GetCurrentTime()
|
||||||
stats, err := tm.repoMgr.TaskItemRepository.GetStatsByTaskID(task.ID)
|
stats, err := tm.repoMgr.TaskItemRepository.GetStatsByTaskID(task.ID)
|
||||||
|
statsDuration := time.Since(statsStart)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
utils.Error("获取任务项统计失败: %v", err)
|
utils.Error("获取任务项统计失败: %v", err)
|
||||||
stats = map[string]int{
|
stats = map[string]int{
|
||||||
@@ -218,14 +228,20 @@ func (tm *TaskManager) processTask(ctx context.Context, task *entity.Task, proce
|
|||||||
"completed": 0,
|
"completed": 0,
|
||||||
"failed": 0,
|
"failed": 0,
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
utils.Debug("获取任务项统计完成,耗时: %v", statsDuration)
|
||||||
}
|
}
|
||||||
|
|
||||||
// 获取待处理的任务项
|
// 获取待处理的任务项
|
||||||
|
itemsStart := utils.GetCurrentTime()
|
||||||
items, err := tm.repoMgr.TaskItemRepository.GetByTaskIDAndStatus(task.ID, "pending")
|
items, err := tm.repoMgr.TaskItemRepository.GetByTaskIDAndStatus(task.ID, "pending")
|
||||||
|
itemsDuration := time.Since(itemsStart)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
utils.Error("获取任务项失败: %v", err)
|
utils.Error("获取任务项失败: %v", err)
|
||||||
tm.markTaskFailed(task.ID, fmt.Sprintf("获取任务项失败: %v", err))
|
tm.markTaskFailed(task.ID, fmt.Sprintf("获取任务项失败: %v", err))
|
||||||
return
|
return
|
||||||
|
} else {
|
||||||
|
utils.Debug("获取任务项完成,数量: %d,耗时: %v", len(items), itemsDuration)
|
||||||
}
|
}
|
||||||
|
|
||||||
// 计算总任务项数和已完成的项数
|
// 计算总任务项数和已完成的项数
|
||||||
@@ -236,10 +252,14 @@ func (tm *TaskManager) processTask(ctx context.Context, task *entity.Task, proce
|
|||||||
|
|
||||||
// 如果当前批次有处理中的任务项,重置它们为pending状态(服务器重启恢复)
|
// 如果当前批次有处理中的任务项,重置它们为pending状态(服务器重启恢复)
|
||||||
if processingItems > 0 {
|
if processingItems > 0 {
|
||||||
utils.Debug("任务 %d 发现 %d 个处理中的任务项,重置为pending状态", task.ID, processingItems)
|
utils.Info("任务 %d 发现 %d 个处理中的任务项,重置为pending状态", task.ID, processingItems)
|
||||||
|
resetStart := utils.GetCurrentTime()
|
||||||
err = tm.repoMgr.TaskItemRepository.ResetProcessingItems(task.ID)
|
err = tm.repoMgr.TaskItemRepository.ResetProcessingItems(task.ID)
|
||||||
|
resetDuration := time.Since(resetStart)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
utils.Error("重置处理中任务项失败: %v", err)
|
utils.Error("重置处理中任务项失败: %v", err)
|
||||||
|
} else {
|
||||||
|
utils.Debug("重置处理中任务项完成,耗时: %v", resetDuration)
|
||||||
}
|
}
|
||||||
// 重新获取待处理的任务项
|
// 重新获取待处理的任务项
|
||||||
items, err = tm.repoMgr.TaskItemRepository.GetByTaskIDAndStatus(task.ID, "pending")
|
items, err = tm.repoMgr.TaskItemRepository.GetByTaskIDAndStatus(task.ID, "pending")
|
||||||
@@ -258,21 +278,35 @@ func (tm *TaskManager) processTask(ctx context.Context, task *entity.Task, proce
|
|||||||
utils.Debug("任务 %d 统计信息: 总计=%d, 已完成=%d, 已失败=%d, 待处理=%d",
|
utils.Debug("任务 %d 统计信息: 总计=%d, 已完成=%d, 已失败=%d, 待处理=%d",
|
||||||
task.ID, totalItems, completedItems, failedItems, currentBatchItems)
|
task.ID, totalItems, completedItems, failedItems, currentBatchItems)
|
||||||
|
|
||||||
for _, item := range items {
|
// 记录处理开始时间
|
||||||
|
batchStartTime := utils.GetCurrentTime()
|
||||||
|
|
||||||
|
for i, item := range items {
|
||||||
select {
|
select {
|
||||||
case <-ctx.Done():
|
case <-ctx.Done():
|
||||||
utils.Debug("任务 %d 被取消", task.ID)
|
utils.Debug("任务 %d 被取消", task.ID)
|
||||||
return
|
return
|
||||||
default:
|
default:
|
||||||
|
// 记录单个任务项处理开始时间
|
||||||
|
itemStartTime := utils.GetCurrentTime()
|
||||||
|
|
||||||
// 处理单个任务项
|
// 处理单个任务项
|
||||||
err := tm.processTaskItem(ctx, task.ID, item, processor)
|
err := tm.processTaskItem(ctx, task.ID, item, processor)
|
||||||
processedItems++
|
processedItems++
|
||||||
|
|
||||||
|
// 记录单个任务项处理耗时
|
||||||
|
itemDuration := time.Since(itemStartTime)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
failedItems++
|
failedItems++
|
||||||
utils.Error("处理任务项 %d 失败: %v", item.ID, err)
|
utils.ErrorWithFields(map[string]interface{}{
|
||||||
|
"task_item_id": item.ID,
|
||||||
|
"error": err.Error(),
|
||||||
|
"duration_ms": itemDuration.Milliseconds(),
|
||||||
|
}, "处理任务项 %d 失败: %v,耗时: %v", item.ID, err, itemDuration)
|
||||||
} else {
|
} else {
|
||||||
successItems++
|
successItems++
|
||||||
|
utils.Info("处理任务项 %d 成功,耗时: %v", item.ID, itemDuration)
|
||||||
}
|
}
|
||||||
|
|
||||||
// 更新任务进度(基于总任务项数)
|
// 更新任务进度(基于总任务项数)
|
||||||
@@ -280,9 +314,21 @@ func (tm *TaskManager) processTask(ctx context.Context, task *entity.Task, proce
|
|||||||
progress := float64(processedItems) / float64(totalItems) * 100
|
progress := float64(processedItems) / float64(totalItems) * 100
|
||||||
tm.updateTaskProgress(task.ID, progress, processedItems, successItems, failedItems)
|
tm.updateTaskProgress(task.ID, progress, processedItems, successItems, failedItems)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 每处理10个任务项记录一次批处理进度
|
||||||
|
if (i+1)%10 == 0 || i == len(items)-1 {
|
||||||
|
batchDuration := time.Since(batchStartTime)
|
||||||
|
utils.Info("任务 %d 批处理进度: 已处理 %d/%d 项,成功 %d 项,失败 %d 项,当前批处理耗时: %v",
|
||||||
|
task.ID, processedItems, totalItems, successItems, failedItems, batchDuration)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 记录整个批处理耗时
|
||||||
|
batchDuration := time.Since(batchStartTime)
|
||||||
|
utils.Info("任务 %d 批处理完成: 总计 %d 项,成功 %d 项,失败 %d 项,总耗时: %v",
|
||||||
|
task.ID, len(items), successItems, failedItems, batchDuration)
|
||||||
|
|
||||||
// 任务完成
|
// 任务完成
|
||||||
status := "completed"
|
status := "completed"
|
||||||
message := fmt.Sprintf("任务完成,共处理 %d 项,成功 %d 项,失败 %d 项", processedItems, successItems, failedItems)
|
message := fmt.Sprintf("任务完成,共处理 %d 项,成功 %d 项,失败 %d 项", processedItems, successItems, failedItems)
|
||||||
@@ -308,25 +354,41 @@ func (tm *TaskManager) processTask(ctx context.Context, task *entity.Task, proce
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
utils.Info("任务 %d 处理完成: %s", task.ID, message)
|
utils.InfoWithFields(map[string]interface{}{
|
||||||
|
"task_id": task.ID,
|
||||||
|
"message": message,
|
||||||
|
}, "任务 %d 处理完成: %s", task.ID, message)
|
||||||
}
|
}
|
||||||
|
|
||||||
// processTaskItem 处理单个任务项
|
// processTaskItem 处理单个任务项
|
||||||
func (tm *TaskManager) processTaskItem(ctx context.Context, taskID uint, item *entity.TaskItem, processor TaskProcessor) error {
|
func (tm *TaskManager) processTaskItem(ctx context.Context, taskID uint, item *entity.TaskItem, processor TaskProcessor) error {
|
||||||
|
itemStartTime := utils.GetCurrentTime()
|
||||||
|
utils.Debug("开始处理任务项: %d (任务ID: %d)", item.ID, taskID)
|
||||||
|
|
||||||
// 更新任务项状态为处理中
|
// 更新任务项状态为处理中
|
||||||
|
updateStart := utils.GetCurrentTime()
|
||||||
err := tm.repoMgr.TaskItemRepository.UpdateStatus(item.ID, "processing")
|
err := tm.repoMgr.TaskItemRepository.UpdateStatus(item.ID, "processing")
|
||||||
|
updateDuration := time.Since(updateStart)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
utils.Error("更新任务项状态失败: %v,耗时: %v", err, updateDuration)
|
||||||
return fmt.Errorf("更新任务项状态失败: %v", err)
|
return fmt.Errorf("更新任务项状态失败: %v", err)
|
||||||
|
} else {
|
||||||
|
utils.Debug("更新任务项状态为处理中完成,耗时: %v", updateDuration)
|
||||||
}
|
}
|
||||||
|
|
||||||
// 处理任务项
|
// 处理任务项
|
||||||
|
processStart := utils.GetCurrentTime()
|
||||||
err = processor.Process(ctx, taskID, item)
|
err = processor.Process(ctx, taskID, item)
|
||||||
|
processDuration := time.Since(processStart)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
// 处理失败
|
// 处理失败
|
||||||
|
utils.Error("处理任务项 %d 失败: %v,处理耗时: %v", item.ID, err, processDuration)
|
||||||
|
|
||||||
outputData := map[string]interface{}{
|
outputData := map[string]interface{}{
|
||||||
"error": err.Error(),
|
"error": err.Error(),
|
||||||
"time": utils.GetCurrentTime(),
|
"time": utils.GetCurrentTime(),
|
||||||
|
"duration_ms": processDuration.Milliseconds(),
|
||||||
}
|
}
|
||||||
outputJSON, _ := json.Marshal(outputData)
|
outputJSON, _ := json.Marshal(outputData)
|
||||||
|
|
||||||
@@ -338,25 +400,49 @@ func (tm *TaskManager) processTaskItem(ctx context.Context, taskID uint, item *e
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 处理成功
|
// 处理成功
|
||||||
|
utils.Info("处理任务项 %d 成功,处理耗时: %v", item.ID, processDuration)
|
||||||
|
|
||||||
// 如果处理器已经设置了 output_data(比如 ExpansionProcessor),则不覆盖
|
// 如果处理器已经设置了 output_data(比如 ExpansionProcessor),则不覆盖
|
||||||
var outputJSON string
|
var outputJSON string
|
||||||
if item.OutputData == "" {
|
if item.OutputData == "" {
|
||||||
outputData := map[string]interface{}{
|
outputData := map[string]interface{}{
|
||||||
"success": true,
|
"success": true,
|
||||||
"time": utils.GetCurrentTime(),
|
"time": utils.GetCurrentTime(),
|
||||||
|
"duration_ms": processDuration.Milliseconds(),
|
||||||
}
|
}
|
||||||
outputBytes, _ := json.Marshal(outputData)
|
outputBytes, _ := json.Marshal(outputData)
|
||||||
outputJSON = string(outputBytes)
|
outputJSON = string(outputBytes)
|
||||||
} else {
|
} else {
|
||||||
// 使用处理器设置的 output_data
|
// 使用处理器设置的 output_data,并添加处理时间信息
|
||||||
outputJSON = item.OutputData
|
var existingOutput map[string]interface{}
|
||||||
|
if json.Unmarshal([]byte(item.OutputData), &existingOutput) == nil {
|
||||||
|
existingOutput["duration_ms"] = processDuration.Milliseconds()
|
||||||
|
outputBytes, _ := json.Marshal(existingOutput)
|
||||||
|
outputJSON = string(outputBytes)
|
||||||
|
} else {
|
||||||
|
// 如果无法解析现有输出,保留原样并添加时间信息
|
||||||
|
outputData := map[string]interface{}{
|
||||||
|
"original_output": item.OutputData,
|
||||||
|
"success": true,
|
||||||
|
"time": utils.GetCurrentTime(),
|
||||||
|
"duration_ms": processDuration.Milliseconds(),
|
||||||
|
}
|
||||||
|
outputBytes, _ := json.Marshal(outputData)
|
||||||
|
outputJSON = string(outputBytes)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
updateSuccessStart := utils.GetCurrentTime()
|
||||||
err = tm.repoMgr.TaskItemRepository.UpdateStatusAndOutput(item.ID, "completed", outputJSON)
|
err = tm.repoMgr.TaskItemRepository.UpdateStatusAndOutput(item.ID, "completed", outputJSON)
|
||||||
|
updateSuccessDuration := time.Since(updateSuccessStart)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
utils.Error("更新成功任务项状态失败: %v", err)
|
utils.Error("更新成功任务项状态失败: %v,耗时: %v", err, updateSuccessDuration)
|
||||||
|
} else {
|
||||||
|
utils.Debug("更新成功任务项状态完成,耗时: %v", updateSuccessDuration)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
itemDuration := time.Since(itemStartTime)
|
||||||
|
utils.Debug("任务项 %d 处理完成,总耗时: %v", item.ID, itemDuration)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -51,20 +51,42 @@ type TransferOutput struct {
|
|||||||
|
|
||||||
// Process 处理转存任务项
|
// Process 处理转存任务项
|
||||||
func (tp *TransferProcessor) Process(ctx context.Context, taskID uint, item *entity.TaskItem) error {
|
func (tp *TransferProcessor) Process(ctx context.Context, taskID uint, item *entity.TaskItem) error {
|
||||||
utils.Info("开始处理转存任务项: %d", item.ID)
|
startTime := utils.GetCurrentTime()
|
||||||
|
utils.InfoWithFields(map[string]interface{}{
|
||||||
|
"task_item_id": item.ID,
|
||||||
|
"task_id": taskID,
|
||||||
|
}, "开始处理转存任务项: %d", item.ID)
|
||||||
|
|
||||||
// 解析输入数据
|
// 解析输入数据
|
||||||
|
parseStart := utils.GetCurrentTime()
|
||||||
var input TransferInput
|
var input TransferInput
|
||||||
if err := json.Unmarshal([]byte(item.InputData), &input); err != nil {
|
if err := json.Unmarshal([]byte(item.InputData), &input); err != nil {
|
||||||
|
parseDuration := time.Since(parseStart)
|
||||||
|
utils.ErrorWithFields(map[string]interface{}{
|
||||||
|
"error": err.Error(),
|
||||||
|
"duration_ms": parseDuration.Milliseconds(),
|
||||||
|
}, "解析输入数据失败: %v,耗时: %v", err, parseDuration)
|
||||||
return fmt.Errorf("解析输入数据失败: %v", err)
|
return fmt.Errorf("解析输入数据失败: %v", err)
|
||||||
}
|
}
|
||||||
|
parseDuration := time.Since(parseStart)
|
||||||
|
utils.DebugWithFields(map[string]interface{}{
|
||||||
|
"duration_ms": parseDuration.Milliseconds(),
|
||||||
|
}, "解析输入数据完成,耗时: %v", parseDuration)
|
||||||
|
|
||||||
// 验证输入数据
|
// 验证输入数据
|
||||||
|
validateStart := utils.GetCurrentTime()
|
||||||
if err := tp.validateInput(&input); err != nil {
|
if err := tp.validateInput(&input); err != nil {
|
||||||
|
validateDuration := time.Since(validateStart)
|
||||||
|
utils.Error("输入数据验证失败: %v,耗时: %v", err, validateDuration)
|
||||||
return fmt.Errorf("输入数据验证失败: %v", err)
|
return fmt.Errorf("输入数据验证失败: %v", err)
|
||||||
}
|
}
|
||||||
|
validateDuration := time.Since(validateStart)
|
||||||
|
utils.DebugWithFields(map[string]interface{}{
|
||||||
|
"duration_ms": validateDuration.Milliseconds(),
|
||||||
|
}, "输入数据验证完成,耗时: %v", validateDuration)
|
||||||
|
|
||||||
// 获取任务配置中的账号信息
|
// 获取任务配置中的账号信息
|
||||||
|
configStart := utils.GetCurrentTime()
|
||||||
var selectedAccounts []uint
|
var selectedAccounts []uint
|
||||||
task, err := tp.repoMgr.TaskRepository.GetByID(taskID)
|
task, err := tp.repoMgr.TaskRepository.GetByID(taskID)
|
||||||
if err == nil && task.Config != "" {
|
if err == nil && task.Config != "" {
|
||||||
@@ -79,15 +101,21 @@ func (tp *TransferProcessor) Process(ctx context.Context, taskID uint, item *ent
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
configDuration := time.Since(configStart)
|
||||||
|
utils.Debug("获取任务配置完成,耗时: %v", configDuration)
|
||||||
|
|
||||||
if len(selectedAccounts) == 0 {
|
if len(selectedAccounts) == 0 {
|
||||||
utils.Error("失败: %v", "没有指定转存账号")
|
utils.Error("失败: %v", "没有指定转存账号")
|
||||||
}
|
}
|
||||||
|
|
||||||
// 检查资源是否已存在
|
// 检查资源是否已存在
|
||||||
|
checkStart := utils.GetCurrentTime()
|
||||||
exists, existingResource, err := tp.checkResourceExists(input.URL)
|
exists, existingResource, err := tp.checkResourceExists(input.URL)
|
||||||
|
checkDuration := time.Since(checkStart)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
utils.Error("检查资源是否存在失败: %v", err)
|
utils.Error("检查资源是否存在失败: %v,耗时: %v", err, checkDuration)
|
||||||
|
} else {
|
||||||
|
utils.Debug("检查资源是否存在完成,耗时: %v", checkDuration)
|
||||||
}
|
}
|
||||||
|
|
||||||
if exists {
|
if exists {
|
||||||
@@ -107,19 +135,26 @@ func (tp *TransferProcessor) Process(ctx context.Context, taskID uint, item *ent
|
|||||||
outputJSON, _ := json.Marshal(output)
|
outputJSON, _ := json.Marshal(output)
|
||||||
item.OutputData = string(outputJSON)
|
item.OutputData = string(outputJSON)
|
||||||
|
|
||||||
utils.Info("资源已存在且有转存链接,跳过转存: %s", input.Title)
|
elapsedTime := time.Since(startTime)
|
||||||
|
utils.Info("资源已存在且有转存链接,跳过转存: %s,总耗时: %v", input.Title, elapsedTime)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 查询出 账号列表
|
// 查询出 账号列表
|
||||||
|
cksStart := utils.GetCurrentTime()
|
||||||
cks, err := tp.repoMgr.CksRepository.FindByIds(selectedAccounts)
|
cks, err := tp.repoMgr.CksRepository.FindByIds(selectedAccounts)
|
||||||
|
cksDuration := time.Since(cksStart)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
utils.Error("读取账号失败: %v", err)
|
utils.Error("读取账号失败: %v,耗时: %v", err, cksDuration)
|
||||||
|
} else {
|
||||||
|
utils.Debug("读取账号完成,账号数量: %d,耗时: %v", len(cks), cksDuration)
|
||||||
}
|
}
|
||||||
|
|
||||||
// 执行转存操作
|
// 执行转存操作
|
||||||
|
transferStart := utils.GetCurrentTime()
|
||||||
resourceID, saveURL, err := tp.performTransfer(ctx, &input, cks)
|
resourceID, saveURL, err := tp.performTransfer(ctx, &input, cks)
|
||||||
|
transferDuration := time.Since(transferStart)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
// 转存失败,更新输出数据
|
// 转存失败,更新输出数据
|
||||||
output := TransferOutput{
|
output := TransferOutput{
|
||||||
@@ -131,7 +166,13 @@ func (tp *TransferProcessor) Process(ctx context.Context, taskID uint, item *ent
|
|||||||
outputJSON, _ := json.Marshal(output)
|
outputJSON, _ := json.Marshal(output)
|
||||||
item.OutputData = string(outputJSON)
|
item.OutputData = string(outputJSON)
|
||||||
|
|
||||||
utils.Error("转存任务项处理失败: %d, 错误: %v", item.ID, err)
|
elapsedTime := time.Since(startTime)
|
||||||
|
utils.ErrorWithFields(map[string]interface{}{
|
||||||
|
"task_item_id": item.ID,
|
||||||
|
"error": err.Error(),
|
||||||
|
"duration_ms": transferDuration.Milliseconds(),
|
||||||
|
"total_ms": elapsedTime.Milliseconds(),
|
||||||
|
}, "转存任务项处理失败: %d, 错误: %v,转存耗时: %v,总耗时: %v", item.ID, err, transferDuration, elapsedTime)
|
||||||
return fmt.Errorf("转存失败: %v", err)
|
return fmt.Errorf("转存失败: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -146,7 +187,8 @@ func (tp *TransferProcessor) Process(ctx context.Context, taskID uint, item *ent
|
|||||||
outputJSON, _ := json.Marshal(output)
|
outputJSON, _ := json.Marshal(output)
|
||||||
item.OutputData = string(outputJSON)
|
item.OutputData = string(outputJSON)
|
||||||
|
|
||||||
utils.Error("转存任务项处理失败: %d, 未获取到分享链接", item.ID)
|
elapsedTime := time.Since(startTime)
|
||||||
|
utils.Error("转存任务项处理失败: %d, 未获取到分享链接,总耗时: %v", item.ID, elapsedTime)
|
||||||
return fmt.Errorf("转存成功但未获取到分享链接")
|
return fmt.Errorf("转存成功但未获取到分享链接")
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -161,7 +203,14 @@ func (tp *TransferProcessor) Process(ctx context.Context, taskID uint, item *ent
|
|||||||
outputJSON, _ := json.Marshal(output)
|
outputJSON, _ := json.Marshal(output)
|
||||||
item.OutputData = string(outputJSON)
|
item.OutputData = string(outputJSON)
|
||||||
|
|
||||||
utils.Info("转存任务项处理完成: %d, 资源ID: %d, 转存链接: %s", item.ID, resourceID, saveURL)
|
elapsedTime := time.Since(startTime)
|
||||||
|
utils.InfoWithFields(map[string]interface{}{
|
||||||
|
"task_item_id": item.ID,
|
||||||
|
"resource_id": resourceID,
|
||||||
|
"save_url": saveURL,
|
||||||
|
"transfer_duration_ms": transferDuration.Milliseconds(),
|
||||||
|
"total_duration_ms": elapsedTime.Milliseconds(),
|
||||||
|
}, "转存任务项处理完成: %d, 资源ID: %d, 转存链接: %s,转存耗时: %v,总耗时: %v", item.ID, resourceID, saveURL, transferDuration, elapsedTime)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
217
utils/logger.go
217
utils/logger.go
@@ -1,12 +1,14 @@
|
|||||||
package utils
|
package utils
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"log"
|
"log"
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"runtime"
|
"runtime"
|
||||||
|
"strings"
|
||||||
"sync"
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
@@ -40,6 +42,16 @@ func (l LogLevel) String() string {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// StructuredLogEntry 结构化日志条目
|
||||||
|
type StructuredLogEntry struct {
|
||||||
|
Timestamp time.Time `json:"timestamp"`
|
||||||
|
Level string `json:"level"`
|
||||||
|
Message string `json:"message"`
|
||||||
|
Caller string `json:"caller"`
|
||||||
|
Module string `json:"module"`
|
||||||
|
Fields map[string]interface{} `json:"fields,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
// Logger 统一日志器
|
// Logger 统一日志器
|
||||||
type Logger struct {
|
type Logger struct {
|
||||||
debugLogger *log.Logger
|
debugLogger *log.Logger
|
||||||
@@ -63,22 +75,72 @@ type LogConfig struct {
|
|||||||
EnableConsole bool // 是否启用控制台输出
|
EnableConsole bool // 是否启用控制台输出
|
||||||
EnableFile bool // 是否启用文件输出
|
EnableFile bool // 是否启用文件输出
|
||||||
EnableRotation bool // 是否启用日志轮转
|
EnableRotation bool // 是否启用日志轮转
|
||||||
|
StructuredLog bool // 是否启用结构化日志格式
|
||||||
}
|
}
|
||||||
|
|
||||||
// DefaultConfig 默认配置
|
// DefaultConfig 默认配置
|
||||||
func DefaultConfig() *LogConfig {
|
func DefaultConfig() *LogConfig {
|
||||||
|
// 从环境变量获取日志级别,默认为INFO
|
||||||
|
logLevel := getLogLevelFromEnv()
|
||||||
|
|
||||||
return &LogConfig{
|
return &LogConfig{
|
||||||
LogDir: "logs",
|
LogDir: "logs",
|
||||||
LogLevel: INFO,
|
LogLevel: logLevel,
|
||||||
MaxFileSize: 100, // 100MB
|
MaxFileSize: 100, // 100MB
|
||||||
MaxBackups: 5,
|
MaxBackups: 5,
|
||||||
MaxAge: 30, // 30天
|
MaxAge: 30, // 30天
|
||||||
EnableConsole: true,
|
EnableConsole: true,
|
||||||
EnableFile: true,
|
EnableFile: true,
|
||||||
EnableRotation: true,
|
EnableRotation: true,
|
||||||
|
StructuredLog: os.Getenv("STRUCTURED_LOG") == "true", // 从环境变量控制结构化日志
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// getLogLevelFromEnv 从环境变量获取日志级别
|
||||||
|
func getLogLevelFromEnv() LogLevel {
|
||||||
|
envLogLevel := os.Getenv("LOG_LEVEL")
|
||||||
|
envDebug := os.Getenv("DEBUG")
|
||||||
|
|
||||||
|
// 如果设置了DEBUG环境变量为true,则使用DEBUG级别
|
||||||
|
if envDebug == "true" || envDebug == "1" {
|
||||||
|
return DEBUG
|
||||||
|
}
|
||||||
|
|
||||||
|
// 根据LOG_LEVEL环境变量设置日志级别
|
||||||
|
switch strings.ToUpper(envLogLevel) {
|
||||||
|
case "DEBUG":
|
||||||
|
return DEBUG
|
||||||
|
case "INFO":
|
||||||
|
return INFO
|
||||||
|
case "WARN", "WARNING":
|
||||||
|
return WARN
|
||||||
|
case "ERROR":
|
||||||
|
return ERROR
|
||||||
|
case "FATAL":
|
||||||
|
return FATAL
|
||||||
|
default:
|
||||||
|
// 根据运行环境设置默认级别:开发环境DEBUG,生产环境INFO
|
||||||
|
if isDevelopment() {
|
||||||
|
return DEBUG
|
||||||
|
}
|
||||||
|
return INFO
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// isDevelopment 判断是否为开发环境
|
||||||
|
func isDevelopment() bool {
|
||||||
|
env := os.Getenv("GO_ENV")
|
||||||
|
return env == "development" || env == "dev" || env == "local" || env == "test"
|
||||||
|
}
|
||||||
|
|
||||||
|
// getEnvironment 获取当前环境类型
|
||||||
|
func (l *Logger) getEnvironment() string {
|
||||||
|
if isDevelopment() {
|
||||||
|
return "development"
|
||||||
|
}
|
||||||
|
return "production"
|
||||||
|
}
|
||||||
|
|
||||||
var (
|
var (
|
||||||
globalLogger *Logger
|
globalLogger *Logger
|
||||||
onceLogger sync.Once
|
onceLogger sync.Once
|
||||||
@@ -135,6 +197,11 @@ func NewLogger(config *LogConfig) (*Logger, error) {
|
|||||||
go logger.startRotationCheck()
|
go logger.startRotationCheck()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 打印日志配置信息
|
||||||
|
logger.Info("日志系统初始化完成 - 级别: %s, 环境: %s",
|
||||||
|
config.LogLevel.String(),
|
||||||
|
logger.getEnvironment())
|
||||||
|
|
||||||
return logger, nil
|
return logger, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -200,26 +267,55 @@ func (l *Logger) log(level LogLevel, format string, args ...interface{}) {
|
|||||||
line = 0
|
line = 0
|
||||||
}
|
}
|
||||||
|
|
||||||
// 提取文件名
|
// 提取文件名作为模块名
|
||||||
fileName := filepath.Base(file)
|
fileName := filepath.Base(file)
|
||||||
|
moduleName := strings.TrimSuffix(fileName, filepath.Ext(fileName))
|
||||||
|
|
||||||
// 格式化消息
|
// 格式化消息
|
||||||
message := fmt.Sprintf(format, args...)
|
message := fmt.Sprintf(format, args...)
|
||||||
|
|
||||||
// 添加调用位置信息
|
// 添加调用位置信息
|
||||||
fullMessage := fmt.Sprintf("[%s:%d] %s", fileName, line, message)
|
caller := fmt.Sprintf("%s:%d", fileName, line)
|
||||||
|
|
||||||
|
if l.config.StructuredLog {
|
||||||
|
// 结构化日志格式
|
||||||
|
entry := StructuredLogEntry{
|
||||||
|
Timestamp: GetCurrentTime(),
|
||||||
|
Level: level.String(),
|
||||||
|
Message: message,
|
||||||
|
Caller: caller,
|
||||||
|
Module: moduleName,
|
||||||
|
}
|
||||||
|
|
||||||
|
jsonBytes, err := json.Marshal(entry)
|
||||||
|
if err != nil {
|
||||||
|
// 如果JSON序列化失败,回退到普通格式
|
||||||
|
fullMessage := fmt.Sprintf("[%s] [%s:%d] %s", level.String(), fileName, line, message)
|
||||||
|
l.logToLevel(level, fullMessage)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
l.logToLevel(level, string(jsonBytes))
|
||||||
|
} else {
|
||||||
|
// 普通文本格式
|
||||||
|
fullMessage := fmt.Sprintf("[%s] [%s:%d] %s", level.String(), fileName, line, message)
|
||||||
|
l.logToLevel(level, fullMessage)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// logToLevel 根据级别输出日志
|
||||||
|
func (l *Logger) logToLevel(level LogLevel, message string) {
|
||||||
switch level {
|
switch level {
|
||||||
case DEBUG:
|
case DEBUG:
|
||||||
l.debugLogger.Println(fullMessage)
|
l.debugLogger.Println(message)
|
||||||
case INFO:
|
case INFO:
|
||||||
l.infoLogger.Println(fullMessage)
|
l.infoLogger.Println(message)
|
||||||
case WARN:
|
case WARN:
|
||||||
l.warnLogger.Println(fullMessage)
|
l.warnLogger.Println(message)
|
||||||
case ERROR:
|
case ERROR:
|
||||||
l.errorLogger.Println(fullMessage)
|
l.errorLogger.Println(message)
|
||||||
case FATAL:
|
case FATAL:
|
||||||
l.fatalLogger.Println(fullMessage)
|
l.fatalLogger.Println(message)
|
||||||
os.Exit(1)
|
os.Exit(1)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -328,15 +424,83 @@ func (l *Logger) cleanOldLogs() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Close 关闭日志器
|
// Min 返回两个整数中的较小值
|
||||||
func (l *Logger) Close() error {
|
func Min(a, b int) int {
|
||||||
l.mu.Lock()
|
if a < b {
|
||||||
defer l.mu.Unlock()
|
return a
|
||||||
|
}
|
||||||
if l.file != nil {
|
return b
|
||||||
return l.file.Close()
|
}
|
||||||
|
|
||||||
|
// 结构化日志方法
|
||||||
|
func (l *Logger) DebugWithFields(fields map[string]interface{}, format string, args ...interface{}) {
|
||||||
|
l.logWithFields(DEBUG, fields, format, args...)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (l *Logger) InfoWithFields(fields map[string]interface{}, format string, args ...interface{}) {
|
||||||
|
l.logWithFields(INFO, fields, format, args...)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (l *Logger) WarnWithFields(fields map[string]interface{}, format string, args ...interface{}) {
|
||||||
|
l.logWithFields(WARN, fields, format, args...)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (l *Logger) ErrorWithFields(fields map[string]interface{}, format string, args ...interface{}) {
|
||||||
|
l.logWithFields(ERROR, fields, format, args...)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (l *Logger) FatalWithFields(fields map[string]interface{}, format string, args ...interface{}) {
|
||||||
|
l.logWithFields(FATAL, fields, format, args...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// logWithFields 带字段的结构化日志方法
|
||||||
|
func (l *Logger) logWithFields(level LogLevel, fields map[string]interface{}, format string, args ...interface{}) {
|
||||||
|
if level < l.config.LogLevel {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取调用者信息
|
||||||
|
_, file, line, ok := runtime.Caller(2)
|
||||||
|
if !ok {
|
||||||
|
file = "unknown"
|
||||||
|
line = 0
|
||||||
|
}
|
||||||
|
|
||||||
|
// 提取文件名作为模块名
|
||||||
|
fileName := filepath.Base(file)
|
||||||
|
moduleName := strings.TrimSuffix(fileName, filepath.Ext(fileName))
|
||||||
|
|
||||||
|
// 格式化消息
|
||||||
|
message := fmt.Sprintf(format, args...)
|
||||||
|
|
||||||
|
// 添加调用位置信息
|
||||||
|
caller := fmt.Sprintf("%s:%d", fileName, line)
|
||||||
|
|
||||||
|
if l.config.StructuredLog {
|
||||||
|
// 结构化日志格式
|
||||||
|
entry := StructuredLogEntry{
|
||||||
|
Timestamp: GetCurrentTime(),
|
||||||
|
Level: level.String(),
|
||||||
|
Message: message,
|
||||||
|
Caller: caller,
|
||||||
|
Module: moduleName,
|
||||||
|
Fields: fields,
|
||||||
|
}
|
||||||
|
|
||||||
|
jsonBytes, err := json.Marshal(entry)
|
||||||
|
if err != nil {
|
||||||
|
// 如果JSON序列化失败,回退到普通格式
|
||||||
|
fullMessage := fmt.Sprintf("[%s] [%s:%d] %s - Fields: %v", level.String(), fileName, line, message, fields)
|
||||||
|
l.logToLevel(level, fullMessage)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
l.logToLevel(level, string(jsonBytes))
|
||||||
|
} else {
|
||||||
|
// 普通文本格式
|
||||||
|
fullMessage := fmt.Sprintf("[%s] [%s:%d] %s - Fields: %v", level.String(), fileName, line, message, fields)
|
||||||
|
l.logToLevel(level, fullMessage)
|
||||||
}
|
}
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// 全局便捷函数
|
// 全局便捷函数
|
||||||
@@ -359,3 +523,24 @@ func Error(format string, args ...interface{}) {
|
|||||||
func Fatal(format string, args ...interface{}) {
|
func Fatal(format string, args ...interface{}) {
|
||||||
GetLogger().Fatal(format, args...)
|
GetLogger().Fatal(format, args...)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 全局结构化日志便捷函数
|
||||||
|
func DebugWithFields(fields map[string]interface{}, format string, args ...interface{}) {
|
||||||
|
GetLogger().DebugWithFields(fields, format, args...)
|
||||||
|
}
|
||||||
|
|
||||||
|
func InfoWithFields(fields map[string]interface{}, format string, args ...interface{}) {
|
||||||
|
GetLogger().InfoWithFields(fields, format, args...)
|
||||||
|
}
|
||||||
|
|
||||||
|
func WarnWithFields(fields map[string]interface{}, format string, args ...interface{}) {
|
||||||
|
GetLogger().WarnWithFields(fields, format, args...)
|
||||||
|
}
|
||||||
|
|
||||||
|
func ErrorWithFields(fields map[string]interface{}, format string, args ...interface{}) {
|
||||||
|
GetLogger().ErrorWithFields(fields, format, args...)
|
||||||
|
}
|
||||||
|
|
||||||
|
func FatalWithFields(fields map[string]interface{}, format string, args ...interface{}) {
|
||||||
|
GetLogger().FatalWithFields(fields, format, args...)
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user