diff --git a/internal/db/models/regions/region_country_dao.go b/internal/db/models/regions/region_country_dao.go index f43d7954..510ca95e 100644 --- a/internal/db/models/regions/region_country_dao.go +++ b/internal/db/models/regions/region_country_dao.go @@ -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 + } + + regionCountryIdAndNameCacheMap[id] = name + return name, nil } -// 根据数据ID查找国家 +// 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). diff --git a/internal/db/models/stats/server_client_browser_monthly_stat_dao.go b/internal/db/models/stats/server_client_browser_monthly_stat_dao.go index 52bf2a55..2261bc13 100644 --- a/internal/db/models/stats/server_client_browser_monthly_stat_dao.go +++ b/internal/db/models/stats/server_client_browser_monthly_stat_dao.go @@ -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 +} diff --git a/internal/db/models/stats/server_client_browser_monthly_stat_dao_test.go b/internal/db/models/stats/server_client_browser_monthly_stat_dao_test.go index c8074623..d321961f 100644 --- a/internal/db/models/stats/server_client_browser_monthly_stat_dao_test.go +++ b/internal/db/models/stats/server_client_browser_monthly_stat_dao_test.go @@ -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") +} diff --git a/internal/db/models/stats/server_client_system_monthly_stat_dao.go b/internal/db/models/stats/server_client_system_monthly_stat_dao.go index e4b7ae2e..dea41230 100644 --- a/internal/db/models/stats/server_client_system_monthly_stat_dao.go +++ b/internal/db/models/stats/server_client_system_monthly_stat_dao.go @@ -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 +} diff --git a/internal/db/models/stats/server_client_system_monthly_stat_dao_test.go b/internal/db/models/stats/server_client_system_monthly_stat_dao_test.go index 6b0462b3..f9820182 100644 --- a/internal/db/models/stats/server_client_system_monthly_stat_dao_test.go +++ b/internal/db/models/stats/server_client_system_monthly_stat_dao_test.go @@ -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") +} diff --git a/internal/db/models/stats/server_http_firewall_daily_stat_dao.go b/internal/db/models/stats/server_http_firewall_daily_stat_dao.go index a610dcf3..12900983 100644 --- a/internal/db/models/stats/server_http_firewall_daily_stat_dao.go +++ b/internal/db/models/stats/server_http_firewall_daily_stat_dao.go @@ -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 } - diff --git a/internal/db/models/stats/server_region_country_daily_stat_dao.go b/internal/db/models/stats/server_region_country_daily_stat_dao.go new file mode 100644 index 00000000..94ce656c --- /dev/null +++ b/internal/db/models/stats/server_region_country_daily_stat_dao.go @@ -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 +} diff --git a/internal/db/models/stats/server_region_country_daily_stat_dao_test.go b/internal/db/models/stats/server_region_country_daily_stat_dao_test.go new file mode 100644 index 00000000..38d304ac --- /dev/null +++ b/internal/db/models/stats/server_region_country_daily_stat_dao_test.go @@ -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)) + } +} diff --git a/internal/db/models/stats/server_region_country_daily_stat_model.go b/internal/db/models/stats/server_region_country_daily_stat_model.go new file mode 100644 index 00000000..17ea766a --- /dev/null +++ b/internal/db/models/stats/server_region_country_daily_stat_model.go @@ -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{} +} diff --git a/internal/db/models/stats/server_region_country_daily_stat_model_ext.go b/internal/db/models/stats/server_region_country_daily_stat_model_ext.go new file mode 100644 index 00000000..43b4fd56 --- /dev/null +++ b/internal/db/models/stats/server_region_country_daily_stat_model_ext.go @@ -0,0 +1 @@ +package stats diff --git a/internal/rpc/services/service_admin.go b/internal/rpc/services/service_admin.go index 343a376c..b323ba0c 100644 --- a/internal/rpc/services/service_admin.go +++ b/internal/rpc/services/service_admin.go @@ -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 { diff --git a/internal/rpc/services/service_server.go b/internal/rpc/services/service_server.go index 179053cf..59f5cca4 100644 --- a/internal/rpc/services/service_server.go +++ b/internal/rpc/services/service_server.go @@ -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() } } diff --git a/internal/rpc/services/service_server_.go b/internal/rpc/services/service_server_.go index 66049065..053413b4 100644 --- a/internal/rpc/services/service_server_.go +++ b/internal/rpc/services/service_server_.go @@ -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 } @@ -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 { return err } } } - return nil }