feat(api): add traffic log details filtering and enhance traffic log structures

This commit is contained in:
Chang lue Tsen
2025-08-26 02:29:25 -04:00
parent ad4f3df74e
commit 9b3cdbbb4f
43 changed files with 384 additions and 1481 deletions
@@ -4,9 +4,13 @@ import (
"context"
"time"
"github.com/perfect-panel/server/internal/model/log"
"github.com/perfect-panel/server/internal/model/traffic"
"github.com/perfect-panel/server/internal/svc"
"github.com/perfect-panel/server/internal/types"
"github.com/perfect-panel/server/pkg/logger"
"github.com/perfect-panel/server/pkg/xerr"
"github.com/pkg/errors"
)
type FilterServerTrafficLogLogic struct {
@@ -23,21 +27,124 @@ func NewFilterServerTrafficLogLogic(ctx context.Context, svcCtx *svc.ServiceCont
svcCtx: svcCtx,
}
}
func (l *FilterServerTrafficLogLogic) FilterServerTrafficLog(req *types.FilterServerTrafficLogRequest) (resp *types.FilterServerTrafficLogResponse, err error) {
today := time.Now().Format("2006-01-02")
if req.Date == "" || req.Date == today {
return l.handlerToday(req)
} else {
return l.handlerSpecify(req)
var list []types.ServerTrafficLog
var total int64
if req.Date == today || req.Date == "" {
now := time.Now()
start := time.Date(now.Year(), now.Month(), now.Day(), 0, 0, 0, 0, time.Local)
end := start.Add(24 * time.Hour).Add(-time.Nanosecond)
var serverTraffic []log.ServerTraffic
err = l.svcCtx.DB.WithContext(l.ctx).
Model(&traffic.TrafficLog{}).
Select("server_id, SUM(download + upload) AS total, SUM(download) AS download, SUM(upload) AS upload").
Where("timestamp BETWEEN ? AND ?", start, end).
Group("server_id").
Order("id DESC").
Scan(&serverTraffic).Error
if err != nil {
l.Errorw("[FilterServerTrafficLog] Query Database Error", logger.Field("error", err.Error()))
return nil, errors.Wrapf(xerr.NewErrCode(xerr.DatabaseQueryError), "today traffic query error: %s", err.Error())
}
for _, v := range serverTraffic {
list = append(list, types.ServerTrafficLog{
ServerId: v.ServerId,
Upload: v.Upload,
Download: v.Download,
Total: v.Total,
Date: today,
Details: true,
})
}
todayTotal := len(list)
startIdx := (req.Page - 1) * req.Size
endIdx := startIdx + req.Size
if startIdx < todayTotal {
if endIdx > todayTotal {
endIdx = todayTotal
}
pageData := list[startIdx:endIdx]
return &types.FilterServerTrafficLogResponse{
List: pageData,
Total: int64(todayTotal),
}, nil
}
need := endIdx - todayTotal
historyPage := (need + req.Size - 1) / req.Size // 算出需要的历史页数
historyData, historyTotal, err := l.svcCtx.LogModel.FilterSystemLog(l.ctx, &log.FilterParams{
Page: historyPage,
Size: need,
Type: log.TypeServerTraffic.Uint8(),
})
if err != nil {
l.Errorw("[FilterServerTrafficLog] Query History Error", logger.Field("error", err.Error()))
return nil, errors.Wrapf(xerr.NewErrCode(xerr.DatabaseQueryError), "history query error: %s", err.Error())
}
for _, item := range historyData {
var content log.ServerTraffic
if err = content.Unmarshal([]byte(item.Content)); err != nil {
l.Errorw("[FilterServerTrafficLog] Unmarshal Error", logger.Field("error", err.Error()), logger.Field("content", item.Content))
continue
}
list = append(list, types.ServerTrafficLog{
ServerId: item.ObjectID,
Upload: content.Upload,
Download: content.Download,
Total: content.Total,
Date: item.Date,
Details: false,
})
}
// 返回最终分页数据
if endIdx > len(list) {
endIdx = len(list)
}
pageData := list[startIdx:endIdx]
return &types.FilterServerTrafficLogResponse{
List: pageData,
Total: int64(todayTotal) + historyTotal,
}, nil
}
}
func (l *FilterServerTrafficLogLogic) handlerToday(req *types.FilterServerTrafficLogRequest) (resp *types.FilterServerTrafficLogResponse, err error) {
data, total, err := l.svcCtx.LogModel.FilterSystemLog(l.ctx, &log.FilterParams{
Page: req.Page,
Size: req.Size,
Type: log.TypeServerTraffic.Uint8(),
})
if err != nil {
l.Errorw("[FilterServerTrafficLog] Query Database Error", logger.Field("error", err.Error()))
return nil, errors.Wrapf(xerr.NewErrCode(xerr.DatabaseQueryError), "history query error: %s", err.Error())
}
return
}
for _, item := range data {
var content log.ServerTraffic
if err = content.Unmarshal([]byte(item.Content)); err != nil {
l.Errorw("[FilterServerTrafficLog] Unmarshal Error", logger.Field("error", err.Error()), logger.Field("content", item.Content))
continue
}
list = append(list, types.ServerTrafficLog{
ServerId: item.ObjectID,
Upload: content.Upload,
Download: content.Download,
Total: content.Total,
Date: item.Date,
Details: false,
})
}
func (l *FilterServerTrafficLogLogic) handlerSpecify(req *types.FilterServerTrafficLogRequest) (resp *types.FilterServerTrafficLogResponse, err error) {
return
return &types.FilterServerTrafficLogResponse{
List: list,
Total: total,
}, nil
}
@@ -0,0 +1,79 @@
package log
import (
"context"
"time"
"github.com/perfect-panel/server/internal/model/traffic"
"github.com/perfect-panel/server/internal/svc"
"github.com/perfect-panel/server/internal/types"
"github.com/perfect-panel/server/pkg/logger"
"github.com/perfect-panel/server/pkg/xerr"
"github.com/pkg/errors"
)
type FilterTrafficLogDetailsLogic struct {
logger.Logger
ctx context.Context
svcCtx *svc.ServiceContext
}
// Filter traffic log details
func NewFilterTrafficLogDetailsLogic(ctx context.Context, svcCtx *svc.ServiceContext) *FilterTrafficLogDetailsLogic {
return &FilterTrafficLogDetailsLogic{
Logger: logger.WithContext(ctx),
ctx: ctx,
svcCtx: svcCtx,
}
}
func (l *FilterTrafficLogDetailsLogic) FilterTrafficLogDetails(req *types.FilterTrafficLogDetailsRequest) (resp *types.FilterTrafficLogDetailsResponse, err error) {
var start, end time.Time
if req.Date != "" {
day, err := time.ParseInLocation("2006-01-02", req.Date, time.Local)
if err != nil {
l.Errorw("[FilterTrafficLogDetails] Date Parse Error", logger.Field("error", err.Error()))
return nil, errors.Wrapf(xerr.NewErrCode(xerr.InvalidParams), " date parse error: %s", err.Error())
}
start = day
end = day.Add(24*time.Hour - time.Nanosecond)
}
var data []*traffic.TrafficLog
tx := l.svcCtx.DB.WithContext(l.ctx).Model(&traffic.TrafficLog{})
if req.ServerId != 0 {
tx = tx.Where("server_id = ?", req.ServerId)
}
if !start.IsZero() && !end.IsZero() {
tx = tx.Where("timestamp BETWEEN ? AND ?", start, end)
}
if req.UserId != 0 {
tx = tx.Where("user_id = ?", req.UserId)
}
if req.SubscribeId != 0 {
tx = tx.Where("subscribe_id = ?", req.SubscribeId)
}
var total int64
err = tx.Count(&total).Limit(req.Size).Offset((req.Page - 1) * req.Size).Find(&data).Error
if err != nil {
l.Errorw("[FilterTrafficLogDetails] Query Database Error", logger.Field("error", err.Error()))
return nil, errors.Wrapf(xerr.NewErrCode(xerr.DatabaseQueryError), " database query error: %s", err.Error())
}
var logs []types.TrafficLogDetails
for _, v := range data {
logs = append(logs, types.TrafficLogDetails{
Id: v.Id,
UserId: v.UserId,
ServerId: v.ServerId,
SubscribeId: v.SubscribeId,
Download: v.Download,
Upload: v.Upload,
Timestamp: v.Timestamp.UnixMilli(),
})
}
return &types.FilterTrafficLogDetailsResponse{
List: logs,
Total: total,
}, nil
}
@@ -2,10 +2,15 @@ package log
import (
"context"
"time"
"github.com/perfect-panel/server/internal/model/log"
"github.com/perfect-panel/server/internal/model/traffic"
"github.com/perfect-panel/server/internal/svc"
"github.com/perfect-panel/server/internal/types"
"github.com/perfect-panel/server/pkg/logger"
"github.com/perfect-panel/server/pkg/xerr"
"github.com/pkg/errors"
)
type FilterUserSubscribeTrafficLogLogic struct {
@@ -24,7 +29,125 @@ func NewFilterUserSubscribeTrafficLogLogic(ctx context.Context, svcCtx *svc.Serv
}
func (l *FilterUserSubscribeTrafficLogLogic) FilterUserSubscribeTrafficLog(req *types.FilterSubscribeTrafficRequest) (resp *types.FilterSubscribeTrafficResponse, err error) {
// todo: add your logic here and delete this line
today := time.Now().Format("2006-01-02")
var list []types.UserSubscribeTrafficLog
var total int64
return
if req.Date == today || req.Date == "" {
now := time.Now()
start := time.Date(now.Year(), now.Month(), now.Day(), 0, 0, 0, 0, time.Local)
end := start.Add(24 * time.Hour).Add(-time.Nanosecond)
var userTraffic []types.UserSubscribeTrafficLog
err = l.svcCtx.DB.WithContext(l.ctx).
Model(&traffic.TrafficLog{}).
Select("user_id, subscribe_id, SUM(download + upload) AS total, SUM(download) AS download, SUM(upload) AS upload").
Where("timestamp BETWEEN ? AND ?", start, end).
Group("user_id, subscribe_id").
Order("id DESC").
Scan(&userTraffic).Error
if err != nil {
l.Errorw("[FilterUserSubscribeTrafficLog] Query Database Error", logger.Field("error", err.Error()))
return nil, err
}
for _, v := range userTraffic {
list = append(list, types.UserSubscribeTrafficLog{
UserId: v.UserId,
SubscribeId: v.SubscribeId,
Upload: v.Upload,
Download: v.Download,
Total: v.Total,
Date: today,
Details: true,
})
}
todayTotal := len(list)
startIdx := (req.Page - 1) * req.Size
endIdx := startIdx + req.Size
if startIdx < todayTotal {
if endIdx > todayTotal {
endIdx = todayTotal
}
pageData := list[startIdx:endIdx]
return &types.FilterSubscribeTrafficResponse{
List: pageData,
Total: int64(todayTotal),
}, nil
}
need := endIdx - todayTotal
historyPage := (need + req.Size - 1) / req.Size // 算出需要的历史页数
historyData, historyTotal, err := l.svcCtx.LogModel.FilterSystemLog(l.ctx, &log.FilterParams{
Page: historyPage,
Size: need,
Type: log.TypeSubscribeTraffic.Uint8(),
})
if err != nil {
l.Errorw("[FilterUserSubscribeTrafficLog] Query Database Error", logger.Field("error", err.Error()))
return nil, errors.Wrapf(xerr.NewErrCode(xerr.DatabaseQueryError), "[FilterUserSubscribeTrafficLog] Query Database Error")
}
for _, datum := range historyData {
var item log.UserTraffic
err = item.Unmarshal([]byte(datum.Content))
if err != nil {
l.Errorw("[FilterUserSubscribeTrafficLog] Unmarshal Content Error", logger.Field("error", err.Error()))
continue
}
list = append(list, types.UserSubscribeTrafficLog{
UserId: item.UserId,
SubscribeId: item.SubscribeId,
Upload: item.Upload,
Download: item.Download,
Total: item.Total,
Date: datum.Date,
Details: false,
})
}
// 返回最终分页数据
if endIdx > len(list) {
endIdx = len(list)
}
pageData := list[startIdx:endIdx]
return &types.FilterSubscribeTrafficResponse{
List: pageData,
Total: int64(todayTotal) + historyTotal,
}, nil
}
var data []*log.SystemLog
data, total, err = l.svcCtx.LogModel.FilterSystemLog(l.ctx, &log.FilterParams{
Page: req.Page,
Size: req.Size,
Type: log.TypeSubscribeTraffic.Uint8(),
Data: req.Date,
})
if err != nil {
l.Errorw("[FilterUserSubscribeTrafficLog] Query Database Error", logger.Field("error", err.Error()))
return nil, errors.Wrapf(xerr.NewErrCode(xerr.DatabaseQueryError), "[FilterUserSubscribeTrafficLog] Query Database Error")
}
for _, datum := range data {
var item log.UserTraffic
err = item.Unmarshal([]byte(datum.Content))
if err != nil {
l.Errorw("[FilterUserSubscribeTrafficLog] Unmarshal Content Error", logger.Field("error", err.Error()))
continue
}
list = append(list, types.UserSubscribeTrafficLog{
UserId: item.UserId,
SubscribeId: item.SubscribeId,
Upload: item.Upload,
Download: item.Download,
Total: item.Total,
Date: datum.Date,
Details: false,
})
}
return &types.FilterSubscribeTrafficResponse{
List: list,
Total: total,
}, nil
}