mirror of
https://github.com/TeaOSLab/EdgeAPI.git
synced 2025-11-11 04:50:25 +08:00
国家/地区统计时上传流量、攻击量等信息/多个统计增加自动清理程序
This commit is contained in:
@@ -16,7 +16,8 @@ const (
|
|||||||
RegionCountryStateDisabled = 0 // 已禁用
|
RegionCountryStateDisabled = 0 // 已禁用
|
||||||
)
|
)
|
||||||
|
|
||||||
var regionCountryNameAndIdCacheMap = map[string]int64{} // country name => int
|
var regionCountryNameAndIdCacheMap = map[string]int64{} // country name => id
|
||||||
|
var regionCountryIdAndNameCacheMap = map[int64]string{} // country id => name
|
||||||
|
|
||||||
type RegionCountryDAO dbs.DAO
|
type RegionCountryDAO dbs.DAO
|
||||||
|
|
||||||
@@ -39,7 +40,7 @@ func init() {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
// 启用条目
|
// EnableRegionCountry 启用条目
|
||||||
func (this *RegionCountryDAO) EnableRegionCountry(tx *dbs.Tx, id uint32) error {
|
func (this *RegionCountryDAO) EnableRegionCountry(tx *dbs.Tx, id uint32) error {
|
||||||
_, err := this.Query(tx).
|
_, err := this.Query(tx).
|
||||||
Pk(id).
|
Pk(id).
|
||||||
@@ -48,7 +49,7 @@ func (this *RegionCountryDAO) EnableRegionCountry(tx *dbs.Tx, id uint32) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// 禁用条目
|
// DisableRegionCountry 禁用条目
|
||||||
func (this *RegionCountryDAO) DisableRegionCountry(tx *dbs.Tx, id int64) error {
|
func (this *RegionCountryDAO) DisableRegionCountry(tx *dbs.Tx, id int64) error {
|
||||||
_, err := this.Query(tx).
|
_, err := this.Query(tx).
|
||||||
Pk(id).
|
Pk(id).
|
||||||
@@ -57,7 +58,7 @@ func (this *RegionCountryDAO) DisableRegionCountry(tx *dbs.Tx, id int64) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// 查找启用中的条目
|
// FindEnabledRegionCountry 查找启用中的条目
|
||||||
func (this *RegionCountryDAO) FindEnabledRegionCountry(tx *dbs.Tx, id int64) (*RegionCountry, error) {
|
func (this *RegionCountryDAO) FindEnabledRegionCountry(tx *dbs.Tx, id int64) (*RegionCountry, error) {
|
||||||
result, err := this.Query(tx).
|
result, err := this.Query(tx).
|
||||||
Pk(id).
|
Pk(id).
|
||||||
@@ -69,15 +70,29 @@ func (this *RegionCountryDAO) FindEnabledRegionCountry(tx *dbs.Tx, id int64) (*R
|
|||||||
return result.(*RegionCountry), err
|
return result.(*RegionCountry), err
|
||||||
}
|
}
|
||||||
|
|
||||||
// 根据主键查找名称
|
// FindRegionCountryName 根据主键查找名称
|
||||||
func (this *RegionCountryDAO) FindRegionCountryName(tx *dbs.Tx, id int64) (string, error) {
|
func (this *RegionCountryDAO) FindRegionCountryName(tx *dbs.Tx, id int64) (string, error) {
|
||||||
return this.Query(tx).
|
SharedCacheLocker.Lock()
|
||||||
|
defer SharedCacheLocker.Unlock()
|
||||||
|
|
||||||
|
name, ok := regionCountryIdAndNameCacheMap[id]
|
||||||
|
if ok {
|
||||||
|
return name, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
name, err := this.Query(tx).
|
||||||
Pk(id).
|
Pk(id).
|
||||||
Result("name").
|
Result("name").
|
||||||
FindStringCol("")
|
FindStringCol("")
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
regionCountryIdAndNameCacheMap[id] = name
|
||||||
|
return name, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// 根据数据ID查找国家
|
// FindCountryIdWithDataId 根据数据ID查找国家
|
||||||
func (this *RegionCountryDAO) FindCountryIdWithDataId(tx *dbs.Tx, dataId string) (int64, error) {
|
func (this *RegionCountryDAO) FindCountryIdWithDataId(tx *dbs.Tx, dataId string) (int64, error) {
|
||||||
return this.Query(tx).
|
return this.Query(tx).
|
||||||
Attr("dataId", dataId).
|
Attr("dataId", dataId).
|
||||||
@@ -85,7 +100,7 @@ func (this *RegionCountryDAO) FindCountryIdWithDataId(tx *dbs.Tx, dataId string)
|
|||||||
FindInt64Col(0)
|
FindInt64Col(0)
|
||||||
}
|
}
|
||||||
|
|
||||||
// 根据国家名查找国家ID
|
// FindCountryIdWithName 根据国家名查找国家ID
|
||||||
func (this *RegionCountryDAO) FindCountryIdWithName(tx *dbs.Tx, countryName string) (int64, error) {
|
func (this *RegionCountryDAO) FindCountryIdWithName(tx *dbs.Tx, countryName string) (int64, error) {
|
||||||
return this.Query(tx).
|
return this.Query(tx).
|
||||||
Where("JSON_CONTAINS(codes, :countryName)").
|
Where("JSON_CONTAINS(codes, :countryName)").
|
||||||
@@ -94,7 +109,7 @@ func (this *RegionCountryDAO) FindCountryIdWithName(tx *dbs.Tx, countryName stri
|
|||||||
FindInt64Col(0)
|
FindInt64Col(0)
|
||||||
}
|
}
|
||||||
|
|
||||||
// 根据国家名查找国家ID,并可使用缓存
|
// FindCountryIdWithNameCacheable 根据国家名查找国家ID,并可使用缓存
|
||||||
func (this *RegionCountryDAO) FindCountryIdWithNameCacheable(tx *dbs.Tx, countryName string) (int64, error) {
|
func (this *RegionCountryDAO) FindCountryIdWithNameCacheable(tx *dbs.Tx, countryName string) (int64, error) {
|
||||||
SharedCacheLocker.RLock()
|
SharedCacheLocker.RLock()
|
||||||
provinceId, ok := regionCountryNameAndIdCacheMap[countryName]
|
provinceId, ok := regionCountryNameAndIdCacheMap[countryName]
|
||||||
@@ -116,7 +131,7 @@ func (this *RegionCountryDAO) FindCountryIdWithNameCacheable(tx *dbs.Tx, country
|
|||||||
return countryId, nil
|
return countryId, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// 根据数据ID创建国家
|
// CreateCountry 根据数据ID创建国家
|
||||||
func (this *RegionCountryDAO) CreateCountry(tx *dbs.Tx, name string, dataId string) (int64, error) {
|
func (this *RegionCountryDAO) CreateCountry(tx *dbs.Tx, name string, dataId string) (int64, error) {
|
||||||
op := NewRegionCountryOperator()
|
op := NewRegionCountryOperator()
|
||||||
op.Name = name
|
op.Name = name
|
||||||
@@ -145,7 +160,7 @@ func (this *RegionCountryDAO) CreateCountry(tx *dbs.Tx, name string, dataId stri
|
|||||||
return types.Int64(op.Id), nil
|
return types.Int64(op.Id), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// 查找所有可用的国家
|
// FindAllEnabledCountriesOrderByPinyin 查找所有可用的国家
|
||||||
func (this *RegionCountryDAO) FindAllEnabledCountriesOrderByPinyin(tx *dbs.Tx) (result []*RegionCountry, err error) {
|
func (this *RegionCountryDAO) FindAllEnabledCountriesOrderByPinyin(tx *dbs.Tx) (result []*RegionCountry, err error) {
|
||||||
_, err = this.Query(tx).
|
_, err = this.Query(tx).
|
||||||
State(RegionCountryStateEnabled).
|
State(RegionCountryStateEnabled).
|
||||||
|
|||||||
@@ -2,12 +2,31 @@ package stats
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/TeaOSLab/EdgeAPI/internal/errors"
|
"github.com/TeaOSLab/EdgeAPI/internal/errors"
|
||||||
|
"github.com/TeaOSLab/EdgeAPI/internal/remotelogs"
|
||||||
_ "github.com/go-sql-driver/mysql"
|
_ "github.com/go-sql-driver/mysql"
|
||||||
"github.com/iwind/TeaGo/Tea"
|
"github.com/iwind/TeaGo/Tea"
|
||||||
"github.com/iwind/TeaGo/dbs"
|
"github.com/iwind/TeaGo/dbs"
|
||||||
"github.com/iwind/TeaGo/maps"
|
"github.com/iwind/TeaGo/maps"
|
||||||
|
"github.com/iwind/TeaGo/rands"
|
||||||
|
timeutil "github.com/iwind/TeaGo/utils/time"
|
||||||
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
dbs.OnReadyDone(func() {
|
||||||
|
// 清理数据任务
|
||||||
|
var ticker = time.NewTicker(time.Duration(rands.Int(24, 48)) * time.Hour)
|
||||||
|
go func() {
|
||||||
|
for range ticker.C {
|
||||||
|
err := SharedServerClientBrowserMonthlyStatDAO.Clean(nil)
|
||||||
|
if err != nil {
|
||||||
|
remotelogs.Error("ServerClientBrowserMonthlyStatDAO", "clean expired data failed: "+err.Error())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
type ServerClientBrowserMonthlyStatDAO dbs.DAO
|
type ServerClientBrowserMonthlyStatDAO dbs.DAO
|
||||||
|
|
||||||
func NewServerClientBrowserMonthlyStatDAO() *ServerClientBrowserMonthlyStatDAO {
|
func NewServerClientBrowserMonthlyStatDAO() *ServerClientBrowserMonthlyStatDAO {
|
||||||
@@ -29,7 +48,7 @@ func init() {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
// 增加数量
|
// IncreaseMonthlyCount 增加数量
|
||||||
func (this *ServerClientBrowserMonthlyStatDAO) IncreaseMonthlyCount(tx *dbs.Tx, serverId int64, browserId int64, version string, month string, count int64) error {
|
func (this *ServerClientBrowserMonthlyStatDAO) IncreaseMonthlyCount(tx *dbs.Tx, serverId int64, browserId int64, version string, month string, count int64) error {
|
||||||
if len(month) != 6 {
|
if len(month) != 6 {
|
||||||
return errors.New("invalid month '" + month + "'")
|
return errors.New("invalid month '" + month + "'")
|
||||||
@@ -51,7 +70,7 @@ func (this *ServerClientBrowserMonthlyStatDAO) IncreaseMonthlyCount(tx *dbs.Tx,
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// 查找单页数据
|
// ListStats 查找单页数据
|
||||||
func (this *ServerClientBrowserMonthlyStatDAO) ListStats(tx *dbs.Tx, serverId int64, month string, offset int64, size int64) (result []*ServerClientBrowserMonthlyStat, err error) {
|
func (this *ServerClientBrowserMonthlyStatDAO) ListStats(tx *dbs.Tx, serverId int64, month string, offset int64, size int64) (result []*ServerClientBrowserMonthlyStat, err error) {
|
||||||
query := this.Query(tx).
|
query := this.Query(tx).
|
||||||
Attr("serverId", serverId).
|
Attr("serverId", serverId).
|
||||||
@@ -63,3 +82,13 @@ func (this *ServerClientBrowserMonthlyStatDAO) ListStats(tx *dbs.Tx, serverId in
|
|||||||
_, err = query.FindAll()
|
_, err = query.FindAll()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Clean 清理统计数据
|
||||||
|
func (this *ServerClientBrowserMonthlyStatDAO) Clean(tx *dbs.Tx) error {
|
||||||
|
// 只保留两个月的
|
||||||
|
var month = timeutil.Format("Ym", time.Now().AddDate(0, -2, 0))
|
||||||
|
_, err := this.Query(tx).
|
||||||
|
Lte("month", month).
|
||||||
|
Delete()
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|||||||
@@ -17,3 +17,12 @@ func TestServerClientBrowserMonthlyStatDAO_IncreaseMonthlyCount(t *testing.T) {
|
|||||||
}
|
}
|
||||||
t.Log("ok")
|
t.Log("ok")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestServerClientBrowserMonthlyStatDAO_Clean(t *testing.T) {
|
||||||
|
var dao = NewServerClientBrowserMonthlyStatDAO()
|
||||||
|
err := dao.Clean(nil)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
t.Log("ok")
|
||||||
|
}
|
||||||
|
|||||||
@@ -2,12 +2,31 @@ package stats
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/TeaOSLab/EdgeAPI/internal/errors"
|
"github.com/TeaOSLab/EdgeAPI/internal/errors"
|
||||||
|
"github.com/TeaOSLab/EdgeAPI/internal/remotelogs"
|
||||||
_ "github.com/go-sql-driver/mysql"
|
_ "github.com/go-sql-driver/mysql"
|
||||||
"github.com/iwind/TeaGo/Tea"
|
"github.com/iwind/TeaGo/Tea"
|
||||||
"github.com/iwind/TeaGo/dbs"
|
"github.com/iwind/TeaGo/dbs"
|
||||||
"github.com/iwind/TeaGo/maps"
|
"github.com/iwind/TeaGo/maps"
|
||||||
|
"github.com/iwind/TeaGo/rands"
|
||||||
|
timeutil "github.com/iwind/TeaGo/utils/time"
|
||||||
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
dbs.OnReadyDone(func() {
|
||||||
|
// 清理数据任务
|
||||||
|
var ticker = time.NewTicker(time.Duration(rands.Int(24, 48)) * time.Hour)
|
||||||
|
go func() {
|
||||||
|
for range ticker.C {
|
||||||
|
err := SharedServerClientSystemMonthlyStatDAO.Clean(nil)
|
||||||
|
if err != nil {
|
||||||
|
remotelogs.Error("ServerClientSystemMonthlyStatDAO", "clean expired data failed: "+err.Error())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
type ServerClientSystemMonthlyStatDAO dbs.DAO
|
type ServerClientSystemMonthlyStatDAO dbs.DAO
|
||||||
|
|
||||||
func NewServerClientSystemMonthlyStatDAO() *ServerClientSystemMonthlyStatDAO {
|
func NewServerClientSystemMonthlyStatDAO() *ServerClientSystemMonthlyStatDAO {
|
||||||
@@ -29,7 +48,7 @@ func init() {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
// 增加数量
|
// IncreaseMonthlyCount 增加数量
|
||||||
func (this *ServerClientSystemMonthlyStatDAO) IncreaseMonthlyCount(tx *dbs.Tx, serverId int64, systemId int64, version string, month string, count int64) error {
|
func (this *ServerClientSystemMonthlyStatDAO) IncreaseMonthlyCount(tx *dbs.Tx, serverId int64, systemId int64, version string, month string, count int64) error {
|
||||||
if len(month) != 6 {
|
if len(month) != 6 {
|
||||||
return errors.New("invalid month '" + month + "'")
|
return errors.New("invalid month '" + month + "'")
|
||||||
@@ -51,7 +70,7 @@ func (this *ServerClientSystemMonthlyStatDAO) IncreaseMonthlyCount(tx *dbs.Tx, s
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// 查找单页数据
|
// ListStats 查找单页数据
|
||||||
func (this *ServerClientSystemMonthlyStatDAO) ListStats(tx *dbs.Tx, serverId int64, month string, offset int64, size int64) (result []*ServerClientSystemMonthlyStat, err error) {
|
func (this *ServerClientSystemMonthlyStatDAO) ListStats(tx *dbs.Tx, serverId int64, month string, offset int64, size int64) (result []*ServerClientSystemMonthlyStat, err error) {
|
||||||
query := this.Query(tx).
|
query := this.Query(tx).
|
||||||
Attr("serverId", serverId).
|
Attr("serverId", serverId).
|
||||||
@@ -63,3 +82,13 @@ func (this *ServerClientSystemMonthlyStatDAO) ListStats(tx *dbs.Tx, serverId int
|
|||||||
_, err = query.FindAll()
|
_, err = query.FindAll()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Clean 清理统计数据
|
||||||
|
func (this *ServerClientSystemMonthlyStatDAO) Clean(tx *dbs.Tx) error {
|
||||||
|
// 只保留两个月的
|
||||||
|
var month = timeutil.Format("Ym", time.Now().AddDate(0, -2, 0))
|
||||||
|
_, err := this.Query(tx).
|
||||||
|
Lte("month", month).
|
||||||
|
Delete()
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|||||||
@@ -2,4 +2,14 @@ package stats
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
_ "github.com/go-sql-driver/mysql"
|
_ "github.com/go-sql-driver/mysql"
|
||||||
|
"testing"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
func TestServerClientSystemMonthlyStatDAO_Clean(t *testing.T) {
|
||||||
|
var dao = NewServerClientSystemMonthlyStatDAO()
|
||||||
|
err := dao.Clean(nil)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
t.Log("ok")
|
||||||
|
}
|
||||||
|
|||||||
@@ -21,7 +21,7 @@ func init() {
|
|||||||
var ticker = time.NewTicker(time.Duration(rands.Int(24, 48)) * time.Hour)
|
var ticker = time.NewTicker(time.Duration(rands.Int(24, 48)) * time.Hour)
|
||||||
go func() {
|
go func() {
|
||||||
for range ticker.C {
|
for range ticker.C {
|
||||||
err := SharedServerHTTPFirewallDailyStatDAO.Clean(nil, 60) // 只保留60天
|
err := SharedServerHTTPFirewallDailyStatDAO.Clean(nil, 30) // 只保留N天
|
||||||
if err != nil {
|
if err != nil {
|
||||||
remotelogs.Error("ServerHTTPFirewallDailyStatDAO", "clean expired data failed: "+err.Error())
|
remotelogs.Error("ServerHTTPFirewallDailyStatDAO", "clean expired data failed: "+err.Error())
|
||||||
}
|
}
|
||||||
@@ -133,4 +133,3 @@ func (this *ServerHTTPFirewallDailyStatDAO) Clean(tx *dbs.Tx, days int) error {
|
|||||||
Delete()
|
Delete()
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
145
internal/db/models/stats/server_region_country_daily_stat_dao.go
Normal file
145
internal/db/models/stats/server_region_country_daily_stat_dao.go
Normal file
@@ -0,0 +1,145 @@
|
|||||||
|
package stats
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/TeaOSLab/EdgeAPI/internal/errors"
|
||||||
|
"github.com/TeaOSLab/EdgeAPI/internal/remotelogs"
|
||||||
|
_ "github.com/go-sql-driver/mysql"
|
||||||
|
"github.com/iwind/TeaGo/Tea"
|
||||||
|
"github.com/iwind/TeaGo/dbs"
|
||||||
|
"github.com/iwind/TeaGo/maps"
|
||||||
|
"github.com/iwind/TeaGo/rands"
|
||||||
|
timeutil "github.com/iwind/TeaGo/utils/time"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
dbs.OnReadyDone(func() {
|
||||||
|
// 清理数据任务
|
||||||
|
var ticker = time.NewTicker(time.Duration(rands.Int(24, 48)) * time.Hour)
|
||||||
|
go func() {
|
||||||
|
for range ticker.C {
|
||||||
|
err := SharedServerRegionCountryDailyStatDAO.Clean(nil)
|
||||||
|
if err != nil {
|
||||||
|
remotelogs.Error("ServerRegionCountryDailyStatDAO", "clean expired data failed: "+err.Error())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
type ServerRegionCountryDailyStatDAO dbs.DAO
|
||||||
|
|
||||||
|
func NewServerRegionCountryDailyStatDAO() *ServerRegionCountryDailyStatDAO {
|
||||||
|
return dbs.NewDAO(&ServerRegionCountryDailyStatDAO{
|
||||||
|
DAOObject: dbs.DAOObject{
|
||||||
|
DB: Tea.Env,
|
||||||
|
Table: "edgeServerRegionCountryDailyStats",
|
||||||
|
Model: new(ServerRegionCountryDailyStat),
|
||||||
|
PkName: "id",
|
||||||
|
},
|
||||||
|
}).(*ServerRegionCountryDailyStatDAO)
|
||||||
|
}
|
||||||
|
|
||||||
|
var SharedServerRegionCountryDailyStatDAO *ServerRegionCountryDailyStatDAO
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
dbs.OnReady(func() {
|
||||||
|
SharedServerRegionCountryDailyStatDAO = NewServerRegionCountryDailyStatDAO()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// IncreaseDailyStat 增加统计
|
||||||
|
func (this *ServerRegionCountryDailyStatDAO) IncreaseDailyStat(tx *dbs.Tx, serverId int64, countryId int64, day string, bytes int64, countRequests int64, attackBytes int64, countAttackRequests int64) error {
|
||||||
|
if len(day) != 8 {
|
||||||
|
return errors.New("invalid day '" + day + "'")
|
||||||
|
}
|
||||||
|
err := this.Query(tx).
|
||||||
|
Param("bytes", bytes).
|
||||||
|
Param("countRequests", countRequests).
|
||||||
|
Param("attackBytes", attackBytes).
|
||||||
|
Param("countAttackRequests", countAttackRequests).
|
||||||
|
InsertOrUpdateQuickly(maps.Map{
|
||||||
|
"serverId": serverId,
|
||||||
|
"countryId": countryId,
|
||||||
|
"day": day,
|
||||||
|
"bytes": bytes,
|
||||||
|
"attackBytes": attackBytes,
|
||||||
|
"countRequests": countRequests,
|
||||||
|
"countAttackRequests": countAttackRequests,
|
||||||
|
}, maps.Map{
|
||||||
|
"bytes": dbs.SQL("bytes+:bytes"),
|
||||||
|
"countRequests": dbs.SQL("countRequests+:countRequests"),
|
||||||
|
"attackBytes": dbs.SQL("attackBytes+:attackBytes"),
|
||||||
|
"countAttackRequests": dbs.SQL("countAttackRequests+:countAttackRequests"),
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// ListServerStats 查找单页数据
|
||||||
|
func (this *ServerRegionCountryDailyStatDAO) ListServerStats(tx *dbs.Tx, serverId int64, day string, orderField string, offset int64, size int64) (result []*ServerRegionCountryDailyStat, err error) {
|
||||||
|
query := this.Query(tx).
|
||||||
|
Attr("serverId", serverId).
|
||||||
|
Attr("day", day).
|
||||||
|
Offset(offset).
|
||||||
|
Limit(size).
|
||||||
|
Slice(&result)
|
||||||
|
|
||||||
|
switch orderField {
|
||||||
|
case "bytes":
|
||||||
|
query.Desc("bytes")
|
||||||
|
case "countRequests":
|
||||||
|
query.Desc("countRequests")
|
||||||
|
case "attackBytes":
|
||||||
|
query.Desc("attackBytes")
|
||||||
|
case "countAttackRequests":
|
||||||
|
query.Desc("countAttackRequests")
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err = query.FindAll()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// ListSumStats 查找总体数据
|
||||||
|
func (this *ServerRegionCountryDailyStatDAO) ListSumStats(tx *dbs.Tx, day string, orderField string, offset int64, size int64) (result []*ServerRegionCountryDailyStat, err error) {
|
||||||
|
query := this.Query(tx).
|
||||||
|
Attr("day", day).
|
||||||
|
Result("countryId", "SUM(bytes) AS bytes", "SUM(countRequests) AS countRequests", "SUM(attackBytes) AS attackBytes", "SUM(countAttackRequests) AS countAttackRequests").
|
||||||
|
Group("countryId").
|
||||||
|
Offset(offset).
|
||||||
|
Limit(size).
|
||||||
|
Slice(&result)
|
||||||
|
|
||||||
|
switch orderField {
|
||||||
|
case "bytes":
|
||||||
|
query.Desc("bytes")
|
||||||
|
case "countRequests":
|
||||||
|
query.Desc("countRequests")
|
||||||
|
case "attackBytes":
|
||||||
|
query.Desc("attackBytes")
|
||||||
|
case "countAttackRequests":
|
||||||
|
query.Desc("countAttackRequests")
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err = query.FindAll()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// SumDailyBytes 计算总流量
|
||||||
|
func (this *ServerRegionCountryDailyStatDAO) SumDailyTotalBytes(tx *dbs.Tx, day string) (int64, error) {
|
||||||
|
return this.Query(tx).
|
||||||
|
Attr("day", day).
|
||||||
|
SumInt64("bytes", 0)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Clean 清理统计数据
|
||||||
|
func (this *ServerRegionCountryDailyStatDAO) Clean(tx *dbs.Tx) error {
|
||||||
|
// 只保留7天的
|
||||||
|
var day = timeutil.Format("Ymd", time.Now().AddDate(0, 0, -7))
|
||||||
|
_, err := this.Query(tx).
|
||||||
|
Lte("day", day).
|
||||||
|
Delete()
|
||||||
|
return err
|
||||||
|
}
|
||||||
@@ -0,0 +1,34 @@
|
|||||||
|
package stats
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
_ "github.com/go-sql-driver/mysql"
|
||||||
|
_ "github.com/iwind/TeaGo/bootstrap"
|
||||||
|
"github.com/iwind/TeaGo/dbs"
|
||||||
|
timeutil "github.com/iwind/TeaGo/utils/time"
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestServerRegionCountryDailyStatDAO_IncreaseDailyStat(t *testing.T) {
|
||||||
|
var tx *dbs.Tx
|
||||||
|
err := NewServerRegionCountryDailyStatDAO().IncreaseDailyStat(tx, 1, 3, timeutil.Format("Ymd"), 2, 2, 1, 1)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
t.Log("ok")
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestServerRegionCountryDailyStatDAO_ListSumStats(t *testing.T) {
|
||||||
|
var tx *dbs.Tx
|
||||||
|
stats, err := NewServerRegionCountryDailyStatDAO().ListSumStats(tx, timeutil.Format("Ymd"), "countAttackRequests", 0, 10)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
for _, stat := range stats {
|
||||||
|
statJSON, err := json.Marshal(stat)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
t.Log(string(statJSON))
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,28 @@
|
|||||||
|
package stats
|
||||||
|
|
||||||
|
// ServerRegionCountryDailyStat 服务用户区域分布统计(按天)
|
||||||
|
type ServerRegionCountryDailyStat struct {
|
||||||
|
Id uint64 `field:"id"` // ID
|
||||||
|
ServerId uint32 `field:"serverId"` // 服务ID
|
||||||
|
CountryId uint32 `field:"countryId"` // 国家/区域ID
|
||||||
|
Day string `field:"day"` // 日期YYYYMMDD
|
||||||
|
CountRequests uint64 `field:"countRequests"` // 请求数量
|
||||||
|
CountAttackRequests uint64 `field:"countAttackRequests"` // 攻击数量
|
||||||
|
AttackBytes uint64 `field:"attackBytes"` // 攻击流量
|
||||||
|
Bytes uint64 `field:"bytes"` // 总流量
|
||||||
|
}
|
||||||
|
|
||||||
|
type ServerRegionCountryDailyStatOperator struct {
|
||||||
|
Id interface{} // ID
|
||||||
|
ServerId interface{} // 服务ID
|
||||||
|
CountryId interface{} // 国家/区域ID
|
||||||
|
Day interface{} // 日期YYYYMMDD
|
||||||
|
CountRequests interface{} // 请求数量
|
||||||
|
CountAttackRequests interface{} // 攻击数量
|
||||||
|
AttackBytes interface{} // 攻击流量
|
||||||
|
Bytes interface{} // 总流量
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewServerRegionCountryDailyStatOperator() *ServerRegionCountryDailyStatOperator {
|
||||||
|
return &ServerRegionCountryDailyStatOperator{}
|
||||||
|
}
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
package stats
|
||||||
@@ -6,6 +6,7 @@ import (
|
|||||||
teaconst "github.com/TeaOSLab/EdgeAPI/internal/const"
|
teaconst "github.com/TeaOSLab/EdgeAPI/internal/const"
|
||||||
"github.com/TeaOSLab/EdgeAPI/internal/db/models"
|
"github.com/TeaOSLab/EdgeAPI/internal/db/models"
|
||||||
"github.com/TeaOSLab/EdgeAPI/internal/db/models/authority"
|
"github.com/TeaOSLab/EdgeAPI/internal/db/models/authority"
|
||||||
|
"github.com/TeaOSLab/EdgeAPI/internal/db/models/regions"
|
||||||
"github.com/TeaOSLab/EdgeAPI/internal/db/models/stats"
|
"github.com/TeaOSLab/EdgeAPI/internal/db/models/stats"
|
||||||
"github.com/TeaOSLab/EdgeAPI/internal/errors"
|
"github.com/TeaOSLab/EdgeAPI/internal/errors"
|
||||||
rpcutils "github.com/TeaOSLab/EdgeAPI/internal/rpc/utils"
|
rpcutils "github.com/TeaOSLab/EdgeAPI/internal/rpc/utils"
|
||||||
@@ -735,6 +736,34 @@ func (this *AdminService) ComposeAdminDashboard(ctx context.Context, req *pb.Com
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 流量排行
|
||||||
|
if isPlus {
|
||||||
|
totalBytes, err := stats.SharedServerRegionCountryDailyStatDAO.SumDailyTotalBytes(tx, timeutil.Format("Ymd"))
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if totalBytes > 0 {
|
||||||
|
topCountryStats, err := stats.SharedServerRegionCountryDailyStatDAO.ListSumStats(tx, timeutil.Format("Ymd"), "bytes", 0, 100)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, stat := range topCountryStats {
|
||||||
|
countryName, err := regions.SharedRegionCountryDAO.FindRegionCountryName(tx, int64(stat.CountryId))
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
result.TopCountryStats = append(result.TopCountryStats, &pb.ComposeAdminDashboardResponse_CountryStat{
|
||||||
|
CountryName: countryName,
|
||||||
|
Bytes: int64(stat.Bytes),
|
||||||
|
CountRequests: int64(stat.CountRequests),
|
||||||
|
Percent: float32(stat.Bytes*100) / float32(totalBytes),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// 指标数据
|
// 指标数据
|
||||||
pbCharts, err := this.findMetricDataCharts(tx)
|
pbCharts, err := this.findMetricDataCharts(tx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|||||||
@@ -1358,9 +1358,17 @@ func (this *ServerService) UploadServerHTTPRequestStat(ctx context.Context, req
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if countryId > 0 {
|
if countryId > 0 {
|
||||||
key := fmt.Sprintf("%d@%d@%s", result.ServerId, countryId, month)
|
countryKey := fmt.Sprintf("%d@%d@%s", result.ServerId, countryId, day)
|
||||||
serverStatLocker.Lock()
|
serverStatLocker.Lock()
|
||||||
serverHTTPCountryStatMap[key] += result.Count
|
stat, ok := serverHTTPCountryStatMap[countryKey]
|
||||||
|
if !ok {
|
||||||
|
stat = &TrafficStat{}
|
||||||
|
serverHTTPCountryStatMap[countryKey] = stat
|
||||||
|
}
|
||||||
|
stat.CountRequests += result.CountRequests
|
||||||
|
stat.Bytes += result.Bytes
|
||||||
|
stat.CountAttackRequests += result.CountAttackRequests
|
||||||
|
stat.AttackBytes += result.AttackBytes
|
||||||
serverStatLocker.Unlock()
|
serverStatLocker.Unlock()
|
||||||
|
|
||||||
// 省份
|
// 省份
|
||||||
@@ -1372,7 +1380,7 @@ func (this *ServerService) UploadServerHTTPRequestStat(ctx context.Context, req
|
|||||||
if provinceId > 0 {
|
if provinceId > 0 {
|
||||||
key := fmt.Sprintf("%d@%d@%s", result.ServerId, provinceId, month)
|
key := fmt.Sprintf("%d@%d@%s", result.ServerId, provinceId, month)
|
||||||
serverStatLocker.Lock()
|
serverStatLocker.Lock()
|
||||||
serverHTTPProvinceStatMap[key] += result.Count
|
serverHTTPProvinceStatMap[key] += result.CountRequests
|
||||||
serverStatLocker.Unlock()
|
serverStatLocker.Unlock()
|
||||||
|
|
||||||
// 城市
|
// 城市
|
||||||
@@ -1384,7 +1392,7 @@ func (this *ServerService) UploadServerHTTPRequestStat(ctx context.Context, req
|
|||||||
if cityId > 0 {
|
if cityId > 0 {
|
||||||
key := fmt.Sprintf("%d@%d@%s", result.ServerId, cityId, month)
|
key := fmt.Sprintf("%d@%d@%s", result.ServerId, cityId, month)
|
||||||
serverStatLocker.Lock()
|
serverStatLocker.Lock()
|
||||||
serverHTTPCityStatMap[key] += result.Count
|
serverHTTPCityStatMap[key] += result.CountRequests
|
||||||
serverStatLocker.Unlock()
|
serverStatLocker.Unlock()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ package services
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/TeaOSLab/EdgeAPI/internal/db/models/stats"
|
"github.com/TeaOSLab/EdgeAPI/internal/db/models/stats"
|
||||||
|
"github.com/TeaOSLab/EdgeAPI/internal/errors"
|
||||||
"github.com/TeaOSLab/EdgeAPI/internal/remotelogs"
|
"github.com/TeaOSLab/EdgeAPI/internal/remotelogs"
|
||||||
"github.com/iwind/TeaGo/Tea"
|
"github.com/iwind/TeaGo/Tea"
|
||||||
"github.com/iwind/TeaGo/dbs"
|
"github.com/iwind/TeaGo/dbs"
|
||||||
@@ -12,8 +13,19 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
type TrafficStat struct {
|
||||||
|
Bytes int64
|
||||||
|
CachedBytes int64
|
||||||
|
CountRequests int64
|
||||||
|
CountCachedRequests int64
|
||||||
|
CountAttackRequests int64
|
||||||
|
AttackBytes int64
|
||||||
|
PlanId int64
|
||||||
|
CheckingTrafficLimit bool
|
||||||
|
}
|
||||||
|
|
||||||
// HTTP请求统计缓存队列
|
// HTTP请求统计缓存队列
|
||||||
var serverHTTPCountryStatMap = map[string]int64{} // serverId@countryId@month => count
|
var serverHTTPCountryStatMap = map[string]*TrafficStat{} // serverId@countryId@day => *TrafficStat
|
||||||
var serverHTTPProvinceStatMap = map[string]int64{} // serverId@provinceId@month => count
|
var serverHTTPProvinceStatMap = map[string]int64{} // serverId@provinceId@month => count
|
||||||
var serverHTTPCityStatMap = map[string]int64{} // serverId@cityId@month => count
|
var serverHTTPCityStatMap = map[string]int64{} // serverId@cityId@month => count
|
||||||
var serverHTTPProviderStatMap = map[string]int64{} // serverId@providerId@month => count
|
var serverHTTPProviderStatMap = map[string]int64{} // serverId@providerId@month => count
|
||||||
@@ -49,14 +61,26 @@ func (this *ServerService) dumpServerHTTPStats() error {
|
|||||||
{
|
{
|
||||||
serverStatLocker.Lock()
|
serverStatLocker.Lock()
|
||||||
m := serverHTTPCountryStatMap
|
m := serverHTTPCountryStatMap
|
||||||
serverHTTPCountryStatMap = map[string]int64{}
|
serverHTTPCountryStatMap = map[string]*TrafficStat{}
|
||||||
serverStatLocker.Unlock()
|
serverStatLocker.Unlock()
|
||||||
for k, count := range m {
|
for k, stat := range m {
|
||||||
pieces := strings.Split(k, "@")
|
pieces := strings.Split(k, "@")
|
||||||
if len(pieces) != 3 {
|
if len(pieces) != 3 {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
err := stats.SharedServerRegionCountryMonthlyStatDAO.IncreaseMonthlyCount(nil, types.Int64(pieces[0]), types.Int64(pieces[1]), pieces[2], count)
|
|
||||||
|
// Monthly
|
||||||
|
var day = pieces[2]
|
||||||
|
if len(day) != 8 {
|
||||||
|
return errors.New("invalid day '" + day + "'")
|
||||||
|
}
|
||||||
|
err := stats.SharedServerRegionCountryMonthlyStatDAO.IncreaseMonthlyCount(nil, types.Int64(pieces[0]), types.Int64(pieces[1]), day[:6], stat.CountRequests)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Daily
|
||||||
|
err = stats.SharedServerRegionCountryDailyStatDAO.IncreaseDailyStat(nil, types.Int64(pieces[0]), types.Int64(pieces[1]), day, stat.Bytes, stat.CountRequests, stat.AttackBytes, stat.CountAttackRequests)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -87,12 +111,12 @@ func (this *ServerService) dumpServerHTTPStats() error {
|
|||||||
m := serverHTTPCityStatMap
|
m := serverHTTPCityStatMap
|
||||||
serverHTTPCityStatMap = map[string]int64{}
|
serverHTTPCityStatMap = map[string]int64{}
|
||||||
serverStatLocker.Unlock()
|
serverStatLocker.Unlock()
|
||||||
for k, count := range m {
|
for k, countRequests := range m {
|
||||||
pieces := strings.Split(k, "@")
|
pieces := strings.Split(k, "@")
|
||||||
if len(pieces) != 3 {
|
if len(pieces) != 3 {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
err := stats.SharedServerRegionCityMonthlyStatDAO.IncreaseMonthlyCount(nil, types.Int64(pieces[0]), types.Int64(pieces[1]), pieces[2], count)
|
err := stats.SharedServerRegionCityMonthlyStatDAO.IncreaseMonthlyCount(nil, types.Int64(pieces[0]), types.Int64(pieces[1]), pieces[2], countRequests)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -172,13 +196,12 @@ func (this *ServerService) dumpServerHTTPStats() error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 按小时统计
|
// 按小时统计
|
||||||
err = stats.SharedServerHTTPFirewallHourlyStatDAO.IncreaseHourlyCount(nil, types.Int64(pieces[0]), types.Int64(pieces[1]), pieces[2], pieces[3] + timeutil.Format("H"), count)
|
err = stats.SharedServerHTTPFirewallHourlyStatDAO.IncreaseHourlyCount(nil, types.Int64(pieces[0]), types.Int64(pieces[1]), pieces[2], pieces[3]+timeutil.Format("H"), count)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user