1
0

marge: 合并代码

This commit is contained in:
TsMask
2023-10-28 20:05:18 +08:00
parent 955aba902b
commit 05559e2c16
29 changed files with 1109 additions and 108 deletions

View File

@@ -114,8 +114,6 @@ func initDefeat(app *gin.Engine) {
func initModulesRoute(app *gin.Engine) {
// 通用模块
common.Setup(app)
// 监控模块
monitor.Setup(app)
// 系统模块
system.Setup(app)
// 网元模块
@@ -124,4 +122,6 @@ func initModulesRoute(app *gin.Engine) {
trace.Setup(app)
// 调度任务模块--暂无接口
crontask.Setup(app)
// 监控模块 - 含调度处理加入队列,放最后
monitor.Setup(app)
}

View File

@@ -12,8 +12,8 @@ import (
func SessionHeader() gin.HandlerFunc {
return func(c *gin.Context) {
// 读取登录生成的会话token
token, err := redis.Get("", "session_token")
if token != "" || err == nil {
token, _ := redis.Get("", "session_token")
if token != "" {
// 过期时间单位秒 配置1800是半小时
expireTime := time.Duration(int64(libConfig.GetExpiresFromConfig())) * time.Second
redis.SetByExpire("", "session_token", token, expireTime)

View File

@@ -23,6 +23,9 @@ func Setup(router *gin.Engine) {
controller.NewIndex.Handler,
)
// 系统可暴露的配置信息
indexGroup.GET("/sys-conf", controller.NewCommont.SysConfig)
// 验证码操作处理
indexGroup.GET("/captchaImage",
middleware.RateLimit(middleware.LimitOption{
@@ -71,7 +74,6 @@ func Setup(router *gin.Engine) {
commonGroup := router.Group("/common")
{
commonGroup.GET("/hash", middleware.PreAuthorize(nil), controller.NewCommont.Hash)
indexGroup.GET("/sysConf", controller.NewCommont.SysConfig)
}
// 文件操作处理

View File

@@ -28,7 +28,7 @@ func (s *CommontController) Hash(c *gin.Context) {
// 系统可暴露的配置信息
//
// GET /sysConf
// GET /sys-conf
func (s *CommontController) SysConfig(c *gin.Context) {
data := s.commontService.SystemConfigInfo()
c.JSON(200, result.OkData(data))

View File

@@ -41,7 +41,7 @@ func (s *RegisterImpl) ValidateCaptcha(code, uuid string) error {
}
verifyKey := cachekey.CAPTCHA_CODE_KEY + uuid
captcha, err := redis.Get("", verifyKey)
if captcha == "" || err != nil {
if err != nil {
return errors.New("验证码已失效")
}
redis.Del("", verifyKey)

View File

@@ -116,7 +116,7 @@ func (s *BarProcessor) Execute(data any) (any, error) {
failureNEs = append(failureNEs, neInfo.NeType+"/"+neInfo.NeId)
continue
}
log.Trace("command output:", out)
log.Tracef("command output:%s", out)
md5Sum, err := global.GetFileMD5Sum(zipFilePath)
if err != nil {

View File

@@ -1,11 +1,8 @@
package crontask
import (
"ems.agt/src/framework/cron"
"ems.agt/src/framework/logger"
"ems.agt/src/modules/crontask/backupEtcFromNE"
"ems.agt/src/modules/crontask/delExpiredNeBackup"
"ems.agt/src/modules/crontask/deleteExpiredRecord"
"ems.agt/src/modules/crontask/processor"
"github.com/gin-gonic/gin"
)
@@ -14,14 +11,13 @@ import (
func Setup(router *gin.Engine) {
logger.Infof("开始加载 ====> crontask 模块路由")
// 初始定时任务队列
InitCronQueue()
// 启动时需要的初始参数
InitLoad()
}
// InitCronQueue 初始定时任务队列
func InitCronQueue() {
// delete expired NE backup file
cron.CreateQueue("delExpiredNeBackup", delExpiredNeBackup.NewProcessor)
cron.CreateQueue("deleteExpiredRecord", deleteExpiredRecord.NewProcessor)
cron.CreateQueue("backupEtcFromNE", backupEtcFromNE.NewProcessor)
// InitLoad 初始参数
func InitLoad() {
// 初始化定时任务处理
processor.InitCronQueue()
}

View File

@@ -5,7 +5,9 @@ import (
"fmt"
"ems.agt/lib/dborm"
"ems.agt/lib/global"
"ems.agt/lib/log"
"ems.agt/restagent/config"
"ems.agt/src/framework/cron"
)
@@ -27,7 +29,7 @@ type BarParams struct {
}
func (s *BarProcessor) Execute(data any) (any, error) {
log.Infof("执行 %d 次,上次进度: %d ", s.count, s.progress)
log.Infof("count: %d progress: %d ", s.count, s.progress)
s.count++
options := data.(cron.JobData)
@@ -39,7 +41,7 @@ func (s *BarProcessor) Execute(data any) (any, error) {
if err == nil {
duration = params.Duration
}
log.Infof("重复 %v 任务ID %s", options.Repeat, sysJob.JobID)
log.Infof("Repeat: %v JobID: %s", options.Repeat, sysJob.JobID)
// // 实现任务处理逻辑
// i := 0
@@ -71,10 +73,22 @@ func (s *BarProcessor) Execute(data any) (any, error) {
// delete expired files in backup directory
// todo ...
// command := fmt.Sprintf("find . -name '*.zip' -mtime +%d -type f -print | xargs rm -rf", duration)
command := fmt.Sprintf("%s/rmexpfiles.sh %s %d", config.GetYamlConfig().OMC.BinDir, config.GetYamlConfig().OMC.Backup, duration)
log.Trace("command:", command)
out, err := global.ExecCmd(command)
if err != nil {
log.Error("Faile to exec command:", err)
return nil, err
}
log.Tracef("command output:%s", out)
// 返回结果,用于记录执行结果
return map[string]any{
"msg": "sucess",
"affected": affected,
"msg": "success",
"cmdoutput": string(out),
"affected": affected,
}, nil
}

View File

@@ -0,0 +1,145 @@
package backupEtcFromNE
import (
"encoding/json"
"fmt"
"os"
"strings"
"time"
"ems.agt/lib/dborm"
"ems.agt/lib/global"
"ems.agt/lib/log"
"ems.agt/restagent/config"
"ems.agt/src/framework/cron"
)
var NewProcessor = &BarProcessor{
progress: 0,
count: 0,
}
// bar 队列任务处理
type BarProcessor struct {
// 任务进度
progress int
// 执行次数
count int
}
type BarParams struct {
Duration int `json:"duration"`
TableName string `json:"tableName"`
ColName string `json:"colName"` // column name of time string
Extras string `json:"extras"` // extras condition for where
}
func (s *BarProcessor) Execute(data any) (any, error) {
log.Infof("execute %dlast progress %d ", s.count, s.progress)
s.count++
options := data.(cron.JobData)
sysJob := options.SysJob
var params BarParams
err := json.Unmarshal([]byte(sysJob.TargetParams), &params)
if err != nil {
return nil, err
}
log.Infof("Repeat %v Job ID %s", options.Repeat, sysJob.JobID)
var nes []dborm.NeInfo
_, err = dborm.XormGetAllNeInfo(&nes)
if err != nil {
return nil, err
}
var successfulNEs, failureNEs []string
for _, neInfo := range nes {
neTypeUpper := strings.ToUpper(neInfo.NeType)
neTypeLower := strings.ToLower(neInfo.NeType)
nePath := fmt.Sprintf("%s/etc/%s", config.GetYamlConfig().OMC.Backup, neTypeLower)
isExist, err := global.PathExists(nePath)
if err != nil {
log.Errorf("Failed to PathExists:", err)
failureNEs = append(failureNEs, neInfo.NeType+"/"+neInfo.NeId)
continue
}
if isExist {
err = os.RemoveAll(nePath)
if err != nil {
log.Errorf("Failed to RemoveAll:", err)
failureNEs = append(failureNEs, neInfo.NeType+"/"+neInfo.NeId)
continue
}
}
err = os.MkdirAll(nePath, os.ModePerm)
if err != nil {
log.Errorf("Failed to MkdirAll:", err)
failureNEs = append(failureNEs, neInfo.NeType+"/"+neInfo.NeId)
continue
}
var scpCmd string
ipType := global.ParseIPAddr(neInfo.Ip)
if neTypeLower != "omc" {
if ipType == global.IsIPv4 {
scpCmd = fmt.Sprintf("scp -r %s@%s:%s/%s/*.yaml %s/etc/%s", config.GetYamlConfig().NE.User,
neInfo.Ip, config.GetYamlConfig().NE.EtcDir,
neTypeLower, config.GetYamlConfig().OMC.Backup, neTypeLower)
} else {
scpCmd = fmt.Sprintf("scp -r %s@[%s]:%s/%s/*.yaml %s/etc/%s", config.GetYamlConfig().NE.User,
neInfo.Ip, config.GetYamlConfig().NE.EtcDir,
neTypeLower, config.GetYamlConfig().OMC.Backup, neTypeLower)
}
} else {
if ipType == global.IsIPv4 {
scpCmd = fmt.Sprintf("scp -r %s@%s:%s/etc/*.yaml %s/etc/%s", config.GetYamlConfig().NE.User,
neInfo.Ip, config.GetYamlConfig().NE.OmcDir, config.GetYamlConfig().OMC.Backup, neTypeLower)
} else {
scpCmd = fmt.Sprintf("scp -r %s@[%s]:%s/etc/*.yaml %s/etc/%s", config.GetYamlConfig().NE.User,
neInfo.Ip, config.GetYamlConfig().NE.OmcDir, config.GetYamlConfig().OMC.Backup, neTypeLower)
}
}
zipFile := fmt.Sprintf("%s-%s-etc-%s.zip", neTypeLower, strings.ToLower(neInfo.NeId), time.Now().Format(global.DateData))
zipFilePath := config.GetYamlConfig().OMC.Backup + "/" + zipFile
zipCmd := fmt.Sprintf("cd %s/etc && zip -r %s %s/*", config.GetYamlConfig().OMC.Backup, zipFilePath, neTypeLower)
command := fmt.Sprintf("%s&&%s", scpCmd, zipCmd)
log.Trace("command:", command)
out, err := global.ExecCmd(command)
if err != nil {
log.Error("Faile to exec command:", err)
failureNEs = append(failureNEs, neInfo.NeType+"/"+neInfo.NeId)
continue
}
log.Trace("command output:", out)
md5Sum, err := global.GetFileMD5Sum(zipFilePath)
if err != nil {
log.Error("Faile to md5sum:", err)
failureNEs = append(failureNEs, neInfo.NeType+"/"+neInfo.NeId)
continue
}
//log.Debug("md5Str:", md5Sum)
path := config.GetYamlConfig().OMC.Backup
neBackup := dborm.NeBackup{NeType: neTypeUpper, NeId: neInfo.NeId, FileName: zipFile, Path: path, Md5Sum: md5Sum}
_, err = dborm.XormInsertTableOne("ne_backup", neBackup)
if err != nil {
log.Error("Faile to XormInsertTableOne:", err)
failureNEs = append(failureNEs, neInfo.NeType+"/"+neInfo.NeId)
continue
}
successfulNEs = append(successfulNEs, neInfo.NeType+"/"+neInfo.NeId)
}
log.Infof("successfulNEs: %s failureNEs: %s", successfulNEs, failureNEs)
// result
return map[string]any{
"successfulNEs": successfulNEs,
"failureNEs": failureNEs,
}, nil
}

View File

@@ -0,0 +1,80 @@
package delExpiredNeBackup
import (
"encoding/json"
"fmt"
"ems.agt/lib/dborm"
"ems.agt/lib/log"
"ems.agt/src/framework/cron"
)
var NewProcessor = &BarProcessor{
progress: 0,
count: 0,
}
// bar 队列任务处理
type BarProcessor struct {
// 任务进度
progress int
// 执行次数
count int
}
type BarParams struct {
Duration int `json:"duration"`
}
func (s *BarProcessor) Execute(data any) (any, error) {
log.Infof("执行 %d 次,上次进度: %d ", s.count, s.progress)
s.count++
options := data.(cron.JobData)
sysJob := options.SysJob
var params BarParams
duration := 60
err := json.Unmarshal([]byte(sysJob.TargetParams), &params)
if err == nil {
duration = params.Duration
}
log.Infof("重复 %v 任务ID %s", options.Repeat, sysJob.JobID)
// // 实现任务处理逻辑
// i := 0
// s.progress = i
// for i < 5 {
// // 获取任务进度
// progress := s.progress
// log.Infof("jonId: %s => 任务进度:%d", sysJob.JobID, progress)
// // 延迟响应
// time.Sleep(time.Second * 2)
// // 程序中途执行错误
// if i == 3 {
// // arr := [1]int{1}
// // arr[i] = 3
// // fmt.Println(arr)
// // return "i = 3"
// panic("程序中途执行错误")
// }
// i++
// // 改变任务进度
// s.progress = i
// }
where := fmt.Sprintf("NOW()>ADDDATE(`create_time`,interval %d day)", duration)
affected, err := dborm.XormDeleteDataByWhere(where, "ne_backup")
if err != nil {
// panic(fmt.Sprintf("Failed to XormDeleteDataByWhere:%v", err))
return nil, err
}
// delete expired files in backup directory
// todo ...
// 返回结果,用于记录执行结果
return map[string]any{
"msg": "sucess",
"affected": affected,
}, nil
}

View File

@@ -0,0 +1,88 @@
package deleteExpiredRecord
import (
"encoding/json"
"fmt"
"ems.agt/lib/dborm"
"ems.agt/lib/log"
"ems.agt/src/framework/cron"
)
var NewProcessor = &BarProcessor{
progress: 0,
count: 0,
}
// bar 队列任务处理
type BarProcessor struct {
// 任务进度
progress int
// 执行次数
count int
}
type BarParams struct {
Duration int `json:"duration"`
TableName string `json:"tableName"`
ColName string `json:"colName"` // column name of time string
Extras string `json:"extras"` // extras condition for where
}
func (s *BarProcessor) Execute(data any) (any, error) {
log.Infof("执行 %d 次,上次进度: %d ", s.count, s.progress)
s.count++
options := data.(cron.JobData)
sysJob := options.SysJob
var params BarParams
err := json.Unmarshal([]byte(sysJob.TargetParams), &params)
if err != nil {
return nil, err
}
//duration = params.Duration
log.Infof("重复 %v 任务ID %s", options.Repeat, sysJob.JobID)
// // 实现任务处理逻辑
// i := 0
// s.progress = i
// for i < 5 {
// // 获取任务进度
// progress := s.progress
// log.Infof("jonId: %s => 任务进度:%d", sysJob.JobID, progress)
// // 延迟响应
// time.Sleep(time.Second * 2)
// // 程序中途执行错误
// if i == 3 {
// // arr := [1]int{1}
// // arr[i] = 3
// // fmt.Println(arr)
// // return "i = 3"
// panic("程序中途执行错误")
// }
// i++
// // 改变任务进度
// s.progress = i
// }
var where string
if params.Extras == "" {
where = fmt.Sprintf("NOW()>ADDDATE(`%s`,interval %d day)", params.ColName, params.Duration)
} else {
where = fmt.Sprintf("NOW()>ADDDATE(`%s`,interval %d day) and %s", params.ColName, params.Duration, params.Extras)
}
affected, err := dborm.XormDeleteDataByWhere(where, params.TableName)
if err != nil {
// panic(fmt.Sprintf("Failed to XormDeleteDataByWhere:%v", err))
return nil, err
}
// 返回结果,用于记录执行结果
return map[string]any{
"msg": "sucess",
"affected": affected,
}, nil
}

View File

@@ -0,0 +1,56 @@
package monitorsysresource
import (
"encoding/json"
"fmt"
"ems.agt/src/framework/cron"
"ems.agt/src/framework/logger"
monitorService "ems.agt/src/modules/monitor/service"
)
var NewProcessor = &MonitorSysResourceProcessor{
monitorService: monitorService.NewMonitorImpl,
count: 0,
openDataCancel: false,
}
// MonitorSysResourceProcessor 系统资源CPU/IO/Netword收集
type MonitorSysResourceProcessor struct {
// 服务器系统相关信息服务
monitorService monitorService.IMonitor
// 执行次数
count int
// 是否已经开启数据通道
openDataCancel bool
}
func (s *MonitorSysResourceProcessor) Execute(data any) (any, error) {
s.count++ // 执行次数加一
options := data.(cron.JobData)
sysJob := options.SysJob
logger.Infof("重复 %v 任务ID %s", options.Repeat, sysJob.JobID)
// 读取参数值
var params struct {
Interval float64 `json:"interval"`
}
err := json.Unmarshal([]byte(sysJob.TargetParams), &params)
if err != nil {
return nil, fmt.Errorf("json params 'interval' err: %v", err)
}
// 避免重复开启chan通道
if !s.openDataCancel {
s.monitorService.RunMonitorDataCancel(false, params.Interval)
s.openDataCancel = true
}
s.monitorService.RunMonitor()
// 返回结果,用于记录执行结果
result := map[string]any{
"count": s.count,
}
return result, nil
}

View File

@@ -0,0 +1,19 @@
package processor
import (
"ems.agt/src/framework/cron"
"ems.agt/src/modules/crontask/processor/backupEtcFromNE"
"ems.agt/src/modules/crontask/processor/delExpiredNeBackup"
"ems.agt/src/modules/crontask/processor/deleteExpiredRecord"
monitorsysresource "ems.agt/src/modules/crontask/processor/monitor_sys_resource"
)
// InitCronQueue 初始定时任务队列
func InitCronQueue() {
// 监控-系统资源
cron.CreateQueue("monitor_sys_resource", monitorsysresource.NewProcessor)
// delete expired NE backup file
cron.CreateQueue("delExpiredNeBackup", delExpiredNeBackup.NewProcessor)
cron.CreateQueue("deleteExpiredRecord", deleteExpiredRecord.NewProcessor)
cron.CreateQueue("backupEtcFromNE", backupEtcFromNE.NewProcessor)
}

View File

@@ -0,0 +1,57 @@
package controller
import (
"ems.agt/src/framework/vo/result"
"ems.agt/src/modules/monitor/service"
"github.com/gin-gonic/gin"
)
// 实例化控制层 MonitorInfoController 结构体
var NewMonitor = &MonitorController{
monitorService: service.NewMonitorImpl,
}
// 服务器资源监控信息
//
// PATH /monitor
type MonitorController struct {
// 服务器系统相关信息服务
monitorService service.IMonitor
}
// 资源监控信息加载
//
// GET /load
func (s *MonitorController) Load(c *gin.Context) {
var querys struct {
// 数据类型all/cpu/memory/io/network
Type string `form:"type" binding:"required,oneof=all cpu memory io network"`
// 开始时间
StartTime int64 `form:"startTime" binding:"required"`
// 结束时间
EndTime int64 `form:"endTime" binding:"required"`
// 网元类型
NeType string `form:"neType"`
// 网元ID
NeID string `form:"neId"`
// 名称networ和iok时有效
Name string `form:"name"`
}
err := c.ShouldBindQuery(&querys)
if err != nil {
c.JSON(400, result.CodeMsg(400, "参数错误"))
return
}
// 查询数据
data := s.monitorService.SelectMonitorInfo(map[string]any{
"type": querys.Type,
"startTime": querys.StartTime,
"endTime": querys.EndTime,
"neType": querys.NeType,
"neId": querys.NeID,
"name": querys.Name,
})
c.JSON(200, result.OkData(data))
}

View File

@@ -0,0 +1,29 @@
package model
// MonitorBase 监控_基本信息 monitor_base
type MonitorBase struct {
// id
ID int64 `json:"id" gorm:"primaryKey"`
// 创建时间
CreateTime int64 `json:"createTime"`
// cpu使用率
CPU float64 `json:"cpu"`
// cpu平均使用率
LoadUsage float64 `json:"loadUsage"`
// cpu使用1分钟
CPULoad1 float64 `json:"cpuLoad1"`
// cpu使用5分钟
CPULoad5 float64 `json:"cpuLoad5"`
// cpu使用15分钟
CPULoad15 float64 `json:"cpuLoad15"`
// 内存使用率
Memory float64 `json:"memory"`
// 网元ID
NeType string `json:"neType"`
// 网元类型
NeID string `json:"neId"`
}
func (MonitorBase) TableName() string {
return "monitor_base"
}

View File

@@ -0,0 +1,27 @@
package model
// MonitorIO 监控_磁盘IO monitor_io
type MonitorIO struct {
// id
ID int64 `json:"id" gorm:"primaryKey"`
// 创建时间
CreateTime int64 `json:"createTime"`
// 磁盘名
Name string `json:"name"`
// 读取K
Read int64 `json:"read"`
// 写入K
Write int64 `json:"write"`
// 次数
Count int64 `json:"count"`
// 耗时
Time int64 `json:"time"`
// 网元ID
NeType string `json:"neType"`
// 网元类型
NeID string `json:"neId"`
}
func (MonitorIO) TableName() string {
return "monitor_io"
}

View File

@@ -0,0 +1,23 @@
package model
// MonitorNetwork 监控_网络IO monitor_network
type MonitorNetwork struct {
// id
ID int64 `json:"id" gorm:"primaryKey"`
// 创建时间
CreateTime int64 `json:"createTime"`
// 网卡名
Name string `json:"name"`
// 上行
Up float64 `json:"up"`
// 下行
Down float64 `json:"down"`
// 网元ID
NeType string `json:"neType"`
// 网元类型
NeID string `json:"neId"`
}
func (MonitorNetwork) TableName() string {
return "monitor_network"
}

View File

@@ -19,6 +19,15 @@ func Setup(router *gin.Engine) {
// 启动时需要的初始参数
InitLoad()
// 服务器资源监控信息
monitorGroup := router.Group("/monitor")
{
monitorGroup.GET("/load",
// middleware.PreAuthorize(nil),
controller.NewMonitor.Load,
)
}
// 服务器服务信息
router.GET("/monitor/system-info",
middleware.PreAuthorize(map[string][]string{"hasPerms": {"monitor:system:info"}}),

View File

@@ -0,0 +1,33 @@
package repository
import "ems.agt/src/modules/monitor/model"
// IMonitor 监控服务资源相关信息 数据接口
type IMonitor interface {
// CreateMonitorBase 创建监控_基本信息
CreateMonitorBase(m model.MonitorBase) error
// DelMonitorBase 删除监控_基本信息
DelMonitorBase(ltTime int64) error
// SelectMonitorBase 查询监控_基本信息
SelectMonitorBase(query map[string]any) []model.MonitorBase
// BatchCreateMonitorIO 批量创建监控_IO
BatchCreateMonitorIO(ioList []model.MonitorIO) error
// DelMonitorIO 删除监控_IO
DelMonitorIO(ltTime int64) error
// SelectMonitorIO 查询监控_IO
SelectMonitorIO(query map[string]any) []model.MonitorIO
// BatchCreateMonitorNet 批量创建监控_网络
BatchCreateMonitorNet(netList []model.MonitorNetwork) error
// DelMonitorNet 删除监控_网络
DelMonitorNet(ltTime int64) error
// SelectMonitorNetwork 查询监控_网络
SelectMonitorNetwork(query map[string]any) []model.MonitorNetwork
}

View File

@@ -0,0 +1,103 @@
package repository
import (
"ems.agt/src/framework/datasource"
"ems.agt/src/framework/logger"
"ems.agt/src/modules/monitor/model"
"gorm.io/gorm"
)
// 实例化数据层 MonitorImpl 结构体
var NewMonitorImpl = &MonitorImpl{
db: datasource.DefaultDB,
}
// MonitorImpl 监控服务资源相关信息 数据层处理
type MonitorImpl struct {
// 数据库实例
db func() *gorm.DB
}
// CreateMonitorBase 创建监控_基本信息
func (r *MonitorImpl) CreateMonitorBase(m model.MonitorBase) error {
return r.db().Create(&m).Error
}
// DelMonitorBase 删除监控_基本信息
func (r *MonitorImpl) DelMonitorBase(ltTime int64) error {
return r.db().Where("create_time < ?", ltTime).Delete(&model.MonitorBase{}).Error
}
// SelectMonitorBase 查询监控_基本信息
func (r *MonitorImpl) SelectMonitorBase(query map[string]any) []model.MonitorBase {
var bases []model.MonitorBase
dbConn := r.db()
if query["neType"] != "" && query["neId"] != "" {
dbConn = dbConn.Where("ne_type = ? and ne_id = ?", query["neType"], query["neId"])
}
dbConn = dbConn.Where("create_time >= ? and create_time <= ?", query["startTime"], query["endTime"])
err := dbConn.Order("create_time desc").Find(&bases).Error
if err != nil {
logger.Errorf("SelectMonitorBase %v", err)
return bases
}
return bases
}
// BatchCreateMonitorIO 批量创建监控_IO
func (r *MonitorImpl) BatchCreateMonitorIO(ioList []model.MonitorIO) error {
return r.db().CreateInBatches(ioList, len(ioList)).Error
}
// DelMonitorIO 删除监控_IO
func (r *MonitorImpl) DelMonitorIO(ltTime int64) error {
return r.db().Where("create_time < ?", ltTime).Delete(&model.MonitorIO{}).Error
}
// SelectMonitorIO 查询监控_IO
func (r *MonitorImpl) SelectMonitorIO(query map[string]any) []model.MonitorIO {
var ios []model.MonitorIO
dbConn := r.db()
if query["name"] != "" {
dbConn = dbConn.Where("name = ?", query["name"])
}
if query["neType"] != "" && query["neId"] != "" {
dbConn = dbConn.Where("ne_type = ? and ne_id = ?", query["neType"], query["neId"])
}
dbConn = dbConn.Where("create_time >= ? and create_time <= ?", query["startTime"], query["endTime"])
err := dbConn.Order("create_time desc").Find(&ios).Error
if err != nil {
logger.Errorf("SelectMonitorIO %v", err)
return ios
}
return ios
}
// BatchCreateMonitorNet 批量创建监控_网络
func (r *MonitorImpl) BatchCreateMonitorNet(netList []model.MonitorNetwork) error {
return r.db().CreateInBatches(netList, len(netList)).Error
}
// DelMonitorNet 删除监控_网络
func (r *MonitorImpl) DelMonitorNet(ltTime int64) error {
return r.db().Where("create_time < ?", ltTime).Delete(&model.MonitorNetwork{}).Error
}
// SelectMonitorNetwork 查询监控_网络
func (r *MonitorImpl) SelectMonitorNetwork(query map[string]any) []model.MonitorNetwork {
var networks []model.MonitorNetwork
dbConn := r.db()
if query["name"] != "" {
dbConn = dbConn.Where("name = ?", query["name"])
}
if query["neType"] != "" && query["neId"] != "" {
dbConn = dbConn.Where("ne_type = ? and ne_id = ?", query["neType"], query["neId"])
}
dbConn = dbConn.Where("create_time >= ? and create_time <= ?", query["startTime"], query["endTime"])
err := dbConn.Order("create_time desc").Find(&networks).Error
if err != nil {
logger.Errorf("SelectMonitorNetwork %v", err)
return networks
}
return networks
}

View File

@@ -0,0 +1,14 @@
package service
// IMonitor 服务器系统相关信息 服务层接口
type IMonitor interface {
// RunMonitor 执行资源监控
RunMonitor()
// RunMonitorDataCancel 启动资源监控数据存储io/network通道 移除之前的chan上下文后在设置新的均值
// interval 采集的平均值(分钟)
RunMonitorDataCancel(removeBefore bool, interval float64)
// SelectMonitorInfo 查询监控资源信息
SelectMonitorInfo(query map[string]any) map[string]MonitorData
}

View File

@@ -0,0 +1,287 @@
package service
import (
"context"
"strconv"
"time"
"ems.agt/src/framework/logger"
"ems.agt/src/modules/monitor/model"
"ems.agt/src/modules/monitor/repository"
systemService "ems.agt/src/modules/system/service"
"github.com/shirou/gopsutil/cpu"
"github.com/shirou/gopsutil/disk"
"github.com/shirou/gopsutil/load"
"github.com/shirou/gopsutil/net"
"github.com/shirou/gopsutil/v3/mem"
)
// 实例化服务层 MonitorImpl 结构体
var NewMonitorImpl = &MonitorImpl{
sysConfigService: systemService.NewSysConfigImpl,
monitorRepository: repository.NewMonitorImpl,
diskIO: make(chan []disk.IOCountersStat, 2),
netIO: make(chan []net.IOCountersStat, 2),
}
// MonitorImpl 服务器系统相关信息 服务层处理
type MonitorImpl struct {
// 参数配置服务
sysConfigService systemService.ISysConfig
// 监控服务资源数据信息
monitorRepository repository.IMonitor
// 磁盘网络IO 数据通道
diskIO chan ([]disk.IOCountersStat)
netIO chan ([]net.IOCountersStat)
}
// RunMonitor 执行资源监控
func (s *MonitorImpl) RunMonitor() {
var itemModel model.MonitorBase
itemModel.CreateTime = time.Now().UnixMilli()
totalPercent, _ := cpu.Percent(3*time.Second, false)
if len(totalPercent) == 1 {
itemModel.CPU = totalPercent[0]
}
cpuCount, _ := cpu.Counts(false)
loadInfo, _ := load.Avg()
itemModel.CPULoad1 = loadInfo.Load1
itemModel.CPULoad5 = loadInfo.Load5
itemModel.CPULoad15 = loadInfo.Load15
itemModel.LoadUsage = loadInfo.Load1 / (float64(cpuCount*2) * 0.75) * 100
memoryInfo, _ := mem.VirtualMemory()
itemModel.Memory = memoryInfo.UsedPercent
if err := s.monitorRepository.CreateMonitorBase(itemModel); err != nil {
logger.Errorf("CreateMonitorBase err: %v", err)
}
// 将当前资源发送到chan中处理保存
s.loadDiskIO()
s.loadNetIO()
// 监控系统资源-保留天数
storeDays := s.sysConfigService.SelectConfigValueByKey("monitor.sysResource.storeDays")
if storeDays != "" {
storeDays, _ := strconv.Atoi(storeDays)
ltTime := time.Now().AddDate(0, 0, -storeDays).UnixMilli()
_ = s.monitorRepository.DelMonitorBase(ltTime)
_ = s.monitorRepository.DelMonitorIO(ltTime)
_ = s.monitorRepository.DelMonitorNet(ltTime)
}
}
func (s *MonitorImpl) loadDiskIO() {
ioStat, _ := disk.IOCounters()
var diskIOList []disk.IOCountersStat
for _, io := range ioStat {
diskIOList = append(diskIOList, io)
}
s.diskIO <- diskIOList
}
func (s *MonitorImpl) loadNetIO() {
netStat, _ := net.IOCounters(true)
netStatAll, _ := net.IOCounters(false)
var netList []net.IOCountersStat
netList = append(netList, netStat...)
netList = append(netList, netStatAll...)
s.netIO <- netList
}
// monitorCancel 监控搜集IO/Network上下文
var monitorCancel context.CancelFunc
// RunMonitorDataCancel 启动资源监控数据存储io/network通道 移除之前的chan上下文后在设置新的均值
// interval 采集的平均值(分钟)
func (s *MonitorImpl) RunMonitorDataCancel(removeBefore bool, interval float64) {
// 是否取消之前的
if removeBefore {
monitorCancel()
}
// 上下文控制
ctx, cancel := context.WithCancel(context.Background())
monitorCancel = cancel
// chanl 通道进行存储数据
go s.saveIODataToDB(ctx, interval)
go s.saveNetDataToDB(ctx, interval)
}
func (s *MonitorImpl) saveIODataToDB(ctx context.Context, interval float64) {
defer close(s.diskIO)
for {
select {
case <-ctx.Done():
return
case ioStat := <-s.diskIO:
select {
case <-ctx.Done():
return
case ioStat2 := <-s.diskIO:
var ioList []model.MonitorIO
timeMilli := time.Now().UnixMilli()
for _, io2 := range ioStat2 {
for _, io1 := range ioStat {
if io2.Name == io1.Name {
var itemIO model.MonitorIO
itemIO.CreateTime = timeMilli
itemIO.Name = io1.Name
if io2.ReadBytes != 0 && io1.ReadBytes != 0 && io2.ReadBytes > io1.ReadBytes {
itemIO.Read = int64(float64(io2.ReadBytes-io1.ReadBytes) / interval / 60)
}
if io2.WriteBytes != 0 && io1.WriteBytes != 0 && io2.WriteBytes > io1.WriteBytes {
itemIO.Write = int64(float64(io2.WriteBytes-io1.WriteBytes) / interval / 60)
}
if io2.ReadCount != 0 && io1.ReadCount != 0 && io2.ReadCount > io1.ReadCount {
itemIO.Count = int64(float64(io2.ReadCount-io1.ReadCount) / interval / 60)
}
writeCount := int64(0)
if io2.WriteCount != 0 && io1.WriteCount != 0 && io2.WriteCount > io1.WriteCount {
writeCount = int64(float64(io2.WriteCount-io1.WriteCount) / interval * 60)
}
if writeCount > itemIO.Count {
itemIO.Count = writeCount
}
if io2.ReadTime != 0 && io1.ReadTime != 0 && io2.ReadTime > io1.ReadTime {
itemIO.Time = int64(float64(io2.ReadTime-io1.ReadTime) / interval / 60)
}
writeTime := int64(0)
if io2.WriteTime != 0 && io1.WriteTime != 0 && io2.WriteTime > io1.WriteTime {
writeTime = int64(float64(io2.WriteTime-io1.WriteTime) / interval / 60)
}
if writeTime > itemIO.Time {
itemIO.Time = writeTime
}
ioList = append(ioList, itemIO)
break
}
}
}
if err := s.monitorRepository.BatchCreateMonitorIO(ioList); err != nil {
logger.Errorf("BatchCreateMonitorIO err: %v", err)
}
s.diskIO <- ioStat2
}
}
}
}
func (s *MonitorImpl) saveNetDataToDB(ctx context.Context, interval float64) {
defer close(s.netIO)
for {
select {
case <-ctx.Done():
return
case netStat := <-s.netIO:
select {
case <-ctx.Done():
return
case netStat2 := <-s.netIO:
var netList []model.MonitorNetwork
timeMilli := time.Now().UnixMilli()
for _, net2 := range netStat2 {
for _, net1 := range netStat {
if net2.Name == net1.Name {
var itemNet model.MonitorNetwork
itemNet.CreateTime = timeMilli
itemNet.Name = net1.Name
if net2.BytesSent != 0 && net1.BytesSent != 0 && net2.BytesSent > net1.BytesSent {
itemNet.Up = float64(net2.BytesSent-net1.BytesSent) / 1024 / interval / 60
}
if net2.BytesRecv != 0 && net1.BytesRecv != 0 && net2.BytesRecv > net1.BytesRecv {
itemNet.Down = float64(net2.BytesRecv-net1.BytesRecv) / 1024 / interval / 60
}
netList = append(netList, itemNet)
break
}
}
}
if err := s.monitorRepository.BatchCreateMonitorNet(netList); err != nil {
logger.Errorf("BatchCreateMonitorNet err: %v", err)
}
s.netIO <- netStat2
}
}
}
}
// MonitorData 监控资源信息
type MonitorData struct {
Date []int64 `json:"date"`
Value []any `json:"value"`
}
// SelectMonitorInfo 查询监控资源信息
func (s *MonitorImpl) SelectMonitorInfo(query map[string]any) map[string]MonitorData {
infoType := query["type"]
startTimeMilli := query["startTime"]
endTimeMilli := query["endTime"]
neType := query["neType"]
neId := query["neId"]
name := query["name"]
// 返回数据
backdatas := map[string]MonitorData{}
// 基本信息
if infoType == "all" || infoType == "cpu" || infoType == "memory" {
rows := s.monitorRepository.SelectMonitorBase(map[string]any{
"startTime": startTimeMilli,
"endTime": endTimeMilli,
"neType": neType,
"neId": neId,
})
// 组装数据
var itemData MonitorData
for _, base := range rows {
itemData.Date = append(itemData.Date, base.CreateTime)
itemData.Value = append(itemData.Value, base)
}
backdatas["base"] = itemData
}
// 磁盘IO
if infoType == "all" || infoType == "io" {
rows := s.monitorRepository.SelectMonitorIO(map[string]any{
"startTime": startTimeMilli,
"endTime": endTimeMilli,
"neType": neType,
"neId": neId,
"name": name,
})
// 组装数据
var itemData MonitorData
for _, base := range rows {
itemData.Date = append(itemData.Date, base.CreateTime)
itemData.Value = append(itemData.Value, base)
}
backdatas["io"] = itemData
}
// 网络
if infoType == "all" || infoType == "network" {
rows := s.monitorRepository.SelectMonitorNetwork(map[string]any{
"startTime": startTimeMilli,
"endTime": endTimeMilli,
"neType": neType,
"neId": neId,
"name": name,
})
// 组装数据
var itemData MonitorData
for _, base := range rows {
itemData.Date = append(itemData.Date, base.CreateTime)
itemData.Value = append(itemData.Value, base)
}
backdatas["network"] = itemData
}
return backdatas
}

View File

@@ -34,8 +34,8 @@ func (r *SysConfigImpl) SelectConfigList(sysConfig model.SysConfig) []model.SysC
func (r *SysConfigImpl) SelectConfigValueByKey(configKey string) string {
cacheKey := r.getCacheKey(configKey)
// 从缓存中读取
cacheValue, err := redis.Get("", cacheKey)
if cacheValue != "" || err != nil {
cacheValue, _ := redis.Get("", cacheKey)
if cacheValue != "" {
return cacheValue
}
// 无缓存时读取数据放入缓存中

View File

@@ -49,7 +49,17 @@ func (r *SysMenuImpl) SelectMenuTreeByUserId(userId string) []model.SysMenu {
// SelectMenuTreeSelectByUserId 根据用户ID查询菜单树结构信息
func (r *SysMenuImpl) SelectMenuTreeSelectByUserId(sysMenu model.SysMenu, userId string) []vo.TreeSelect {
sysMenus := r.sysMenuRepository.SelectMenuList(sysMenu, userId)
menus := r.parseDataToTree(sysMenus)
// 过滤旧前端菜单
sysMenusF := []model.SysMenu{}
for _, v := range sysMenus {
if v.Perms == "page" {
continue
}
sysMenusF = append(sysMenusF, v)
}
menus := r.parseDataToTree(sysMenusF)
tree := make([]vo.TreeSelect, 0)
for _, menu := range menus {
tree = append(tree, vo.SysMenuTreeSelect(menu))