mirror of
https://github.com/TeaOSLab/EdgeAPI.git
synced 2025-11-05 01:20:25 +08:00
实现集群看板
This commit is contained in:
@@ -379,6 +379,14 @@ func (this *NSNodeDAO) ComposeNodeConfig(tx *dbs.Tx, nodeId int64) (*dnsconfigs.
|
|||||||
return config, nil
|
return config, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// FindNodeClusterId 获取节点的集群ID
|
||||||
|
func (this *NSNodeDAO) FindNodeClusterId(tx *dbs.Tx, nodeId int64) (int64, error) {
|
||||||
|
return this.Query(tx).
|
||||||
|
Pk(nodeId).
|
||||||
|
Result("clusterId").
|
||||||
|
FindInt64Col(0)
|
||||||
|
}
|
||||||
|
|
||||||
// NotifyUpdate 通知更新
|
// NotifyUpdate 通知更新
|
||||||
func (this *NSNodeDAO) NotifyUpdate(tx *dbs.Tx, nodeId int64) error {
|
func (this *NSNodeDAO) NotifyUpdate(tx *dbs.Tx, nodeId int64) error {
|
||||||
// TODO 先什么都不做
|
// TODO 先什么都不做
|
||||||
|
|||||||
@@ -33,13 +33,14 @@ func init() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// CreateValue 创建值
|
// CreateValue 创建值
|
||||||
func (this *NodeValueDAO) CreateValue(tx *dbs.Tx, role nodeconfigs.NodeRole, nodeId int64, item string, valueJSON []byte, createdAt int64) error {
|
func (this *NodeValueDAO) CreateValue(tx *dbs.Tx, clusterId int64, role nodeconfigs.NodeRole, nodeId int64, item string, valueJSON []byte, createdAt int64) error {
|
||||||
day := timeutil.FormatTime("Ymd", createdAt)
|
day := timeutil.FormatTime("Ymd", createdAt)
|
||||||
hour := timeutil.FormatTime("YmdH", createdAt)
|
hour := timeutil.FormatTime("YmdH", createdAt)
|
||||||
minute := timeutil.FormatTime("YmdHi", createdAt)
|
minute := timeutil.FormatTime("YmdHi", createdAt)
|
||||||
|
|
||||||
return this.Query(tx).
|
return this.Query(tx).
|
||||||
InsertOrUpdateQuickly(maps.Map{
|
InsertOrUpdateQuickly(maps.Map{
|
||||||
|
"clusterId": clusterId,
|
||||||
"role": role,
|
"role": role,
|
||||||
"nodeId": nodeId,
|
"nodeId": nodeId,
|
||||||
"item": item,
|
"item": item,
|
||||||
@@ -90,6 +91,31 @@ func (this *NodeValueDAO) ListValues(tx *dbs.Tx, role string, nodeId int64, item
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ListValuesWithClusterId 列出集群最近的的平均数据
|
||||||
|
func (this *NodeValueDAO) ListValuesWithClusterId(tx *dbs.Tx, clusterId int64, role string, item string, key string, timeRange nodeconfigs.NodeValueRange) (result []*NodeValue, err error) {
|
||||||
|
query := this.Query(tx).
|
||||||
|
Attr("role", role).
|
||||||
|
Attr("clusterId", clusterId).
|
||||||
|
Attr("item", item).
|
||||||
|
Result("AVG(JSON_EXTRACT(value, '$." + key + "')) AS value, MIN(createdAt) AS createdAt")
|
||||||
|
|
||||||
|
switch timeRange {
|
||||||
|
// TODO 支持更多的时间范围
|
||||||
|
case nodeconfigs.NodeValueRangeMinute:
|
||||||
|
fromMinute := timeutil.FormatTime("YmdHi", time.Now().Unix()-3600) // 一个小时之前的
|
||||||
|
query.Gte("minute", fromMinute)
|
||||||
|
query.Result("minute")
|
||||||
|
query.Group("minute")
|
||||||
|
default:
|
||||||
|
err = errors.New("invalid 'range' value: '" + timeRange + "'")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err = query.Slice(&result).
|
||||||
|
FindAll()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
// SumValues 计算某项参数值
|
// SumValues 计算某项参数值
|
||||||
func (this *NodeValueDAO) SumValues(tx *dbs.Tx, role string, nodeId int64, item string, param string, method nodeconfigs.NodeValueSumMethod, duration int32, durationUnit nodeconfigs.NodeValueDurationUnit) (float64, error) {
|
func (this *NodeValueDAO) SumValues(tx *dbs.Tx, role string, nodeId int64, item string, param string, method nodeconfigs.NodeValueSumMethod, duration int32, durationUnit nodeconfigs.NodeValueDurationUnit) (float64, error) {
|
||||||
if duration <= 0 {
|
if duration <= 0 {
|
||||||
@@ -110,10 +136,10 @@ func (this *NodeValueDAO) SumValues(tx *dbs.Tx, role string, nodeId int64, item
|
|||||||
}
|
}
|
||||||
switch durationUnit {
|
switch durationUnit {
|
||||||
case nodeconfigs.NodeValueDurationUnitMinute:
|
case nodeconfigs.NodeValueDurationUnitMinute:
|
||||||
fromMinute := timeutil.FormatTime("YmdHi", time.Now().Unix()-int64(duration * 60))
|
fromMinute := timeutil.FormatTime("YmdHi", time.Now().Unix()-int64(duration*60))
|
||||||
query.Gte("minute", fromMinute)
|
query.Gte("minute", fromMinute)
|
||||||
default:
|
default:
|
||||||
fromMinute := timeutil.FormatTime("YmdHi", time.Now().Unix()-int64(duration * 60))
|
fromMinute := timeutil.FormatTime("YmdHi", time.Now().Unix()-int64(duration*60))
|
||||||
query.Gte("minute", fromMinute)
|
query.Gte("minute", fromMinute)
|
||||||
}
|
}
|
||||||
return query.FindFloat64Col(0)
|
return query.FindFloat64Col(0)
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ package models
|
|||||||
// NodeValue 节点监控数据
|
// NodeValue 节点监控数据
|
||||||
type NodeValue struct {
|
type NodeValue struct {
|
||||||
Id uint64 `field:"id"` // ID
|
Id uint64 `field:"id"` // ID
|
||||||
|
ClusterId uint32 `field:"clusterId"` // 集群ID
|
||||||
NodeId uint32 `field:"nodeId"` // 节点ID
|
NodeId uint32 `field:"nodeId"` // 节点ID
|
||||||
Role string `field:"role"` // 节点角色
|
Role string `field:"role"` // 节点角色
|
||||||
Item string `field:"item"` // 监控项
|
Item string `field:"item"` // 监控项
|
||||||
@@ -15,6 +16,7 @@ type NodeValue struct {
|
|||||||
|
|
||||||
type NodeValueOperator struct {
|
type NodeValueOperator struct {
|
||||||
Id interface{} // ID
|
Id interface{} // ID
|
||||||
|
ClusterId interface{} // 集群ID
|
||||||
NodeId interface{} // 节点ID
|
NodeId interface{} // 节点ID
|
||||||
Role interface{} // 节点角色
|
Role interface{} // 节点角色
|
||||||
Item interface{} // 监控项
|
Item interface{} // 监控项
|
||||||
|
|||||||
@@ -5,13 +5,30 @@ import (
|
|||||||
_ "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/logs"
|
||||||
"github.com/iwind/TeaGo/maps"
|
"github.com/iwind/TeaGo/maps"
|
||||||
timeutil "github.com/iwind/TeaGo/utils/time"
|
timeutil "github.com/iwind/TeaGo/utils/time"
|
||||||
"regexp"
|
"regexp"
|
||||||
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
type ServerDailyStatDAO dbs.DAO
|
type ServerDailyStatDAO dbs.DAO
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
dbs.OnReadyDone(func() {
|
||||||
|
// 清理数据任务
|
||||||
|
var ticker = time.NewTicker(24 * time.Hour)
|
||||||
|
go func() {
|
||||||
|
for range ticker.C {
|
||||||
|
err := SharedServerDailyStatDAO.Clean(nil, 60) // 只保留60天
|
||||||
|
if err != nil {
|
||||||
|
logs.Println("ServerDailyStatDAO", "clean expired data failed: "+err.Error())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
func NewServerDailyStatDAO() *ServerDailyStatDAO {
|
func NewServerDailyStatDAO() *ServerDailyStatDAO {
|
||||||
return dbs.NewDAO(&ServerDailyStatDAO{
|
return dbs.NewDAO(&ServerDailyStatDAO{
|
||||||
DAOObject: dbs.DAOObject{
|
DAOObject: dbs.DAOObject{
|
||||||
@@ -35,6 +52,7 @@ func init() {
|
|||||||
func (this *ServerDailyStatDAO) SaveStats(tx *dbs.Tx, stats []*pb.ServerDailyStat) error {
|
func (this *ServerDailyStatDAO) SaveStats(tx *dbs.Tx, stats []*pb.ServerDailyStat) error {
|
||||||
for _, stat := range stats {
|
for _, stat := range stats {
|
||||||
day := timeutil.FormatTime("Ymd", stat.CreatedAt)
|
day := timeutil.FormatTime("Ymd", stat.CreatedAt)
|
||||||
|
hour := timeutil.FormatTime("YmdH", stat.CreatedAt)
|
||||||
timeFrom := timeutil.FormatTime("His", stat.CreatedAt)
|
timeFrom := timeutil.FormatTime("His", stat.CreatedAt)
|
||||||
timeTo := timeutil.FormatTime("His", stat.CreatedAt+5*60-1) // 5分钟
|
timeTo := timeutil.FormatTime("His", stat.CreatedAt+5*60-1) // 5分钟
|
||||||
|
|
||||||
@@ -51,6 +69,7 @@ func (this *ServerDailyStatDAO) SaveStats(tx *dbs.Tx, stats []*pb.ServerDailySta
|
|||||||
"countRequests": dbs.SQL("countRequests+:countRequests"),
|
"countRequests": dbs.SQL("countRequests+:countRequests"),
|
||||||
"countCachedRequests": dbs.SQL("countCachedRequests+:countCachedRequests"),
|
"countCachedRequests": dbs.SQL("countCachedRequests+:countCachedRequests"),
|
||||||
"day": day,
|
"day": day,
|
||||||
|
"hour": hour,
|
||||||
"timeFrom": timeFrom,
|
"timeFrom": timeFrom,
|
||||||
"timeTo": timeTo,
|
"timeTo": timeTo,
|
||||||
}, maps.Map{
|
}, maps.Map{
|
||||||
@@ -217,3 +236,12 @@ func (this *ServerDailyStatDAO) SumDailyStat(tx *dbs.Tx, serverId int64, day str
|
|||||||
stat.CountCachedRequests = one.GetInt64("countCachedRequests")
|
stat.CountCachedRequests = one.GetInt64("countCachedRequests")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Clean 清理历史数据
|
||||||
|
func (this *ServerDailyStatDAO) Clean(tx *dbs.Tx, days int) error {
|
||||||
|
var day = timeutil.Format("Ymd", time.Now().AddDate(0, 0, -days))
|
||||||
|
_, err := this.Query(tx).
|
||||||
|
Lt("day", day).
|
||||||
|
Delete()
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ type ServerDailyStat struct {
|
|||||||
CountRequests uint64 `field:"countRequests"` // 请求数
|
CountRequests uint64 `field:"countRequests"` // 请求数
|
||||||
CountCachedRequests uint64 `field:"countCachedRequests"` // 缓存的请求数
|
CountCachedRequests uint64 `field:"countCachedRequests"` // 缓存的请求数
|
||||||
Day string `field:"day"` // 日期YYYYMMDD
|
Day string `field:"day"` // 日期YYYYMMDD
|
||||||
|
Hour string `field:"hour"` // YYYYMMDDHH
|
||||||
TimeFrom string `field:"timeFrom"` // 开始时间HHMMSS
|
TimeFrom string `field:"timeFrom"` // 开始时间HHMMSS
|
||||||
TimeTo string `field:"timeTo"` // 结束时间
|
TimeTo string `field:"timeTo"` // 结束时间
|
||||||
IsCharged uint8 `field:"isCharged"` // 是否已计算费用
|
IsCharged uint8 `field:"isCharged"` // 是否已计算费用
|
||||||
@@ -24,6 +25,7 @@ type ServerDailyStatOperator struct {
|
|||||||
CountRequests interface{} // 请求数
|
CountRequests interface{} // 请求数
|
||||||
CountCachedRequests interface{} // 缓存的请求数
|
CountCachedRequests interface{} // 缓存的请求数
|
||||||
Day interface{} // 日期YYYYMMDD
|
Day interface{} // 日期YYYYMMDD
|
||||||
|
Hour interface{} // YYYYMMDDHH
|
||||||
TimeFrom interface{} // 开始时间HHMMSS
|
TimeFrom interface{} // 开始时间HHMMSS
|
||||||
TimeTo interface{} // 结束时间
|
TimeTo interface{} // 结束时间
|
||||||
IsCharged interface{} // 是否已计算费用
|
IsCharged interface{} // 是否已计算费用
|
||||||
|
|||||||
93
internal/db/models/server_stat_board_chart_dao.go
Normal file
93
internal/db/models/server_stat_board_chart_dao.go
Normal file
@@ -0,0 +1,93 @@
|
|||||||
|
package models
|
||||||
|
|
||||||
|
import (
|
||||||
|
_ "github.com/go-sql-driver/mysql"
|
||||||
|
"github.com/iwind/TeaGo/Tea"
|
||||||
|
"github.com/iwind/TeaGo/dbs"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
ServerStatBoardChartStateEnabled = 1 // 已启用
|
||||||
|
ServerStatBoardChartStateDisabled = 0 // 已禁用
|
||||||
|
)
|
||||||
|
|
||||||
|
type ServerStatBoardChartDAO dbs.DAO
|
||||||
|
|
||||||
|
func NewServerStatBoardChartDAO() *ServerStatBoardChartDAO {
|
||||||
|
return dbs.NewDAO(&ServerStatBoardChartDAO{
|
||||||
|
DAOObject: dbs.DAOObject{
|
||||||
|
DB: Tea.Env,
|
||||||
|
Table: "edgeServerStatBoardCharts",
|
||||||
|
Model: new(ServerStatBoardChart),
|
||||||
|
PkName: "id",
|
||||||
|
},
|
||||||
|
}).(*ServerStatBoardChartDAO)
|
||||||
|
}
|
||||||
|
|
||||||
|
var SharedServerStatBoardChartDAO *ServerStatBoardChartDAO
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
dbs.OnReady(func() {
|
||||||
|
SharedServerStatBoardChartDAO = NewServerStatBoardChartDAO()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// EnableServerStatBoardChart 启用条目
|
||||||
|
func (this *ServerStatBoardChartDAO) EnableServerStatBoardChart(tx *dbs.Tx, id uint64) error {
|
||||||
|
_, err := this.Query(tx).
|
||||||
|
Pk(id).
|
||||||
|
Set("state", ServerStatBoardChartStateEnabled).
|
||||||
|
Update()
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// DisableServerStatBoardChart 禁用条目
|
||||||
|
func (this *ServerStatBoardChartDAO) DisableServerStatBoardChart(tx *dbs.Tx, id uint64) error {
|
||||||
|
_, err := this.Query(tx).
|
||||||
|
Pk(id).
|
||||||
|
Set("state", ServerStatBoardChartStateDisabled).
|
||||||
|
Update()
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// FindEnabledServerStatBoardChart 查找启用中的条目
|
||||||
|
func (this *ServerStatBoardChartDAO) FindEnabledServerStatBoardChart(tx *dbs.Tx, id uint64) (*ServerStatBoardChart, error) {
|
||||||
|
result, err := this.Query(tx).
|
||||||
|
Pk(id).
|
||||||
|
Attr("state", ServerStatBoardChartStateEnabled).
|
||||||
|
Find()
|
||||||
|
if result == nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return result.(*ServerStatBoardChart), err
|
||||||
|
}
|
||||||
|
|
||||||
|
// EnableChart 启用图表
|
||||||
|
func (this *ServerStatBoardChartDAO) EnableChart(tx *dbs.Tx, boardId int64, chartId int64) error {
|
||||||
|
op := NewServerStatBoardChartOperator()
|
||||||
|
op.BoardId = boardId
|
||||||
|
op.ChartId = chartId
|
||||||
|
op.State = ServerStatBoardChartStateEnabled
|
||||||
|
return this.Save(tx, op)
|
||||||
|
}
|
||||||
|
|
||||||
|
// DisableChart 禁用图表
|
||||||
|
func (this *ServerStatBoardChartDAO) DisableChart(tx *dbs.Tx, boardId int64, chartId int64) error {
|
||||||
|
return this.Query(tx).
|
||||||
|
Attr("borderId", boardId).
|
||||||
|
Attr("chartId", chartId).
|
||||||
|
Set("state", ServerStatBoardChartStateDisabled).
|
||||||
|
UpdateQuickly()
|
||||||
|
}
|
||||||
|
|
||||||
|
// FindAllEnabledCharts 查找看板中所有图表
|
||||||
|
func (this *ServerStatBoardChartDAO) FindAllEnabledCharts(tx *dbs.Tx, boardId int64) (result []*ServerStatBoardChart, err error) {
|
||||||
|
_, err = this.Query(tx).
|
||||||
|
Attr("boardId", boardId).
|
||||||
|
Desc("order").
|
||||||
|
AscPk().
|
||||||
|
State(ServerStatBoardChartStateEnabled).
|
||||||
|
Slice(&result).
|
||||||
|
FindAll()
|
||||||
|
return
|
||||||
|
}
|
||||||
6
internal/db/models/server_stat_board_chart_dao_test.go
Normal file
6
internal/db/models/server_stat_board_chart_dao_test.go
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
package models
|
||||||
|
|
||||||
|
import (
|
||||||
|
_ "github.com/go-sql-driver/mysql"
|
||||||
|
_ "github.com/iwind/TeaGo/bootstrap"
|
||||||
|
)
|
||||||
26
internal/db/models/server_stat_board_chart_model.go
Normal file
26
internal/db/models/server_stat_board_chart_model.go
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
package models
|
||||||
|
|
||||||
|
// ServerStatBoardChart 服务看板中的图表
|
||||||
|
type ServerStatBoardChart struct {
|
||||||
|
Id uint64 `field:"id"` // ID
|
||||||
|
BoardId uint64 `field:"boardId"` // 看板ID
|
||||||
|
Code string `field:"code"` // 内置图表代码
|
||||||
|
ItemId uint32 `field:"itemId"` // 指标ID
|
||||||
|
ChartId uint32 `field:"chartId"` // 图表ID
|
||||||
|
Order uint32 `field:"order"` // 排序
|
||||||
|
State uint8 `field:"state"` // 状态
|
||||||
|
}
|
||||||
|
|
||||||
|
type ServerStatBoardChartOperator struct {
|
||||||
|
Id interface{} // ID
|
||||||
|
BoardId interface{} // 看板ID
|
||||||
|
Code interface{} // 内置图表代码
|
||||||
|
ItemId interface{} // 指标ID
|
||||||
|
ChartId interface{} // 图表ID
|
||||||
|
Order interface{} // 排序
|
||||||
|
State interface{} // 状态
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewServerStatBoardChartOperator() *ServerStatBoardChartOperator {
|
||||||
|
return &ServerStatBoardChartOperator{}
|
||||||
|
}
|
||||||
1
internal/db/models/server_stat_board_chart_model_ext.go
Normal file
1
internal/db/models/server_stat_board_chart_model_ext.go
Normal file
@@ -0,0 +1 @@
|
|||||||
|
package models
|
||||||
83
internal/db/models/server_stat_board_dao.go
Normal file
83
internal/db/models/server_stat_board_dao.go
Normal file
@@ -0,0 +1,83 @@
|
|||||||
|
package models
|
||||||
|
|
||||||
|
import (
|
||||||
|
_ "github.com/go-sql-driver/mysql"
|
||||||
|
"github.com/iwind/TeaGo/Tea"
|
||||||
|
"github.com/iwind/TeaGo/dbs"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
ServerStatBoardStateEnabled = 1 // 已启用
|
||||||
|
ServerStatBoardStateDisabled = 0 // 已禁用
|
||||||
|
)
|
||||||
|
|
||||||
|
type ServerStatBoardDAO dbs.DAO
|
||||||
|
|
||||||
|
func NewServerStatBoardDAO() *ServerStatBoardDAO {
|
||||||
|
return dbs.NewDAO(&ServerStatBoardDAO{
|
||||||
|
DAOObject: dbs.DAOObject{
|
||||||
|
DB: Tea.Env,
|
||||||
|
Table: "edgeServerStatBoards",
|
||||||
|
Model: new(ServerStatBoard),
|
||||||
|
PkName: "id",
|
||||||
|
},
|
||||||
|
}).(*ServerStatBoardDAO)
|
||||||
|
}
|
||||||
|
|
||||||
|
var SharedServerStatBoardDAO *ServerStatBoardDAO
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
dbs.OnReady(func() {
|
||||||
|
SharedServerStatBoardDAO = NewServerStatBoardDAO()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// EnableServerStatBoard 启用条目
|
||||||
|
func (this *ServerStatBoardDAO) EnableServerStatBoard(tx *dbs.Tx, id uint64) error {
|
||||||
|
_, err := this.Query(tx).
|
||||||
|
Pk(id).
|
||||||
|
Set("state", ServerStatBoardStateEnabled).
|
||||||
|
Update()
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// DisableServerStatBoard 禁用条目
|
||||||
|
func (this *ServerStatBoardDAO) DisableServerStatBoard(tx *dbs.Tx, id uint64) error {
|
||||||
|
_, err := this.Query(tx).
|
||||||
|
Pk(id).
|
||||||
|
Set("state", ServerStatBoardStateDisabled).
|
||||||
|
Update()
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// FindEnabledServerStatBoard 查找启用中的条目
|
||||||
|
func (this *ServerStatBoardDAO) FindEnabledServerStatBoard(tx *dbs.Tx, id uint64) (*ServerStatBoard, error) {
|
||||||
|
result, err := this.Query(tx).
|
||||||
|
Pk(id).
|
||||||
|
Attr("state", ServerStatBoardStateEnabled).
|
||||||
|
Find()
|
||||||
|
if result == nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return result.(*ServerStatBoard), err
|
||||||
|
}
|
||||||
|
|
||||||
|
// FindServerStatBoardName 根据主键查找名称
|
||||||
|
func (this *ServerStatBoardDAO) FindServerStatBoardName(tx *dbs.Tx, id uint64) (string, error) {
|
||||||
|
return this.Query(tx).
|
||||||
|
Pk(id).
|
||||||
|
Result("name").
|
||||||
|
FindStringCol("")
|
||||||
|
}
|
||||||
|
|
||||||
|
// FindAllEnabledBoards 查找看板
|
||||||
|
func (this *ServerStatBoardDAO) FindAllEnabledBoards(tx *dbs.Tx, clusterId int64) (result []*ServerStatBoard, err error) {
|
||||||
|
_, err = this.Query(tx).
|
||||||
|
Attr("clusterId", clusterId).
|
||||||
|
State(ServerStatBoardStateEnabled).
|
||||||
|
Slice(&result).
|
||||||
|
Desc("order").
|
||||||
|
AscPk().
|
||||||
|
FindAll()
|
||||||
|
return
|
||||||
|
}
|
||||||
6
internal/db/models/server_stat_board_dao_test.go
Normal file
6
internal/db/models/server_stat_board_dao_test.go
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
package models
|
||||||
|
|
||||||
|
import (
|
||||||
|
_ "github.com/go-sql-driver/mysql"
|
||||||
|
_ "github.com/iwind/TeaGo/bootstrap"
|
||||||
|
)
|
||||||
24
internal/db/models/server_stat_board_model.go
Normal file
24
internal/db/models/server_stat_board_model.go
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
package models
|
||||||
|
|
||||||
|
// ServerStatBoard 服务统计看板
|
||||||
|
type ServerStatBoard struct {
|
||||||
|
Id uint64 `field:"id"` // ID
|
||||||
|
Name string `field:"name"` // 名称
|
||||||
|
ClusterId uint32 `field:"clusterId"` // 集群ID
|
||||||
|
IsOn uint8 `field:"isOn"` // 是否启用
|
||||||
|
Order uint32 `field:"order"` // 排序
|
||||||
|
State uint8 `field:"state"` // 状态
|
||||||
|
}
|
||||||
|
|
||||||
|
type ServerStatBoardOperator struct {
|
||||||
|
Id interface{} // ID
|
||||||
|
Name interface{} // 名称
|
||||||
|
ClusterId interface{} // 集群ID
|
||||||
|
IsOn interface{} // 是否启用
|
||||||
|
Order interface{} // 排序
|
||||||
|
State interface{} // 状态
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewServerStatBoardOperator() *ServerStatBoardOperator {
|
||||||
|
return &ServerStatBoardOperator{}
|
||||||
|
}
|
||||||
1
internal/db/models/server_stat_board_model_ext.go
Normal file
1
internal/db/models/server_stat_board_model_ext.go
Normal file
@@ -0,0 +1 @@
|
|||||||
|
package models
|
||||||
@@ -2,14 +2,33 @@ package stats
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/TeaOSLab/EdgeAPI/internal/errors"
|
"github.com/TeaOSLab/EdgeAPI/internal/errors"
|
||||||
|
"github.com/TeaOSLab/EdgeAPI/internal/remotelogs"
|
||||||
|
"github.com/TeaOSLab/EdgeAPI/internal/utils"
|
||||||
_ "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"
|
||||||
|
timeutil "github.com/iwind/TeaGo/utils/time"
|
||||||
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
type NodeClusterTrafficDailyStatDAO dbs.DAO
|
type NodeClusterTrafficDailyStatDAO dbs.DAO
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
dbs.OnReadyDone(func() {
|
||||||
|
// 清理数据任务
|
||||||
|
var ticker = time.NewTicker(24 * time.Hour)
|
||||||
|
go func() {
|
||||||
|
for range ticker.C {
|
||||||
|
err := SharedNodeClusterTrafficDailyStatDAO.Clean(nil, 60) // 只保留60天
|
||||||
|
if err != nil {
|
||||||
|
remotelogs.Error("NodeClusterTrafficDailyStatDAO", "clean expired data failed: "+err.Error())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
func NewNodeClusterTrafficDailyStatDAO() *NodeClusterTrafficDailyStatDAO {
|
func NewNodeClusterTrafficDailyStatDAO() *NodeClusterTrafficDailyStatDAO {
|
||||||
return dbs.NewDAO(&NodeClusterTrafficDailyStatDAO{
|
return dbs.NewDAO(&NodeClusterTrafficDailyStatDAO{
|
||||||
DAOObject: dbs.DAOObject{
|
DAOObject: dbs.DAOObject{
|
||||||
@@ -29,22 +48,69 @@ func init() {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
// 增加流量
|
// IncreaseDailyStat 增加统计数据
|
||||||
func (this *NodeClusterTrafficDailyStatDAO) IncreaseDailyBytes(tx *dbs.Tx, clusterId int64, day string, bytes int64) error {
|
func (this *NodeClusterTrafficDailyStatDAO) IncreaseDailyStat(tx *dbs.Tx, clusterId int64, day string, bytes int64, cachedBytes int64, countRequests int64, countCachedRequests int64) error {
|
||||||
if len(day) != 8 {
|
if len(day) != 8 {
|
||||||
return errors.New("invalid day '" + day + "'")
|
return errors.New("invalid day '" + day + "'")
|
||||||
}
|
}
|
||||||
err := this.Query(tx).
|
err := this.Query(tx).
|
||||||
Param("bytes", bytes).
|
Param("bytes", bytes).
|
||||||
|
Param("cachedBytes", cachedBytes).
|
||||||
|
Param("countRequests", countRequests).
|
||||||
|
Param("countCachedRequests", countCachedRequests).
|
||||||
InsertOrUpdateQuickly(maps.Map{
|
InsertOrUpdateQuickly(maps.Map{
|
||||||
"clusterId": clusterId,
|
"clusterId": clusterId,
|
||||||
"day": day,
|
"day": day,
|
||||||
"bytes": bytes,
|
"bytes": bytes,
|
||||||
|
"cachedBytes": cachedBytes,
|
||||||
|
"countRequests": countRequests,
|
||||||
|
"countCachedRequests": countCachedRequests,
|
||||||
}, maps.Map{
|
}, maps.Map{
|
||||||
"bytes": dbs.SQL("bytes+:bytes"),
|
"bytes": dbs.SQL("bytes+:bytes"),
|
||||||
|
"cachedBytes": dbs.SQL("cachedBytes+:cachedBytes"),
|
||||||
|
"countRequests": dbs.SQL("countRequests+:countRequests"),
|
||||||
|
"countCachedRequests": dbs.SQL("countCachedRequests+:countCachedRequests"),
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// FindDailyStats 获取日期之间统计
|
||||||
|
func (this *NodeClusterTrafficDailyStatDAO) FindDailyStats(tx *dbs.Tx, clusterId int64, dayFrom string, dayTo string) (result []*NodeClusterTrafficDailyStat, err error) {
|
||||||
|
ones, err := this.Query(tx).
|
||||||
|
Attr("clusterId", clusterId).
|
||||||
|
Between("day", dayFrom, dayTo).
|
||||||
|
FindAll()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
dayMap := map[string]*NodeClusterTrafficDailyStat{} // day => Stat
|
||||||
|
for _, one := range ones {
|
||||||
|
stat := one.(*NodeClusterTrafficDailyStat)
|
||||||
|
dayMap[stat.Day] = stat
|
||||||
|
}
|
||||||
|
days, err := utils.RangeDays(dayFrom, dayTo)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
for _, day := range days {
|
||||||
|
stat, ok := dayMap[day]
|
||||||
|
if ok {
|
||||||
|
result = append(result, stat)
|
||||||
|
} else {
|
||||||
|
result = append(result, &NodeClusterTrafficDailyStat{Day: day})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Clean 清理历史数据
|
||||||
|
func (this *NodeClusterTrafficDailyStatDAO) Clean(tx *dbs.Tx, days int) error {
|
||||||
|
var day = timeutil.Format("Ymd", time.Now().AddDate(0, 0, -days))
|
||||||
|
_, err := this.Query(tx).
|
||||||
|
Lt("day", day).
|
||||||
|
Delete()
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,18 +1,24 @@
|
|||||||
package stats
|
package stats
|
||||||
|
|
||||||
// 总的流量统计(按天)
|
// NodeClusterTrafficDailyStat 总的流量统计(按天)
|
||||||
type NodeClusterTrafficDailyStat struct {
|
type NodeClusterTrafficDailyStat struct {
|
||||||
Id uint64 `field:"id"` // ID
|
Id uint64 `field:"id"` // ID
|
||||||
ClusterId uint32 `field:"clusterId"` // 集群ID
|
ClusterId uint32 `field:"clusterId"` // 集群ID
|
||||||
Day string `field:"day"` // YYYYMMDD
|
Day string `field:"day"` // YYYYMMDD
|
||||||
Bytes uint64 `field:"bytes"` // 流量字节
|
Bytes uint64 `field:"bytes"` // 流量字节
|
||||||
|
CachedBytes uint64 `field:"cachedBytes"` // 缓存流量
|
||||||
|
CountRequests uint64 `field:"countRequests"` // 请求数
|
||||||
|
CountCachedRequests uint64 `field:"countCachedRequests"` // 缓存的请求数
|
||||||
}
|
}
|
||||||
|
|
||||||
type NodeClusterTrafficDailyStatOperator struct {
|
type NodeClusterTrafficDailyStatOperator struct {
|
||||||
Id interface{} // ID
|
Id interface{} // ID
|
||||||
ClusterId interface{} // 集群ID
|
ClusterId interface{} // 集群ID
|
||||||
Day interface{} // YYYYMMDD
|
Day interface{} // YYYYMMDD
|
||||||
Bytes interface{} // 流量字节
|
Bytes interface{} // 流量字节
|
||||||
|
CachedBytes interface{} // 缓存流量
|
||||||
|
CountRequests interface{} // 请求数
|
||||||
|
CountCachedRequests interface{} // 缓存的请求数
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewNodeClusterTrafficDailyStatOperator() *NodeClusterTrafficDailyStatOperator {
|
func NewNodeClusterTrafficDailyStatOperator() *NodeClusterTrafficDailyStatOperator {
|
||||||
|
|||||||
@@ -2,14 +2,32 @@ 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"
|
||||||
|
timeutil "github.com/iwind/TeaGo/utils/time"
|
||||||
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
type NodeTrafficDailyStatDAO dbs.DAO
|
type NodeTrafficDailyStatDAO dbs.DAO
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
dbs.OnReadyDone(func() {
|
||||||
|
// 清理数据任务
|
||||||
|
var ticker = time.NewTicker(24 * time.Hour)
|
||||||
|
go func() {
|
||||||
|
for range ticker.C {
|
||||||
|
err := SharedNodeTrafficDailyStatDAO.Clean(nil, 60) // 只保留60天
|
||||||
|
if err != nil {
|
||||||
|
remotelogs.Error("NodeTrafficDailyStatDAO", "clean expired data failed: "+err.Error())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
func NewNodeTrafficDailyStatDAO() *NodeTrafficDailyStatDAO {
|
func NewNodeTrafficDailyStatDAO() *NodeTrafficDailyStatDAO {
|
||||||
return dbs.NewDAO(&NodeTrafficDailyStatDAO{
|
return dbs.NewDAO(&NodeTrafficDailyStatDAO{
|
||||||
DAOObject: dbs.DAOObject{
|
DAOObject: dbs.DAOObject{
|
||||||
@@ -29,22 +47,42 @@ func init() {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
// 增加流量
|
// IncreaseDailyStat 增加统计数据
|
||||||
func (this *NodeTrafficDailyStatDAO) IncreaseDailyBytes(tx *dbs.Tx, nodeId int64, day string, bytes int64) error {
|
func (this *NodeTrafficDailyStatDAO) IncreaseDailyStat(tx *dbs.Tx, clusterId int64, role string, nodeId int64, day string, bytes int64, cachedBytes int64, countRequests int64, countCachedRequests int64) error {
|
||||||
if len(day) != 8 {
|
if len(day) != 8 {
|
||||||
return errors.New("invalid day '" + day + "'")
|
return errors.New("invalid day '" + day + "'")
|
||||||
}
|
}
|
||||||
err := this.Query(tx).
|
err := this.Query(tx).
|
||||||
Param("bytes", bytes).
|
Param("bytes", bytes).
|
||||||
|
Param("cachedBytes", cachedBytes).
|
||||||
|
Param("countRequests", countRequests).
|
||||||
|
Param("countCachedRequests", countCachedRequests).
|
||||||
InsertOrUpdateQuickly(maps.Map{
|
InsertOrUpdateQuickly(maps.Map{
|
||||||
"nodeId": nodeId,
|
"clusterId": clusterId,
|
||||||
"day": day,
|
"role": role,
|
||||||
"bytes": bytes,
|
"nodeId": nodeId,
|
||||||
|
"day": day,
|
||||||
|
"bytes": bytes,
|
||||||
|
"cachedBytes": cachedBytes,
|
||||||
|
"countRequests": countRequests,
|
||||||
|
"countCachedRequests": countCachedRequests,
|
||||||
}, maps.Map{
|
}, maps.Map{
|
||||||
"bytes": dbs.SQL("bytes+:bytes"),
|
"bytes": dbs.SQL("bytes+:bytes"),
|
||||||
|
"cachedBytes": dbs.SQL("cachedBytes+:cachedBytes"),
|
||||||
|
"countRequests": dbs.SQL("countRequests+:countRequests"),
|
||||||
|
"countCachedRequests": dbs.SQL("countCachedRequests+:countCachedRequests"),
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Clean 清理历史数据
|
||||||
|
func (this *NodeTrafficDailyStatDAO) Clean(tx *dbs.Tx, days int) error {
|
||||||
|
var day = timeutil.Format("Ymd", time.Now().AddDate(0, 0, -days))
|
||||||
|
_, err := this.Query(tx).
|
||||||
|
Lt("day", day).
|
||||||
|
Delete()
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,18 +1,28 @@
|
|||||||
package stats
|
package stats
|
||||||
|
|
||||||
// 总的流量统计(按天)
|
// NodeTrafficDailyStat 总的流量统计(按天)
|
||||||
type NodeTrafficDailyStat struct {
|
type NodeTrafficDailyStat struct {
|
||||||
Id uint64 `field:"id"` // ID
|
Id uint64 `field:"id"` // ID
|
||||||
NodeId uint32 `field:"nodeId"` // 集群ID
|
Role string `field:"role"` // 节点角色
|
||||||
Day string `field:"day"` // YYYYMMDD
|
ClusterId uint32 `field:"clusterId"` // 集群ID
|
||||||
Bytes uint64 `field:"bytes"` // 流量字节
|
NodeId uint32 `field:"nodeId"` // 集群ID
|
||||||
|
Day string `field:"day"` // YYYYMMDD
|
||||||
|
Bytes uint64 `field:"bytes"` // 流量字节
|
||||||
|
CachedBytes uint64 `field:"cachedBytes"` // 缓存流量
|
||||||
|
CountRequests uint64 `field:"countRequests"` // 请求数
|
||||||
|
CountCachedRequests uint64 `field:"countCachedRequests"` // 缓存的请求数
|
||||||
}
|
}
|
||||||
|
|
||||||
type NodeTrafficDailyStatOperator struct {
|
type NodeTrafficDailyStatOperator struct {
|
||||||
Id interface{} // ID
|
Id interface{} // ID
|
||||||
NodeId interface{} // 集群ID
|
Role interface{} // 节点角色
|
||||||
Day interface{} // YYYYMMDD
|
ClusterId interface{} // 集群ID
|
||||||
Bytes interface{} // 流量字节
|
NodeId interface{} // 集群ID
|
||||||
|
Day interface{} // YYYYMMDD
|
||||||
|
Bytes interface{} // 流量字节
|
||||||
|
CachedBytes interface{} // 缓存流量
|
||||||
|
CountRequests interface{} // 请求数
|
||||||
|
CountCachedRequests interface{} // 缓存的请求数
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewNodeTrafficDailyStatOperator() *NodeTrafficDailyStatOperator {
|
func NewNodeTrafficDailyStatOperator() *NodeTrafficDailyStatOperator {
|
||||||
|
|||||||
134
internal/db/models/stats/node_traffic_hourly_stat_dao.go
Normal file
134
internal/db/models/stats/node_traffic_hourly_stat_dao.go
Normal file
@@ -0,0 +1,134 @@
|
|||||||
|
package stats
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/TeaOSLab/EdgeAPI/internal/errors"
|
||||||
|
"github.com/TeaOSLab/EdgeAPI/internal/remotelogs"
|
||||||
|
"github.com/TeaOSLab/EdgeAPI/internal/utils"
|
||||||
|
_ "github.com/go-sql-driver/mysql"
|
||||||
|
"github.com/iwind/TeaGo/Tea"
|
||||||
|
"github.com/iwind/TeaGo/dbs"
|
||||||
|
"github.com/iwind/TeaGo/maps"
|
||||||
|
timeutil "github.com/iwind/TeaGo/utils/time"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
type NodeTrafficHourlyStatDAO dbs.DAO
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
dbs.OnReadyDone(func() {
|
||||||
|
// 清理数据任务
|
||||||
|
var ticker = time.NewTicker(24 * time.Hour)
|
||||||
|
go func() {
|
||||||
|
for range ticker.C {
|
||||||
|
err := SharedNodeTrafficHourlyStatDAO.Clean(nil, 60) // 只保留60天
|
||||||
|
if err != nil {
|
||||||
|
remotelogs.Error("NodeTrafficHourlyStatDAO", "clean expired data failed: "+err.Error())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewNodeTrafficHourlyStatDAO() *NodeTrafficHourlyStatDAO {
|
||||||
|
return dbs.NewDAO(&NodeTrafficHourlyStatDAO{
|
||||||
|
DAOObject: dbs.DAOObject{
|
||||||
|
DB: Tea.Env,
|
||||||
|
Table: "edgeNodeTrafficHourlyStats",
|
||||||
|
Model: new(NodeTrafficHourlyStat),
|
||||||
|
PkName: "id",
|
||||||
|
},
|
||||||
|
}).(*NodeTrafficHourlyStatDAO)
|
||||||
|
}
|
||||||
|
|
||||||
|
var SharedNodeTrafficHourlyStatDAO *NodeTrafficHourlyStatDAO
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
dbs.OnReady(func() {
|
||||||
|
SharedNodeTrafficHourlyStatDAO = NewNodeTrafficHourlyStatDAO()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// IncreaseHourlyStat 增加统计数据
|
||||||
|
func (this *NodeTrafficHourlyStatDAO) IncreaseHourlyStat(tx *dbs.Tx, clusterId int64, role string, nodeId int64, hour string, bytes int64, cachedBytes int64, countRequests int64, countCachedRequests int64) error {
|
||||||
|
if len(hour) != 10 {
|
||||||
|
return errors.New("invalid hour '" + hour + "'")
|
||||||
|
}
|
||||||
|
err := this.Query(tx).
|
||||||
|
Param("bytes", bytes).
|
||||||
|
Param("cachedBytes", cachedBytes).
|
||||||
|
Param("countRequests", countRequests).
|
||||||
|
Param("countCachedRequests", countCachedRequests).
|
||||||
|
InsertOrUpdateQuickly(maps.Map{
|
||||||
|
"clusterId": clusterId,
|
||||||
|
"role": role,
|
||||||
|
"nodeId": nodeId,
|
||||||
|
"hour": hour,
|
||||||
|
"bytes": bytes,
|
||||||
|
"cachedBytes": cachedBytes,
|
||||||
|
"countRequests": countRequests,
|
||||||
|
"countCachedRequests": countCachedRequests,
|
||||||
|
}, maps.Map{
|
||||||
|
"bytes": dbs.SQL("bytes+:bytes"),
|
||||||
|
"cachedBytes": dbs.SQL("cachedBytes+:cachedBytes"),
|
||||||
|
"countRequests": dbs.SQL("countRequests+:countRequests"),
|
||||||
|
"countCachedRequests": dbs.SQL("countCachedRequests+:countCachedRequests"),
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// FindHourlyStatsWithClusterId 获取小时之间统计
|
||||||
|
func (this *NodeTrafficHourlyStatDAO) FindHourlyStatsWithClusterId(tx *dbs.Tx, clusterId int64, hourFrom string, hourTo string) (result []*NodeTrafficHourlyStat, err error) {
|
||||||
|
ones, err := this.Query(tx).
|
||||||
|
Attr("clusterId", clusterId).
|
||||||
|
Between("hour", hourFrom, hourTo).
|
||||||
|
Result("hour, SUM(bytes) AS bytes, SUM(cachedBytes) AS cachedBytes, SUM(countRequests) AS countRequests, SUM(countCachedRequests) AS countCachedRequests").
|
||||||
|
Group("hour").
|
||||||
|
FindAll()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
hourMap := map[string]*NodeTrafficHourlyStat{} // hour => Stat
|
||||||
|
for _, one := range ones {
|
||||||
|
stat := one.(*NodeTrafficHourlyStat)
|
||||||
|
hourMap[stat.Hour] = stat
|
||||||
|
}
|
||||||
|
hours, err := utils.RangeHours(hourFrom, hourTo)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
for _, hour := range hours {
|
||||||
|
stat, ok := hourMap[hour]
|
||||||
|
if ok {
|
||||||
|
result = append(result, stat)
|
||||||
|
} else {
|
||||||
|
result = append(result, &NodeTrafficHourlyStat{Hour: hour})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// FindTopNodeStatsWithClusterId 取得一定时间内的节点排行数据
|
||||||
|
func (this *NodeTrafficHourlyStatDAO) FindTopNodeStatsWithClusterId(tx *dbs.Tx, clusterId int64, hourFrom string, hourTo string) (result []*NodeTrafficHourlyStat, err error) {
|
||||||
|
// TODO 节点如果已经被删除,则忽略
|
||||||
|
_, err = this.Query(tx).
|
||||||
|
Attr("clusterId", clusterId).
|
||||||
|
Between("hour", hourFrom, hourTo).
|
||||||
|
Result("nodeId, SUM(bytes) AS bytes, SUM(cachedBytes) AS cachedBytes, SUM(countRequests) AS countRequests, SUM(countCachedRequests) AS countCachedRequests").
|
||||||
|
Group("nodeId").
|
||||||
|
Desc("countRequests").
|
||||||
|
Slice(&result).
|
||||||
|
FindAll()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Clean 清理历史数据
|
||||||
|
func (this *NodeTrafficHourlyStatDAO) Clean(tx *dbs.Tx, days int) error {
|
||||||
|
var hour = timeutil.Format("Ymd00", time.Now().AddDate(0, 0, -days))
|
||||||
|
_, err := this.Query(tx).
|
||||||
|
Lt("hour", hour).
|
||||||
|
Delete()
|
||||||
|
return err
|
||||||
|
}
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
package stats
|
||||||
|
|
||||||
|
import (
|
||||||
|
_ "github.com/go-sql-driver/mysql"
|
||||||
|
_ "github.com/iwind/TeaGo/bootstrap"
|
||||||
|
)
|
||||||
30
internal/db/models/stats/node_traffic_hourly_stat_model.go
Normal file
30
internal/db/models/stats/node_traffic_hourly_stat_model.go
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
package stats
|
||||||
|
|
||||||
|
// NodeTrafficHourlyStat 总的流量统计(按天)
|
||||||
|
type NodeTrafficHourlyStat struct {
|
||||||
|
Id uint64 `field:"id"` // ID
|
||||||
|
Role string `field:"role"` // 节点角色
|
||||||
|
ClusterId uint32 `field:"clusterId"` // 集群ID
|
||||||
|
NodeId uint32 `field:"nodeId"` // 集群ID
|
||||||
|
Hour string `field:"hour"` // YYYYMMDDHH
|
||||||
|
Bytes uint64 `field:"bytes"` // 流量字节
|
||||||
|
CachedBytes uint64 `field:"cachedBytes"` // 缓存流量
|
||||||
|
CountRequests uint64 `field:"countRequests"` // 请求数
|
||||||
|
CountCachedRequests uint64 `field:"countCachedRequests"` // 缓存的请求数
|
||||||
|
}
|
||||||
|
|
||||||
|
type NodeTrafficHourlyStatOperator struct {
|
||||||
|
Id interface{} // ID
|
||||||
|
Role interface{} // 节点角色
|
||||||
|
ClusterId interface{} // 集群ID
|
||||||
|
NodeId interface{} // 集群ID
|
||||||
|
Hour interface{} // YYYYMMDDHH
|
||||||
|
Bytes interface{} // 流量字节
|
||||||
|
CachedBytes interface{} // 缓存流量
|
||||||
|
CountRequests interface{} // 请求数
|
||||||
|
CountCachedRequests interface{} // 缓存的请求数
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewNodeTrafficHourlyStatOperator() *NodeTrafficHourlyStatOperator {
|
||||||
|
return &NodeTrafficHourlyStatOperator{}
|
||||||
|
}
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
package stats
|
||||||
103
internal/db/models/stats/server_domain_hourly_stat_dao.go
Normal file
103
internal/db/models/stats/server_domain_hourly_stat_dao.go
Normal file
@@ -0,0 +1,103 @@
|
|||||||
|
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"
|
||||||
|
timeutil "github.com/iwind/TeaGo/utils/time"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
type ServerDomainHourlyStatDAO dbs.DAO
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
dbs.OnReadyDone(func() {
|
||||||
|
// 清理数据任务
|
||||||
|
var ticker = time.NewTicker(24 * time.Hour)
|
||||||
|
go func() {
|
||||||
|
for range ticker.C {
|
||||||
|
err := SharedServerDomainHourlyStatDAO.Clean(nil, 60) // 只保留60天
|
||||||
|
if err != nil {
|
||||||
|
remotelogs.Error("ServerDomainHourlyStatDAO", "clean expired data failed: "+err.Error())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewServerDomainHourlyStatDAO() *ServerDomainHourlyStatDAO {
|
||||||
|
return dbs.NewDAO(&ServerDomainHourlyStatDAO{
|
||||||
|
DAOObject: dbs.DAOObject{
|
||||||
|
DB: Tea.Env,
|
||||||
|
Table: "edgeServerDomainHourlyStats",
|
||||||
|
Model: new(ServerDomainHourlyStat),
|
||||||
|
PkName: "id",
|
||||||
|
},
|
||||||
|
}).(*ServerDomainHourlyStatDAO)
|
||||||
|
}
|
||||||
|
|
||||||
|
var SharedServerDomainHourlyStatDAO *ServerDomainHourlyStatDAO
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
dbs.OnReady(func() {
|
||||||
|
SharedServerDomainHourlyStatDAO = NewServerDomainHourlyStatDAO()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// IncreaseHourlyStat 增加统计数据
|
||||||
|
func (this *ServerDomainHourlyStatDAO) IncreaseHourlyStat(tx *dbs.Tx, clusterId int64, nodeId int64, serverId int64, domain string, hour string, bytes int64, cachedBytes int64, countRequests int64, countCachedRequests int64) error {
|
||||||
|
if len(hour) != 10 {
|
||||||
|
return errors.New("invalid hour '" + hour + "'")
|
||||||
|
}
|
||||||
|
err := this.Query(tx).
|
||||||
|
Param("bytes", bytes).
|
||||||
|
Param("cachedBytes", cachedBytes).
|
||||||
|
Param("countRequests", countRequests).
|
||||||
|
Param("countCachedRequests", countCachedRequests).
|
||||||
|
InsertOrUpdateQuickly(maps.Map{
|
||||||
|
"clusterId": clusterId,
|
||||||
|
"nodeId": nodeId,
|
||||||
|
"serverId": serverId,
|
||||||
|
"hour": hour,
|
||||||
|
"domain": domain,
|
||||||
|
"bytes": bytes,
|
||||||
|
"cachedBytes": cachedBytes,
|
||||||
|
"countRequests": countRequests,
|
||||||
|
"countCachedRequests": countCachedRequests,
|
||||||
|
}, maps.Map{
|
||||||
|
"bytes": dbs.SQL("bytes+:bytes"),
|
||||||
|
"cachedBytes": dbs.SQL("cachedBytes+:cachedBytes"),
|
||||||
|
"countRequests": dbs.SQL("countRequests+:countRequests"),
|
||||||
|
"countCachedRequests": dbs.SQL("countCachedRequests+:countCachedRequests"),
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// FindTopDomainStatsWithClusterId 取得一定时间内的节点排行数据
|
||||||
|
func (this *ServerDomainHourlyStatDAO) FindTopDomainStatsWithClusterId(tx *dbs.Tx, clusterId int64, hourFrom string, hourTo string) (result []*ServerDomainHourlyStat, err error) {
|
||||||
|
// TODO 节点如果已经被删除,则忽略
|
||||||
|
_, err = this.Query(tx).
|
||||||
|
Attr("clusterId", clusterId).
|
||||||
|
Between("hour", hourFrom, hourTo).
|
||||||
|
Result("domain, MIN(serverId) AS serverId, SUM(bytes) AS bytes, SUM(cachedBytes) AS cachedBytes, SUM(countRequests) AS countRequests, SUM(countCachedRequests) AS countCachedRequests").
|
||||||
|
Group("domain").
|
||||||
|
Desc("countRequests").
|
||||||
|
Slice(&result).
|
||||||
|
FindAll()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Clean 清理历史数据
|
||||||
|
func (this *ServerDomainHourlyStatDAO) Clean(tx *dbs.Tx, days int) error {
|
||||||
|
var hour = timeutil.Format("Ymd00", time.Now().AddDate(0, 0, -days))
|
||||||
|
_, err := this.Query(tx).
|
||||||
|
Lt("hour", hour).
|
||||||
|
Delete()
|
||||||
|
return err
|
||||||
|
}
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
package stats
|
||||||
|
|
||||||
|
import (
|
||||||
|
_ "github.com/go-sql-driver/mysql"
|
||||||
|
_ "github.com/iwind/TeaGo/bootstrap"
|
||||||
|
)
|
||||||
32
internal/db/models/stats/server_domain_hourly_stat_model.go
Normal file
32
internal/db/models/stats/server_domain_hourly_stat_model.go
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
package stats
|
||||||
|
|
||||||
|
// ServerDomainHourlyStat 服务域名统计
|
||||||
|
type ServerDomainHourlyStat struct {
|
||||||
|
Id uint64 `field:"id"` // ID
|
||||||
|
ClusterId uint32 `field:"clusterId"` // 集群ID
|
||||||
|
NodeId uint32 `field:"nodeId"` // 节点ID
|
||||||
|
ServerId uint32 `field:"serverId"` // 服务ID
|
||||||
|
Domain string `field:"domain"` // 域名
|
||||||
|
Hour string `field:"hour"` // YYYYMMDDHH
|
||||||
|
Bytes uint64 `field:"bytes"` // 流量
|
||||||
|
CachedBytes uint64 `field:"cachedBytes"` // 缓存流量
|
||||||
|
CountRequests uint64 `field:"countRequests"` // 请求数
|
||||||
|
CountCachedRequests uint64 `field:"countCachedRequests"` // 缓存请求
|
||||||
|
}
|
||||||
|
|
||||||
|
type ServerDomainHourlyStatOperator struct {
|
||||||
|
Id interface{} // ID
|
||||||
|
ClusterId interface{} // 集群ID
|
||||||
|
NodeId interface{} // 节点ID
|
||||||
|
ServerId interface{} // 服务ID
|
||||||
|
Domain interface{} // 域名
|
||||||
|
Hour interface{} // YYYYMMDDHH
|
||||||
|
Bytes interface{} // 流量
|
||||||
|
CachedBytes interface{} // 缓存流量
|
||||||
|
CountRequests interface{} // 请求数
|
||||||
|
CountCachedRequests interface{} // 缓存请求
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewServerDomainHourlyStatOperator() *ServerDomainHourlyStatOperator {
|
||||||
|
return &ServerDomainHourlyStatOperator{}
|
||||||
|
}
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
package stats
|
||||||
@@ -2,15 +2,33 @@ package stats
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/TeaOSLab/EdgeAPI/internal/errors"
|
"github.com/TeaOSLab/EdgeAPI/internal/errors"
|
||||||
|
"github.com/TeaOSLab/EdgeAPI/internal/remotelogs"
|
||||||
"github.com/TeaOSLab/EdgeAPI/internal/utils"
|
"github.com/TeaOSLab/EdgeAPI/internal/utils"
|
||||||
_ "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"
|
||||||
|
timeutil "github.com/iwind/TeaGo/utils/time"
|
||||||
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
type TrafficDailyStatDAO dbs.DAO
|
type TrafficDailyStatDAO dbs.DAO
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
dbs.OnReadyDone(func() {
|
||||||
|
// 清理数据任务
|
||||||
|
var ticker = time.NewTicker(24 * time.Hour)
|
||||||
|
go func() {
|
||||||
|
for range ticker.C {
|
||||||
|
err := SharedTrafficDailyStatDAO.Clean(nil, 60) // 只保留60天
|
||||||
|
if err != nil {
|
||||||
|
remotelogs.Error("TrafficDailyStatDAO", "clean expired data failed: "+err.Error())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
func NewTrafficDailyStatDAO() *TrafficDailyStatDAO {
|
func NewTrafficDailyStatDAO() *TrafficDailyStatDAO {
|
||||||
return dbs.NewDAO(&TrafficDailyStatDAO{
|
return dbs.NewDAO(&TrafficDailyStatDAO{
|
||||||
DAOObject: dbs.DAOObject{
|
DAOObject: dbs.DAOObject{
|
||||||
@@ -30,18 +48,27 @@ func init() {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
// 增加流量
|
// IncreaseDailyStat 增加统计数据
|
||||||
func (this *TrafficDailyStatDAO) IncreaseDailyBytes(tx *dbs.Tx, day string, bytes int64) error {
|
func (this *TrafficDailyStatDAO) IncreaseDailyStat(tx *dbs.Tx, day string, bytes int64, cachedBytes int64, countRequests int64, countCachedRequests int64) error {
|
||||||
if len(day) != 8 {
|
if len(day) != 8 {
|
||||||
return errors.New("invalid day '" + day + "'")
|
return errors.New("invalid day '" + day + "'")
|
||||||
}
|
}
|
||||||
err := this.Query(tx).
|
err := this.Query(tx).
|
||||||
Param("bytes", bytes).
|
Param("bytes", bytes).
|
||||||
|
Param("cachedBytes", cachedBytes).
|
||||||
|
Param("countRequests", countRequests).
|
||||||
|
Param("countCachedRequests", countCachedRequests).
|
||||||
InsertOrUpdateQuickly(maps.Map{
|
InsertOrUpdateQuickly(maps.Map{
|
||||||
"day": day,
|
"day": day,
|
||||||
"bytes": bytes,
|
"bytes": bytes,
|
||||||
|
"cachedBytes": cachedBytes,
|
||||||
|
"countRequests": countRequests,
|
||||||
|
"countCachedRequests": countCachedRequests,
|
||||||
}, maps.Map{
|
}, maps.Map{
|
||||||
"bytes": dbs.SQL("bytes+:bytes"),
|
"bytes": dbs.SQL("bytes+:bytes"),
|
||||||
|
"cachedBytes": dbs.SQL("cachedBytes+:cachedBytes"),
|
||||||
|
"countRequests": dbs.SQL("countRequests+:countRequests"),
|
||||||
|
"countCachedRequests": dbs.SQL("countCachedRequests+:countCachedRequests"),
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
@@ -49,11 +76,14 @@ func (this *TrafficDailyStatDAO) IncreaseDailyBytes(tx *dbs.Tx, day string, byte
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// 获取日期之间统计
|
// FindDailyStats 获取日期之间统计
|
||||||
func (this *TrafficDailyStatDAO) FindDailyStats(tx *dbs.Tx, dayFrom string, dayTo string) (result []*TrafficDailyStat, err error) {
|
func (this *TrafficDailyStatDAO) FindDailyStats(tx *dbs.Tx, dayFrom string, dayTo string) (result []*TrafficDailyStat, err error) {
|
||||||
ones, err := this.Query(tx).
|
ones, err := this.Query(tx).
|
||||||
Between("day", dayFrom, dayTo).
|
Between("day", dayFrom, dayTo).
|
||||||
FindAll()
|
FindAll()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
dayMap := map[string]*TrafficDailyStat{} // day => Stat
|
dayMap := map[string]*TrafficDailyStat{} // day => Stat
|
||||||
for _, one := range ones {
|
for _, one := range ones {
|
||||||
stat := one.(*TrafficDailyStat)
|
stat := one.(*TrafficDailyStat)
|
||||||
@@ -73,3 +103,12 @@ func (this *TrafficDailyStatDAO) FindDailyStats(tx *dbs.Tx, dayFrom string, dayT
|
|||||||
}
|
}
|
||||||
return result, nil
|
return result, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Clean 清理历史数据
|
||||||
|
func (this *TrafficDailyStatDAO) Clean(tx *dbs.Tx, days int) error {
|
||||||
|
var day = timeutil.Format("Ymd", time.Now().AddDate(0, 0, -days))
|
||||||
|
_, err := this.Query(tx).
|
||||||
|
Lt("day", day).
|
||||||
|
Delete()
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,16 +1,22 @@
|
|||||||
package stats
|
package stats
|
||||||
|
|
||||||
// 总的流量统计
|
// TrafficDailyStat 总的流量统计(按天)
|
||||||
type TrafficDailyStat struct {
|
type TrafficDailyStat struct {
|
||||||
Id uint64 `field:"id"` // ID
|
Id uint64 `field:"id"` // ID
|
||||||
Day string `field:"day"` // YYYYMMDD
|
Day string `field:"day"` // YYYYMMDD
|
||||||
Bytes uint64 `field:"bytes"` // 流量字节
|
CachedBytes uint64 `field:"cachedBytes"` // 缓存流量
|
||||||
|
Bytes uint64 `field:"bytes"` // 流量字节
|
||||||
|
CountRequests uint64 `field:"countRequests"` // 请求数
|
||||||
|
CountCachedRequests uint64 `field:"countCachedRequests"` // 缓存请求数
|
||||||
}
|
}
|
||||||
|
|
||||||
type TrafficDailyStatOperator struct {
|
type TrafficDailyStatOperator struct {
|
||||||
Id interface{} // ID
|
Id interface{} // ID
|
||||||
Day interface{} // YYYYMMDD
|
Day interface{} // YYYYMMDD
|
||||||
Bytes interface{} // 流量字节
|
CachedBytes interface{} // 缓存流量
|
||||||
|
Bytes interface{} // 流量字节
|
||||||
|
CountRequests interface{} // 请求数
|
||||||
|
CountCachedRequests interface{} // 缓存请求数
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewTrafficDailyStatOperator() *TrafficDailyStatOperator {
|
func NewTrafficDailyStatOperator() *TrafficDailyStatOperator {
|
||||||
|
|||||||
@@ -2,15 +2,33 @@ package stats
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/TeaOSLab/EdgeAPI/internal/errors"
|
"github.com/TeaOSLab/EdgeAPI/internal/errors"
|
||||||
|
"github.com/TeaOSLab/EdgeAPI/internal/remotelogs"
|
||||||
"github.com/TeaOSLab/EdgeAPI/internal/utils"
|
"github.com/TeaOSLab/EdgeAPI/internal/utils"
|
||||||
_ "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"
|
||||||
|
timeutil "github.com/iwind/TeaGo/utils/time"
|
||||||
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
type TrafficHourlyStatDAO dbs.DAO
|
type TrafficHourlyStatDAO dbs.DAO
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
dbs.OnReadyDone(func() {
|
||||||
|
// 清理数据任务
|
||||||
|
var ticker = time.NewTicker(24 * time.Hour)
|
||||||
|
go func() {
|
||||||
|
for range ticker.C {
|
||||||
|
err := SharedTrafficHourlyStatDAO.Clean(nil, 60) // 只保留60天
|
||||||
|
if err != nil {
|
||||||
|
remotelogs.Error("TrafficHourlyStatDAO", "clean expired data failed: "+err.Error())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
func NewTrafficHourlyStatDAO() *TrafficHourlyStatDAO {
|
func NewTrafficHourlyStatDAO() *TrafficHourlyStatDAO {
|
||||||
return dbs.NewDAO(&TrafficHourlyStatDAO{
|
return dbs.NewDAO(&TrafficHourlyStatDAO{
|
||||||
DAOObject: dbs.DAOObject{
|
DAOObject: dbs.DAOObject{
|
||||||
@@ -30,18 +48,27 @@ func init() {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
// 增加流量
|
// IncreaseHourlyStat 增加流量
|
||||||
func (this *TrafficHourlyStatDAO) IncreaseHourlyBytes(tx *dbs.Tx, hour string, bytes int64) error {
|
func (this *TrafficHourlyStatDAO) IncreaseHourlyStat(tx *dbs.Tx, hour string, bytes int64, cachedBytes int64, countRequests int64, countCachedRequests int64) error {
|
||||||
if len(hour) != 10 {
|
if len(hour) != 10 {
|
||||||
return errors.New("invalid hour '" + hour + "'")
|
return errors.New("invalid hour '" + hour + "'")
|
||||||
}
|
}
|
||||||
err := this.Query(tx).
|
err := this.Query(tx).
|
||||||
Param("bytes", bytes).
|
Param("bytes", bytes).
|
||||||
|
Param("cachedBytes", cachedBytes).
|
||||||
|
Param("countRequests", countRequests).
|
||||||
|
Param("countCachedRequests", countCachedRequests).
|
||||||
InsertOrUpdateQuickly(maps.Map{
|
InsertOrUpdateQuickly(maps.Map{
|
||||||
"hour": hour,
|
"hour": hour,
|
||||||
"bytes": bytes,
|
"bytes": bytes,
|
||||||
|
"cachedBytes": cachedBytes,
|
||||||
|
"countRequests": countRequests,
|
||||||
|
"countCachedRequests": countCachedRequests,
|
||||||
}, maps.Map{
|
}, maps.Map{
|
||||||
"bytes": dbs.SQL("bytes+:bytes"),
|
"bytes": dbs.SQL("bytes+:bytes"),
|
||||||
|
"cachedBytes": dbs.SQL("cachedBytes+:cachedBytes"),
|
||||||
|
"countRequests": dbs.SQL("countRequests+:countRequests"),
|
||||||
|
"countCachedRequests": dbs.SQL("countCachedRequests+:countCachedRequests"),
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
@@ -49,11 +76,14 @@ func (this *TrafficHourlyStatDAO) IncreaseHourlyBytes(tx *dbs.Tx, hour string, b
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// 获取日期之间统计
|
// FindHourlyStats 获取小时之间统计
|
||||||
func (this *TrafficHourlyStatDAO) FindHourlyStats(tx *dbs.Tx, hourFrom string, hourTo string) (result []*TrafficHourlyStat, err error) {
|
func (this *TrafficHourlyStatDAO) FindHourlyStats(tx *dbs.Tx, hourFrom string, hourTo string) (result []*TrafficHourlyStat, err error) {
|
||||||
ones, err := this.Query(tx).
|
ones, err := this.Query(tx).
|
||||||
Between("hour", hourFrom, hourTo).
|
Between("hour", hourFrom, hourTo).
|
||||||
FindAll()
|
FindAll()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
hourMap := map[string]*TrafficHourlyStat{} // hour => Stat
|
hourMap := map[string]*TrafficHourlyStat{} // hour => Stat
|
||||||
for _, one := range ones {
|
for _, one := range ones {
|
||||||
stat := one.(*TrafficHourlyStat)
|
stat := one.(*TrafficHourlyStat)
|
||||||
@@ -73,3 +103,12 @@ func (this *TrafficHourlyStatDAO) FindHourlyStats(tx *dbs.Tx, hourFrom string, h
|
|||||||
}
|
}
|
||||||
return result, nil
|
return result, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Clean 清理历史数据
|
||||||
|
func (this *TrafficHourlyStatDAO) Clean(tx *dbs.Tx, days int) error {
|
||||||
|
var hour = timeutil.Format("Ymd00", time.Now().AddDate(0, 0, -days))
|
||||||
|
_, err := this.Query(tx).
|
||||||
|
Lt("hour", hour).
|
||||||
|
Delete()
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,16 +1,22 @@
|
|||||||
package stats
|
package stats
|
||||||
|
|
||||||
// 总的流量统计(按小时)
|
// TrafficHourlyStat 总的流量统计(按小时)
|
||||||
type TrafficHourlyStat struct {
|
type TrafficHourlyStat struct {
|
||||||
Id uint64 `field:"id"` // ID
|
Id uint64 `field:"id"` // ID
|
||||||
Hour string `field:"hour"` // YYYYMMDDHH
|
Hour string `field:"hour"` // YYYYMMDDHH
|
||||||
Bytes uint64 `field:"bytes"` // 流量字节
|
Bytes uint64 `field:"bytes"` // 流量字节
|
||||||
|
CachedBytes uint64 `field:"cachedBytes"` // 缓存流量
|
||||||
|
CountRequests uint64 `field:"countRequests"` // 请求数
|
||||||
|
CountCachedRequests uint64 `field:"countCachedRequests"` // 缓存请求数
|
||||||
}
|
}
|
||||||
|
|
||||||
type TrafficHourlyStatOperator struct {
|
type TrafficHourlyStatOperator struct {
|
||||||
Id interface{} // ID
|
Id interface{} // ID
|
||||||
Hour interface{} // YYYYMMDDHH
|
Hour interface{} // YYYYMMDDHH
|
||||||
Bytes interface{} // 流量字节
|
Bytes interface{} // 流量字节
|
||||||
|
CachedBytes interface{} // 缓存流量
|
||||||
|
CountRequests interface{} // 请求数
|
||||||
|
CountCachedRequests interface{} // 缓存请求数
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewTrafficHourlyStatOperator() *TrafficHourlyStatOperator {
|
func NewTrafficHourlyStatOperator() *TrafficHourlyStatOperator {
|
||||||
|
|||||||
@@ -156,9 +156,12 @@ func (this *UserDAO) UpdateUserLogin(tx *dbs.Tx, userId int64, username string,
|
|||||||
}
|
}
|
||||||
|
|
||||||
// CountAllEnabledUsers 计算用户数量
|
// CountAllEnabledUsers 计算用户数量
|
||||||
func (this *UserDAO) CountAllEnabledUsers(tx *dbs.Tx, keyword string) (int64, error) {
|
func (this *UserDAO) CountAllEnabledUsers(tx *dbs.Tx, clusterId int64, keyword string) (int64, error) {
|
||||||
query := this.Query(tx)
|
query := this.Query(tx)
|
||||||
query.State(UserStateEnabled)
|
query.State(UserStateEnabled)
|
||||||
|
if clusterId > 0 {
|
||||||
|
query.Attr("clusterId", clusterId)
|
||||||
|
}
|
||||||
if len(keyword) > 0 {
|
if len(keyword) > 0 {
|
||||||
query.Where("(username LIKE :keyword OR fullname LIKE :keyword OR mobile LIKE :keyword OR email LIKE :keyword OR tel LIKE :keyword OR remark LIKE :keyword)").
|
query.Where("(username LIKE :keyword OR fullname LIKE :keyword OR mobile LIKE :keyword OR email LIKE :keyword OR tel LIKE :keyword OR remark LIKE :keyword)").
|
||||||
Param("keyword", "%"+keyword+"%")
|
Param("keyword", "%"+keyword+"%")
|
||||||
@@ -167,9 +170,12 @@ func (this *UserDAO) CountAllEnabledUsers(tx *dbs.Tx, keyword string) (int64, er
|
|||||||
}
|
}
|
||||||
|
|
||||||
// ListEnabledUsers 列出单页用户
|
// ListEnabledUsers 列出单页用户
|
||||||
func (this *UserDAO) ListEnabledUsers(tx *dbs.Tx, keyword string, offset int64, size int64) (result []*User, err error) {
|
func (this *UserDAO) ListEnabledUsers(tx *dbs.Tx, clusterId int64, keyword string, offset int64, size int64) (result []*User, err error) {
|
||||||
query := this.Query(tx)
|
query := this.Query(tx)
|
||||||
query.State(UserStateEnabled)
|
query.State(UserStateEnabled)
|
||||||
|
if clusterId > 0 {
|
||||||
|
query.Attr("clusterId", clusterId)
|
||||||
|
}
|
||||||
if len(keyword) > 0 {
|
if len(keyword) > 0 {
|
||||||
query.Where("(username LIKE :keyword OR fullname LIKE :keyword OR mobile LIKE :keyword OR email LIKE :keyword OR tel LIKE :keyword OR remark LIKE :keyword)").
|
query.Where("(username LIKE :keyword OR fullname LIKE :keyword OR mobile LIKE :keyword OR email LIKE :keyword OR tel LIKE :keyword OR remark LIKE :keyword)").
|
||||||
Param("keyword", "%"+keyword+"%")
|
Param("keyword", "%"+keyword+"%")
|
||||||
|
|||||||
@@ -464,6 +464,18 @@ func (this *APINode) registerServices(server *grpc.Server) {
|
|||||||
this.rest(instance)
|
this.rest(instance)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
instance := this.serviceInstance(&services.ServerStatBoardService{}).(*services.ServerStatBoardService)
|
||||||
|
pb.RegisterServerStatBoardServiceServer(server, instance)
|
||||||
|
this.rest(instance)
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
instance := this.serviceInstance(&services.ServerStatBoardChartService{}).(*services.ServerStatBoardChartService)
|
||||||
|
pb.RegisterServerStatBoardChartServiceServer(server, instance)
|
||||||
|
this.rest(instance)
|
||||||
|
}
|
||||||
|
|
||||||
// TODO check service names
|
// TODO check service names
|
||||||
for serviceName := range server.GetServiceInfo() {
|
for serviceName := range server.GetServiceInfo() {
|
||||||
index := strings.LastIndex(serviceName, ".")
|
index := strings.LastIndex(serviceName, ".")
|
||||||
|
|||||||
@@ -493,7 +493,7 @@ func (this *AdminService) ComposeAdminDashboard(ctx context.Context, req *pb.Com
|
|||||||
resp.CountServers = countServers
|
resp.CountServers = countServers
|
||||||
|
|
||||||
// 用户数
|
// 用户数
|
||||||
countUsers, err := models.SharedUserDAO.CountAllEnabledUsers(tx, "")
|
countUsers, err := models.SharedUserDAO.CountAllEnabledUsers(tx, 0, "")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -163,6 +163,7 @@ func (this *BaseService) ValidateNodeId(ctx context.Context, roles ...rpcutils.U
|
|||||||
return rpcutils.UserTypeNone, 0, errors.New("authenticate timeout, please check your system clock")
|
return rpcutils.UserTypeNone, 0, errors.New("authenticate timeout, please check your system clock")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
role = apiToken.Role
|
||||||
switch apiToken.Role {
|
switch apiToken.Role {
|
||||||
case rpcutils.UserTypeNode:
|
case rpcutils.UserTypeNode:
|
||||||
nodeIntId, err = models.SharedNodeDAO.FindEnabledNodeIdWithUniqueId(nil, nodeId)
|
nodeIntId, err = models.SharedNodeDAO.FindEnabledNodeIdWithUniqueId(nil, nodeId)
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ package services
|
|||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"github.com/TeaOSLab/EdgeAPI/internal/db/models"
|
"github.com/TeaOSLab/EdgeAPI/internal/db/models"
|
||||||
|
"github.com/TeaOSLab/EdgeAPI/internal/db/models/nameservers"
|
||||||
rpcutils "github.com/TeaOSLab/EdgeAPI/internal/rpc/utils"
|
rpcutils "github.com/TeaOSLab/EdgeAPI/internal/rpc/utils"
|
||||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||||
)
|
)
|
||||||
@@ -15,13 +16,25 @@ type NodeValueService struct {
|
|||||||
|
|
||||||
// CreateNodeValue 记录数据
|
// CreateNodeValue 记录数据
|
||||||
func (this *NodeValueService) CreateNodeValue(ctx context.Context, req *pb.CreateNodeValueRequest) (*pb.RPCSuccess, error) {
|
func (this *NodeValueService) CreateNodeValue(ctx context.Context, req *pb.CreateNodeValueRequest) (*pb.RPCSuccess, error) {
|
||||||
role, nodeId, err := rpcutils.ValidateRequest(ctx, rpcutils.UserTypeNode)
|
role, nodeId, err := rpcutils.ValidateRequest(ctx, rpcutils.UserTypeNode, rpcutils.UserTypeDNS)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
var tx = this.NullTx()
|
var tx = this.NullTx()
|
||||||
err = models.SharedNodeValueDAO.CreateValue(tx, role, nodeId, req.Item, req.ValueJSON, req.CreatedAt)
|
|
||||||
|
var clusterId int64
|
||||||
|
switch role {
|
||||||
|
case rpcutils.UserTypeNode:
|
||||||
|
clusterId, err = models.SharedNodeDAO.FindNodeClusterId(tx, nodeId)
|
||||||
|
case rpcutils.UserTypeDNS:
|
||||||
|
clusterId, err = nameservers.SharedNSNodeDAO.FindNodeClusterId(tx, nodeId)
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
err = models.SharedNodeValueDAO.CreateValue(tx, clusterId, role, nodeId, req.Item, req.ValueJSON, req.CreatedAt)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,7 +3,9 @@ package services
|
|||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"github.com/TeaOSLab/EdgeAPI/internal/db/models"
|
"github.com/TeaOSLab/EdgeAPI/internal/db/models"
|
||||||
|
"github.com/TeaOSLab/EdgeAPI/internal/db/models/nameservers"
|
||||||
"github.com/TeaOSLab/EdgeAPI/internal/db/models/stats"
|
"github.com/TeaOSLab/EdgeAPI/internal/db/models/stats"
|
||||||
|
rpcutils "github.com/TeaOSLab/EdgeAPI/internal/rpc/utils"
|
||||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||||
timeutil "github.com/iwind/TeaGo/utils/time"
|
timeutil "github.com/iwind/TeaGo/utils/time"
|
||||||
"math"
|
"math"
|
||||||
@@ -17,7 +19,7 @@ type ServerDailyStatService struct {
|
|||||||
|
|
||||||
// UploadServerDailyStats 上传统计
|
// UploadServerDailyStats 上传统计
|
||||||
func (this *ServerDailyStatService) UploadServerDailyStats(ctx context.Context, req *pb.UploadServerDailyStatsRequest) (*pb.RPCSuccess, error) {
|
func (this *ServerDailyStatService) UploadServerDailyStats(ctx context.Context, req *pb.UploadServerDailyStatsRequest) (*pb.RPCSuccess, error) {
|
||||||
nodeId, err := this.ValidateNode(ctx)
|
role, nodeId, err := this.ValidateNodeId(ctx, rpcutils.UserTypeNode, rpcutils.UserTypeDNS)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@@ -29,35 +31,50 @@ func (this *ServerDailyStatService) UploadServerDailyStats(ctx context.Context,
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var clusterId int64
|
||||||
|
switch role {
|
||||||
|
case rpcutils.UserTypeNode:
|
||||||
|
clusterId, err = models.SharedNodeDAO.FindNodeClusterId(tx, nodeId)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
case rpcutils.UserTypeDNS:
|
||||||
|
clusterId, err = nameservers.SharedNSNodeDAO.FindNodeClusterId(tx, nodeId)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// 写入其他统计表
|
// 写入其他统计表
|
||||||
// TODO 将来改成每小时入库一次
|
// TODO 将来改成每小时入库一次
|
||||||
for _, stat := range req.Stats {
|
for _, stat := range req.Stats {
|
||||||
// 总体流量(按天)
|
// 总体流量(按天)
|
||||||
err = stats.SharedTrafficDailyStatDAO.IncreaseDailyBytes(tx, timeutil.FormatTime("Ymd", stat.CreatedAt), stat.Bytes)
|
err = stats.SharedTrafficDailyStatDAO.IncreaseDailyStat(tx, timeutil.FormatTime("Ymd", stat.CreatedAt), stat.Bytes, stat.CachedBytes, stat.CountRequests, stat.CountCachedRequests)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// 总体统计(按小时)
|
// 总体统计(按小时)
|
||||||
err = stats.SharedTrafficHourlyStatDAO.IncreaseHourlyBytes(tx, timeutil.FormatTime("YmdH", stat.CreatedAt), stat.Bytes)
|
err = stats.SharedTrafficHourlyStatDAO.IncreaseHourlyStat(tx, timeutil.FormatTime("YmdH", stat.CreatedAt), stat.Bytes, stat.CachedBytes, stat.CountRequests, stat.CountCachedRequests)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// 节点流量
|
// 节点流量
|
||||||
if nodeId > 0 {
|
if nodeId > 0 {
|
||||||
err = stats.SharedNodeTrafficDailyStatDAO.IncreaseDailyBytes(tx, nodeId, timeutil.FormatTime("Ymd", stat.CreatedAt), stat.Bytes)
|
err = stats.SharedNodeTrafficDailyStatDAO.IncreaseDailyStat(tx, clusterId, role, nodeId, timeutil.FormatTime("Ymd", stat.CreatedAt), stat.Bytes, stat.CachedBytes, stat.CountRequests, stat.CountCachedRequests)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
err = stats.SharedNodeTrafficHourlyStatDAO.IncreaseHourlyStat(tx, clusterId, role, nodeId, timeutil.FormatTime("YmdH", stat.CreatedAt), stat.Bytes, stat.CachedBytes, stat.CountRequests, stat.CountCachedRequests)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// 集群流量
|
// 集群流量
|
||||||
clusterId, err := models.SharedNodeDAO.FindNodeClusterId(tx, nodeId)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
if clusterId > 0 {
|
if clusterId > 0 {
|
||||||
err = stats.SharedNodeClusterTrafficDailyStatDAO.IncreaseDailyBytes(tx, clusterId, timeutil.FormatTime("Ymd", stat.CreatedAt), stat.Bytes)
|
err = stats.SharedNodeClusterTrafficDailyStatDAO.IncreaseDailyStat(tx, clusterId, timeutil.FormatTime("Ymd", stat.CreatedAt), stat.Bytes, stat.CachedBytes, stat.CountRequests, stat.CountCachedRequests)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@@ -65,6 +82,14 @@ func (this *ServerDailyStatService) UploadServerDailyStats(ctx context.Context,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 域名统计
|
||||||
|
for _, stat := range req.DomainStats {
|
||||||
|
err := stats.SharedServerDomainHourlyStatDAO.IncreaseHourlyStat(tx, clusterId, nodeId, stat.ServerId, stat.Domain, timeutil.FormatTime("YmdH", stat.CreatedAt), stat.Bytes, stat.CachedBytes, stat.CountRequests, stat.CountCachedRequests)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return this.Success()
|
return this.Success()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
199
internal/rpc/services/service_server_stat_board.go
Normal file
199
internal/rpc/services/service_server_stat_board.go
Normal file
@@ -0,0 +1,199 @@
|
|||||||
|
// Copyright 2021 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
|
||||||
|
|
||||||
|
package services
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"encoding/json"
|
||||||
|
"github.com/TeaOSLab/EdgeAPI/internal/db/models"
|
||||||
|
"github.com/TeaOSLab/EdgeAPI/internal/db/models/stats"
|
||||||
|
"github.com/TeaOSLab/EdgeCommon/pkg/configutils"
|
||||||
|
"github.com/TeaOSLab/EdgeCommon/pkg/nodeconfigs"
|
||||||
|
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||||
|
"github.com/iwind/TeaGo/types"
|
||||||
|
timeutil "github.com/iwind/TeaGo/utils/time"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
// ServerStatBoardService 统计看板条目
|
||||||
|
type ServerStatBoardService struct {
|
||||||
|
BaseService
|
||||||
|
}
|
||||||
|
|
||||||
|
// FindAllEnabledServerStatBoards 读取所有看板
|
||||||
|
func (this *ServerStatBoardService) FindAllEnabledServerStatBoards(ctx context.Context, req *pb.FindAllEnabledServerStatBoardsRequest) (*pb.FindAllEnabledServerStatBoardsResponse, error) {
|
||||||
|
_, err := this.ValidateAdmin(ctx, 0)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
var tx = this.NullTx()
|
||||||
|
boards, err := models.SharedServerStatBoardDAO.FindAllEnabledBoards(tx, req.NodeClusterId)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
var pbBoards = []*pb.ServerStatBoard{}
|
||||||
|
for _, board := range boards {
|
||||||
|
pbBoards = append(pbBoards, &pb.ServerStatBoard{
|
||||||
|
Id: int64(board.Id),
|
||||||
|
Name: board.Name,
|
||||||
|
IsOn: board.IsOn == 1,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
return &pb.FindAllEnabledServerStatBoardsResponse{
|
||||||
|
ServerStatBoards: pbBoards,
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// ComposeServerStatNodeClusterBoard 组合看板数据
|
||||||
|
func (this *ServerStatBoardService) ComposeServerStatNodeClusterBoard(ctx context.Context, req *pb.ComposeServerStatNodeClusterBoardRequest) (*pb.ComposeServerStatNodeClusterBoardResponse, error) {
|
||||||
|
_, err := this.ValidateAdmin(ctx, 0)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
var tx = this.NullTx()
|
||||||
|
var result = &pb.ComposeServerStatNodeClusterBoardResponse{}
|
||||||
|
|
||||||
|
// 统计数字
|
||||||
|
countActiveNodes, err := models.SharedNodeDAO.CountAllEnabledNodesMatch(tx, req.NodeClusterId, configutils.BoolStateAll, configutils.BoolStateYes, "", 0, 0)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
result.CountActiveNodes = countActiveNodes
|
||||||
|
|
||||||
|
countInactiveNodes, err := models.SharedNodeDAO.CountAllEnabledNodesMatch(tx, req.NodeClusterId, configutils.BoolStateAll, configutils.BoolStateNo, "", 0, 0)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
result.CountInactiveNodes = countInactiveNodes
|
||||||
|
|
||||||
|
countUsers, err := models.SharedUserDAO.CountAllEnabledUsers(tx, req.NodeClusterId, "")
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
result.CountUsers = countUsers
|
||||||
|
|
||||||
|
countServers, err := models.SharedServerDAO.CountAllEnabledServersWithNodeClusterId(tx, req.NodeClusterId)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
result.CountServers = countServers
|
||||||
|
|
||||||
|
// 按日流量统计
|
||||||
|
dayFrom := timeutil.Format("Ymd", time.Now().AddDate(0, 0, -14))
|
||||||
|
dailyTrafficStats, err := stats.SharedNodeClusterTrafficDailyStatDAO.FindDailyStats(tx, req.NodeClusterId, dayFrom, timeutil.Format("Ymd"))
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
for _, stat := range dailyTrafficStats {
|
||||||
|
result.DailyTrafficStats = append(result.DailyTrafficStats, &pb.ComposeServerStatNodeClusterBoardResponse_DailyTrafficStat{
|
||||||
|
Day: stat.Day,
|
||||||
|
Bytes: int64(stat.Bytes),
|
||||||
|
CachedBytes: int64(stat.CachedBytes),
|
||||||
|
CountRequests: int64(stat.CountRequests),
|
||||||
|
CountCachedRequests: int64(stat.CountCachedRequests),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 小时流量统计
|
||||||
|
hourFrom := timeutil.Format("YmdH", time.Now().Add(-23*time.Hour))
|
||||||
|
hourTo := timeutil.Format("YmdH")
|
||||||
|
hourlyTrafficStats, err := stats.SharedNodeTrafficHourlyStatDAO.FindHourlyStatsWithClusterId(tx, req.NodeClusterId, hourFrom, hourTo)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
for _, stat := range hourlyTrafficStats {
|
||||||
|
result.HourlyTrafficStats = append(result.HourlyTrafficStats, &pb.ComposeServerStatNodeClusterBoardResponse_HourlyTrafficStat{
|
||||||
|
Hour: stat.Hour,
|
||||||
|
Bytes: int64(stat.Bytes),
|
||||||
|
CachedBytes: int64(stat.CachedBytes),
|
||||||
|
CountRequests: int64(stat.CountRequests),
|
||||||
|
CountCachedRequests: int64(stat.CountCachedRequests),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 节点排行
|
||||||
|
topNodeStats, err := stats.SharedNodeTrafficHourlyStatDAO.FindTopNodeStatsWithClusterId(tx, req.NodeClusterId, hourFrom, hourTo)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
for _, stat := range topNodeStats {
|
||||||
|
nodeName, err := models.SharedNodeDAO.FindNodeName(tx, int64(stat.NodeId))
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if len(nodeName) == 0 {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
result.TopNodeStats = append(result.TopNodeStats, &pb.ComposeServerStatNodeClusterBoardResponse_NodeStat{
|
||||||
|
NodeId: int64(stat.NodeId),
|
||||||
|
NodeName: nodeName,
|
||||||
|
CountRequests: int64(stat.CountRequests),
|
||||||
|
Bytes: int64(stat.Bytes),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 域名排行
|
||||||
|
topDomainStats, err := stats.SharedServerDomainHourlyStatDAO.FindTopDomainStatsWithClusterId(tx, req.NodeClusterId, hourFrom, hourTo)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
for _, stat := range topDomainStats {
|
||||||
|
result.TopDomainStats = append(result.TopDomainStats, &pb.ComposeServerStatNodeClusterBoardResponse_DomainStat{
|
||||||
|
ServerId: int64(stat.ServerId),
|
||||||
|
Domain: stat.Domain,
|
||||||
|
CountRequests: int64(stat.CountRequests),
|
||||||
|
Bytes: int64(stat.Bytes),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// CPU、内存、负载
|
||||||
|
cpuValues, err := models.SharedNodeValueDAO.ListValuesWithClusterId(tx, req.NodeClusterId, "node", nodeconfigs.NodeValueItemCPU, "usage", nodeconfigs.NodeValueRangeMinute)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
for _, v := range cpuValues {
|
||||||
|
valueJSON, err := json.Marshal(types.Float32(v.Value))
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
result.CpuNodeValues = append(result.CpuNodeValues, &pb.NodeValue{
|
||||||
|
ValueJSON: valueJSON,
|
||||||
|
CreatedAt: int64(v.CreatedAt),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
memoryValues, err := models.SharedNodeValueDAO.ListValuesWithClusterId(tx, req.NodeClusterId, "node", nodeconfigs.NodeValueItemMemory, "usage", nodeconfigs.NodeValueRangeMinute)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
for _, v := range memoryValues {
|
||||||
|
valueJSON, err := json.Marshal(types.Float32(v.Value))
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
result.MemoryNodeValues = append(result.MemoryNodeValues, &pb.NodeValue{
|
||||||
|
ValueJSON: valueJSON,
|
||||||
|
CreatedAt: int64(v.CreatedAt),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
loadValues, err := models.SharedNodeValueDAO.ListValuesWithClusterId(tx, req.NodeClusterId, "node", nodeconfigs.NodeValueItemLoad, "load5m", nodeconfigs.NodeValueRangeMinute)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
for _, v := range loadValues {
|
||||||
|
valueJSON, err := json.Marshal(types.Float32(v.Value))
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
result.LoadNodeValues = append(result.LoadNodeValues, &pb.NodeValue{
|
||||||
|
ValueJSON: valueJSON,
|
||||||
|
CreatedAt: int64(v.CreatedAt),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
return result, nil
|
||||||
|
}
|
||||||
107
internal/rpc/services/service_server_stat_board_chart.go
Normal file
107
internal/rpc/services/service_server_stat_board_chart.go
Normal file
@@ -0,0 +1,107 @@
|
|||||||
|
// Copyright 2021 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
|
||||||
|
|
||||||
|
package services
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"github.com/TeaOSLab/EdgeAPI/internal/db/models"
|
||||||
|
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||||
|
"github.com/iwind/TeaGo/types"
|
||||||
|
)
|
||||||
|
|
||||||
|
// ServerStatBoardChartService 统计看板条目
|
||||||
|
type ServerStatBoardChartService struct {
|
||||||
|
BaseService
|
||||||
|
}
|
||||||
|
|
||||||
|
// EnableServerStatBoardChart 添加图表
|
||||||
|
func (this *ServerStatBoardChartService) EnableServerStatBoardChart(ctx context.Context, req *pb.EnableServerStatBoardChartRequest) (*pb.RPCSuccess, error) {
|
||||||
|
_, err := this.ValidateAdmin(ctx, 0)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
var tx = this.NullTx()
|
||||||
|
err = models.SharedServerStatBoardChartDAO.EnableChart(tx, req.ServerStatBoardId, req.MetricChartId)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return this.Success()
|
||||||
|
}
|
||||||
|
|
||||||
|
// DisableServerStatBoardChart 取消图表
|
||||||
|
func (this *ServerStatBoardChartService) DisableServerStatBoardChart(ctx context.Context, req *pb.DisableServerStatBoardChartRequest) (*pb.RPCSuccess, error) {
|
||||||
|
_, err := this.ValidateAdmin(ctx, 0)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
var tx = this.NullTx()
|
||||||
|
err = models.SharedServerStatBoardChartDAO.DisableChart(tx, req.ServerStatBoardId, req.MetricChartId)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return this.Success()
|
||||||
|
}
|
||||||
|
|
||||||
|
// FindAllEnabledServerStatBoardCharts 读取看板中的图表
|
||||||
|
func (this *ServerStatBoardChartService) FindAllEnabledServerStatBoardCharts(ctx context.Context, req *pb.FindAllEnabledServerStatBoardChartsRequest) (*pb.FindAllEnabledServerStatBoardChartsResponse, error) {
|
||||||
|
_, err := this.ValidateAdmin(ctx, 0)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
var tx = this.NullTx()
|
||||||
|
charts, err := models.SharedServerStatBoardChartDAO.FindAllEnabledCharts(tx, req.ServerStatBoardId)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
var pbCharts []*pb.ServerStatBoardChart
|
||||||
|
for _, chart := range charts {
|
||||||
|
// 指标图表
|
||||||
|
metricChart, err := models.SharedMetricChartDAO.FindEnabledMetricChart(tx, int64(chart.ChartId))
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if metricChart == nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
// 指标
|
||||||
|
metricItem, err := models.SharedMetricItemDAO.FindEnabledMetricItem(tx, int64(chart.ItemId))
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if metricItem == nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
pbCharts = append(pbCharts, &pb.ServerStatBoardChart{
|
||||||
|
Id: int64(chart.Id),
|
||||||
|
MetricChart: &pb.MetricChart{
|
||||||
|
Id: int64(metricChart.Id),
|
||||||
|
Name: metricChart.Name,
|
||||||
|
Type: metricChart.Type,
|
||||||
|
WidthDiv: types.Int32(metricChart.WidthDiv),
|
||||||
|
ParamsJSON: nil,
|
||||||
|
IsOn: metricChart.IsOn == 1,
|
||||||
|
MaxItems: types.Int32(metricChart.MaxItems),
|
||||||
|
MetricItem: &pb.MetricItem{
|
||||||
|
Id: int64(metricItem.Id),
|
||||||
|
IsOn: metricItem.IsOn == 1,
|
||||||
|
Code: metricItem.Code,
|
||||||
|
Category: metricItem.Category,
|
||||||
|
Name: metricItem.Name,
|
||||||
|
Keys: metricItem.DecodeKeys(),
|
||||||
|
Period: types.Int32(metricItem.Period),
|
||||||
|
PeriodUnit: metricItem.PeriodUnit,
|
||||||
|
Value: metricItem.Value,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
return &pb.FindAllEnabledServerStatBoardChartsResponse{ServerStatBoardCharts: pbCharts}, nil
|
||||||
|
}
|
||||||
@@ -99,7 +99,7 @@ func (this *UserService) CountAllEnabledUsers(ctx context.Context, req *pb.Count
|
|||||||
|
|
||||||
tx := this.NullTx()
|
tx := this.NullTx()
|
||||||
|
|
||||||
count, err := models.SharedUserDAO.CountAllEnabledUsers(tx, req.Keyword)
|
count, err := models.SharedUserDAO.CountAllEnabledUsers(tx, 0, req.Keyword)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@@ -115,7 +115,7 @@ func (this *UserService) ListEnabledUsers(ctx context.Context, req *pb.ListEnabl
|
|||||||
|
|
||||||
tx := this.NullTx()
|
tx := this.NullTx()
|
||||||
|
|
||||||
users, err := models.SharedUserDAO.ListEnabledUsers(tx, req.Keyword, req.Offset, req.Size)
|
users, err := models.SharedUserDAO.ListEnabledUsers(tx, 0, req.Keyword, req.Offset, req.Size)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user