mirror of
				https://github.com/TeaOSLab/EdgeAPI.git
				synced 2025-11-04 07:50:25 +08:00 
			
		
		
		
	国家/地区统计时上传流量、攻击量等信息/多个统计增加自动清理程序
This commit is contained in:
		@@ -16,7 +16,8 @@ const (
 | 
			
		||||
	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
 | 
			
		||||
 | 
			
		||||
@@ -39,7 +40,7 @@ func init() {
 | 
			
		||||
	})
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// 启用条目
 | 
			
		||||
// EnableRegionCountry 启用条目
 | 
			
		||||
func (this *RegionCountryDAO) EnableRegionCountry(tx *dbs.Tx, id uint32) error {
 | 
			
		||||
	_, err := this.Query(tx).
 | 
			
		||||
		Pk(id).
 | 
			
		||||
@@ -48,7 +49,7 @@ func (this *RegionCountryDAO) EnableRegionCountry(tx *dbs.Tx, id uint32) error {
 | 
			
		||||
	return err
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// 禁用条目
 | 
			
		||||
// DisableRegionCountry 禁用条目
 | 
			
		||||
func (this *RegionCountryDAO) DisableRegionCountry(tx *dbs.Tx, id int64) error {
 | 
			
		||||
	_, err := this.Query(tx).
 | 
			
		||||
		Pk(id).
 | 
			
		||||
@@ -57,7 +58,7 @@ func (this *RegionCountryDAO) DisableRegionCountry(tx *dbs.Tx, id int64) error {
 | 
			
		||||
	return err
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// 查找启用中的条目
 | 
			
		||||
// FindEnabledRegionCountry 查找启用中的条目
 | 
			
		||||
func (this *RegionCountryDAO) FindEnabledRegionCountry(tx *dbs.Tx, id int64) (*RegionCountry, error) {
 | 
			
		||||
	result, err := this.Query(tx).
 | 
			
		||||
		Pk(id).
 | 
			
		||||
@@ -69,15 +70,29 @@ func (this *RegionCountryDAO) FindEnabledRegionCountry(tx *dbs.Tx, id int64) (*R
 | 
			
		||||
	return result.(*RegionCountry), err
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// 根据主键查找名称
 | 
			
		||||
// FindRegionCountryName 根据主键查找名称
 | 
			
		||||
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).
 | 
			
		||||
		Result("name").
 | 
			
		||||
		FindStringCol("")
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return "", err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
// 根据数据ID查找国家
 | 
			
		||||
	regionCountryIdAndNameCacheMap[id] = name
 | 
			
		||||
	return name, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// FindCountryIdWithDataId 根据数据ID查找国家
 | 
			
		||||
func (this *RegionCountryDAO) FindCountryIdWithDataId(tx *dbs.Tx, dataId string) (int64, error) {
 | 
			
		||||
	return this.Query(tx).
 | 
			
		||||
		Attr("dataId", dataId).
 | 
			
		||||
@@ -85,7 +100,7 @@ func (this *RegionCountryDAO) FindCountryIdWithDataId(tx *dbs.Tx, dataId string)
 | 
			
		||||
		FindInt64Col(0)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// 根据国家名查找国家ID
 | 
			
		||||
// FindCountryIdWithName 根据国家名查找国家ID
 | 
			
		||||
func (this *RegionCountryDAO) FindCountryIdWithName(tx *dbs.Tx, countryName string) (int64, error) {
 | 
			
		||||
	return this.Query(tx).
 | 
			
		||||
		Where("JSON_CONTAINS(codes, :countryName)").
 | 
			
		||||
@@ -94,7 +109,7 @@ func (this *RegionCountryDAO) FindCountryIdWithName(tx *dbs.Tx, countryName stri
 | 
			
		||||
		FindInt64Col(0)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// 根据国家名查找国家ID,并可使用缓存
 | 
			
		||||
// FindCountryIdWithNameCacheable 根据国家名查找国家ID,并可使用缓存
 | 
			
		||||
func (this *RegionCountryDAO) FindCountryIdWithNameCacheable(tx *dbs.Tx, countryName string) (int64, error) {
 | 
			
		||||
	SharedCacheLocker.RLock()
 | 
			
		||||
	provinceId, ok := regionCountryNameAndIdCacheMap[countryName]
 | 
			
		||||
@@ -116,7 +131,7 @@ func (this *RegionCountryDAO) FindCountryIdWithNameCacheable(tx *dbs.Tx, country
 | 
			
		||||
	return countryId, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// 根据数据ID创建国家
 | 
			
		||||
// CreateCountry 根据数据ID创建国家
 | 
			
		||||
func (this *RegionCountryDAO) CreateCountry(tx *dbs.Tx, name string, dataId string) (int64, error) {
 | 
			
		||||
	op := NewRegionCountryOperator()
 | 
			
		||||
	op.Name = name
 | 
			
		||||
@@ -145,7 +160,7 @@ func (this *RegionCountryDAO) CreateCountry(tx *dbs.Tx, name string, dataId stri
 | 
			
		||||
	return types.Int64(op.Id), nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// 查找所有可用的国家
 | 
			
		||||
// FindAllEnabledCountriesOrderByPinyin 查找所有可用的国家
 | 
			
		||||
func (this *RegionCountryDAO) FindAllEnabledCountriesOrderByPinyin(tx *dbs.Tx) (result []*RegionCountry, err error) {
 | 
			
		||||
	_, err = this.Query(tx).
 | 
			
		||||
		State(RegionCountryStateEnabled).
 | 
			
		||||
 
 | 
			
		||||
@@ -2,12 +2,31 @@ 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 := SharedServerClientBrowserMonthlyStatDAO.Clean(nil)
 | 
			
		||||
				if err != nil {
 | 
			
		||||
					remotelogs.Error("ServerClientBrowserMonthlyStatDAO", "clean expired data failed: "+err.Error())
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
		}()
 | 
			
		||||
	})
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type ServerClientBrowserMonthlyStatDAO dbs.DAO
 | 
			
		||||
 | 
			
		||||
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 {
 | 
			
		||||
	if len(month) != 6 {
 | 
			
		||||
		return errors.New("invalid month '" + month + "'")
 | 
			
		||||
@@ -51,7 +70,7 @@ func (this *ServerClientBrowserMonthlyStatDAO) IncreaseMonthlyCount(tx *dbs.Tx,
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// 查找单页数据
 | 
			
		||||
// ListStats 查找单页数据
 | 
			
		||||
func (this *ServerClientBrowserMonthlyStatDAO) ListStats(tx *dbs.Tx, serverId int64, month string, offset int64, size int64) (result []*ServerClientBrowserMonthlyStat, err error) {
 | 
			
		||||
	query := this.Query(tx).
 | 
			
		||||
		Attr("serverId", serverId).
 | 
			
		||||
@@ -63,3 +82,13 @@ func (this *ServerClientBrowserMonthlyStatDAO) ListStats(tx *dbs.Tx, serverId in
 | 
			
		||||
	_, err = query.FindAll()
 | 
			
		||||
	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")
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
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 (
 | 
			
		||||
	"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 := SharedServerClientSystemMonthlyStatDAO.Clean(nil)
 | 
			
		||||
				if err != nil {
 | 
			
		||||
					remotelogs.Error("ServerClientSystemMonthlyStatDAO", "clean expired data failed: "+err.Error())
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
		}()
 | 
			
		||||
	})
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type ServerClientSystemMonthlyStatDAO dbs.DAO
 | 
			
		||||
 | 
			
		||||
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 {
 | 
			
		||||
	if len(month) != 6 {
 | 
			
		||||
		return errors.New("invalid month '" + month + "'")
 | 
			
		||||
@@ -51,7 +70,7 @@ func (this *ServerClientSystemMonthlyStatDAO) IncreaseMonthlyCount(tx *dbs.Tx, s
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// 查找单页数据
 | 
			
		||||
// ListStats 查找单页数据
 | 
			
		||||
func (this *ServerClientSystemMonthlyStatDAO) ListStats(tx *dbs.Tx, serverId int64, month string, offset int64, size int64) (result []*ServerClientSystemMonthlyStat, err error) {
 | 
			
		||||
	query := this.Query(tx).
 | 
			
		||||
		Attr("serverId", serverId).
 | 
			
		||||
@@ -63,3 +82,13 @@ func (this *ServerClientSystemMonthlyStatDAO) ListStats(tx *dbs.Tx, serverId int
 | 
			
		||||
	_, err = query.FindAll()
 | 
			
		||||
	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 (
 | 
			
		||||
	_ "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)
 | 
			
		||||
		go func() {
 | 
			
		||||
			for range ticker.C {
 | 
			
		||||
				err := SharedServerHTTPFirewallDailyStatDAO.Clean(nil, 60) // 只保留60天
 | 
			
		||||
				err := SharedServerHTTPFirewallDailyStatDAO.Clean(nil, 30) // 只保留N天
 | 
			
		||||
				if err != nil {
 | 
			
		||||
					remotelogs.Error("ServerHTTPFirewallDailyStatDAO", "clean expired data failed: "+err.Error())
 | 
			
		||||
				}
 | 
			
		||||
@@ -133,4 +133,3 @@ func (this *ServerHTTPFirewallDailyStatDAO) Clean(tx *dbs.Tx, days int) error {
 | 
			
		||||
		Delete()
 | 
			
		||||
	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"
 | 
			
		||||
	"github.com/TeaOSLab/EdgeAPI/internal/db/models"
 | 
			
		||||
	"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/errors"
 | 
			
		||||
	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)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
 
 | 
			
		||||
@@ -1358,9 +1358,17 @@ func (this *ServerService) UploadServerHTTPRequestStat(ctx context.Context, req
 | 
			
		||||
					return err
 | 
			
		||||
				}
 | 
			
		||||
				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()
 | 
			
		||||
					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()
 | 
			
		||||
 | 
			
		||||
					// 省份
 | 
			
		||||
@@ -1372,7 +1380,7 @@ func (this *ServerService) UploadServerHTTPRequestStat(ctx context.Context, req
 | 
			
		||||
						if provinceId > 0 {
 | 
			
		||||
							key := fmt.Sprintf("%d@%d@%s", result.ServerId, provinceId, month)
 | 
			
		||||
							serverStatLocker.Lock()
 | 
			
		||||
							serverHTTPProvinceStatMap[key] += result.Count
 | 
			
		||||
							serverHTTPProvinceStatMap[key] += result.CountRequests
 | 
			
		||||
							serverStatLocker.Unlock()
 | 
			
		||||
 | 
			
		||||
							// 城市
 | 
			
		||||
@@ -1384,7 +1392,7 @@ func (this *ServerService) UploadServerHTTPRequestStat(ctx context.Context, req
 | 
			
		||||
								if cityId > 0 {
 | 
			
		||||
									key := fmt.Sprintf("%d@%d@%s", result.ServerId, cityId, month)
 | 
			
		||||
									serverStatLocker.Lock()
 | 
			
		||||
									serverHTTPCityStatMap[key] += result.Count
 | 
			
		||||
									serverHTTPCityStatMap[key] += result.CountRequests
 | 
			
		||||
									serverStatLocker.Unlock()
 | 
			
		||||
								}
 | 
			
		||||
							}
 | 
			
		||||
 
 | 
			
		||||
@@ -2,6 +2,7 @@ package services
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"github.com/TeaOSLab/EdgeAPI/internal/db/models/stats"
 | 
			
		||||
	"github.com/TeaOSLab/EdgeAPI/internal/errors"
 | 
			
		||||
	"github.com/TeaOSLab/EdgeAPI/internal/remotelogs"
 | 
			
		||||
	"github.com/iwind/TeaGo/Tea"
 | 
			
		||||
	"github.com/iwind/TeaGo/dbs"
 | 
			
		||||
@@ -12,8 +13,19 @@ import (
 | 
			
		||||
	"time"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
type TrafficStat struct {
 | 
			
		||||
	Bytes                int64
 | 
			
		||||
	CachedBytes          int64
 | 
			
		||||
	CountRequests        int64
 | 
			
		||||
	CountCachedRequests  int64
 | 
			
		||||
	CountAttackRequests  int64
 | 
			
		||||
	AttackBytes          int64
 | 
			
		||||
	PlanId               int64
 | 
			
		||||
	CheckingTrafficLimit bool
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// 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 serverHTTPCityStatMap = map[string]int64{}              // serverId@cityId@month => count
 | 
			
		||||
var serverHTTPProviderStatMap = map[string]int64{}          // serverId@providerId@month => count
 | 
			
		||||
@@ -49,14 +61,26 @@ func (this *ServerService) dumpServerHTTPStats() error {
 | 
			
		||||
	{
 | 
			
		||||
		serverStatLocker.Lock()
 | 
			
		||||
		m := serverHTTPCountryStatMap
 | 
			
		||||
		serverHTTPCountryStatMap = map[string]int64{}
 | 
			
		||||
		serverHTTPCountryStatMap = map[string]*TrafficStat{}
 | 
			
		||||
		serverStatLocker.Unlock()
 | 
			
		||||
		for k, count := range m {
 | 
			
		||||
		for k, stat := range m {
 | 
			
		||||
			pieces := strings.Split(k, "@")
 | 
			
		||||
			if len(pieces) != 3 {
 | 
			
		||||
				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 {
 | 
			
		||||
				return err
 | 
			
		||||
			}
 | 
			
		||||
@@ -87,12 +111,12 @@ func (this *ServerService) dumpServerHTTPStats() error {
 | 
			
		||||
		m := serverHTTPCityStatMap
 | 
			
		||||
		serverHTTPCityStatMap = map[string]int64{}
 | 
			
		||||
		serverStatLocker.Unlock()
 | 
			
		||||
		for k, count := range m {
 | 
			
		||||
		for k, countRequests := range m {
 | 
			
		||||
			pieces := strings.Split(k, "@")
 | 
			
		||||
			if len(pieces) != 3 {
 | 
			
		||||
				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 {
 | 
			
		||||
				return err
 | 
			
		||||
			}
 | 
			
		||||
@@ -179,6 +203,5 @@ func (this *ServerService) dumpServerHTTPStats() error {
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user