134 lines
3.6 KiB
Go
134 lines
3.6 KiB
Go
package monitor
|
|
|
|
import (
|
|
"backend/Type"
|
|
"backend/feishu"
|
|
"backend/model"
|
|
"backend/util"
|
|
"fmt"
|
|
"log"
|
|
"time"
|
|
)
|
|
|
|
func UserAliveMonitor(AppId int) {
|
|
AppConfig, _ := util.GetAppConfig(AppId)
|
|
Db := util.MPool.GetTopicDB(AppConfig.Topic)
|
|
defer Db.Close()
|
|
for {
|
|
//now := time.Now()
|
|
//next := now.Truncate(time.Hour).Add(time.Hour)
|
|
// time.Sleep(time.Until(next))
|
|
|
|
for {
|
|
// time window: the hour that just finished
|
|
endT := time.Now().Truncate(time.Hour)
|
|
startT := endT.Add(-time.Hour)
|
|
yStartT := startT.Add(-24 * time.Hour)
|
|
yEndT := endT.Add(-24 * time.Hour)
|
|
|
|
start := startT.Unix()
|
|
end := endT.Unix()
|
|
yStart := yStartT.Unix()
|
|
yEnd := yEndT.Unix()
|
|
|
|
var curCount, yCount int64
|
|
if err := Db.QueryRow("SELECT COUNT(DISTINCT Uid) FROM log_event WHERE Timestamp>=? AND Timestamp<?", start, end).Scan(&curCount); err != nil {
|
|
log.Printf("monitor current count query error: %v", err)
|
|
time.Sleep(time.Hour)
|
|
continue
|
|
}
|
|
if err := Db.QueryRow("SELECT COUNT(DISTINCT Uid) FROM log_event WHERE Timestamp>=? AND Timestamp<?", yStart, yEnd).Scan(&yCount); err != nil {
|
|
log.Printf("monitor yesterday count query error: %v", err)
|
|
time.Sleep(time.Hour)
|
|
continue
|
|
}
|
|
|
|
if yCount > 0 {
|
|
drop := float64(yCount-curCount) / float64(yCount)
|
|
if drop >= 0.3 && (yCount-curCount) >= int64(10) {
|
|
feishu.SendNoticeMsg("meowment", "用户存活监控",
|
|
fmt.Sprintf("监控时间段: %s ~ %s\n昨日活跃用户数: %d\n当前活跃用户数: %d\n用户流失率: %.2f%%",
|
|
startT.Format("2006-01-02 15:04:05"),
|
|
endT.Format("2006-01-02 15:04:05"),
|
|
yCount,
|
|
curCount,
|
|
drop*100))
|
|
}
|
|
}
|
|
|
|
time.Sleep(time.Until(time.Now().Truncate(time.Hour).Add(time.Hour)))
|
|
}
|
|
}
|
|
}
|
|
|
|
func ServerInfoMonitor() {
|
|
for {
|
|
now := time.Now()
|
|
next := now.Truncate(1 * time.Minute).Add(1 * time.Minute)
|
|
time.Sleep(time.Until(next))
|
|
monitorServerInfo()
|
|
}
|
|
}
|
|
|
|
func monitorServerInfo() {
|
|
Db := util.MPool.GetGameDB()
|
|
var server []*Type.ServerInfo
|
|
defer Db.Close()
|
|
err := Db.Select(&server, "SELECT `AppId`, `ServerId`, `ServerName`, `Status`, `CreateTime`, `OpenServerTime` FROM server ")
|
|
if err != nil {
|
|
return
|
|
}
|
|
for _, v := range server {
|
|
if v.Status == 2 || v.Status == 3 { // 维护中或停用跳过
|
|
continue
|
|
}
|
|
go func(v *Type.ServerInfo) {
|
|
tmpDb := util.MPool.GetGameDB()
|
|
defer tmpDb.Close()
|
|
res, err := model.GetServerInfo(v.AppId, v.ServerId)
|
|
if err != nil {
|
|
// tmpDb.Exec("update server set Status=0 where AppId=? and ServerId=?", v.AppId, v.ServerId)
|
|
return
|
|
}
|
|
serverInfo := res.(map[string]interface{})
|
|
free_mem := util.Int(serverInfo["FreeMem"])
|
|
usage_mem := util.Int(serverInfo["Sys"])
|
|
cpu := util.Int(serverInfo["CPU"])
|
|
// compute weight in 0-100 based on free_mem (MB) and cpu (%)
|
|
// heuristic: more free memory and lower CPU -> higher weight
|
|
memCap := 8192 // 8GB as reference cap for normalization
|
|
if free_mem < 0 {
|
|
free_mem = 0
|
|
}
|
|
memScore := 0
|
|
if free_mem >= memCap {
|
|
memScore = 100
|
|
} else {
|
|
memScore = free_mem * 100 / memCap
|
|
}
|
|
|
|
if cpu < 0 {
|
|
cpu = 0
|
|
}
|
|
if cpu > 100 {
|
|
cpu = 100
|
|
}
|
|
cpuScore := 100 - cpu // lower CPU -> higher score
|
|
|
|
// weighted: 60% memory, 40% CPU
|
|
weight := (memScore*6 + cpuScore*4) / 10
|
|
if weight < 0 {
|
|
weight = 0
|
|
}
|
|
if weight > 100 {
|
|
weight = 100
|
|
}
|
|
|
|
// optionally store/update weight
|
|
serverInfo["Weight"] = weight
|
|
// Process serverInfo as needed
|
|
tmpDb.Exec("update server set Status=1, Online=?,free_mem=?,cpu=?,weight=? where AppId=? and ServerId=?", util.Int(serverInfo["PlayerNum"]), usage_mem, cpu, weight, v.AppId, v.ServerId)
|
|
}(v)
|
|
}
|
|
}
|