From 7a42e34c2bff09899d74ca40d8797147da0d6134 Mon Sep 17 00:00:00 2001 From: ssongliu Date: Tue, 6 Sep 2022 18:48:14 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E7=9B=91=E6=8E=A7=E5=89=8D=E7=AB=AF?= =?UTF-8?q?=E7=95=8C=E9=9D=A2=E6=98=BE=E7=A4=BA?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- backend/app.yaml | 2 +- backend/app/api/v1/monitor.go | 72 +++- backend/app/api/v1/monitor_test.go | 47 --- backend/app/dto/monitor.go | 10 +- backend/app/model/monitor.go | 13 +- backend/cron/job/monitor.go | 28 ++ backend/init/router/router.go | 1 + backend/router/entry.go | 1 + backend/router/ro_monitor.go | 19 + frontend/src/api/interface/monitor.ts | 13 + frontend/src/api/modules/monitor.ts | 10 + frontend/src/lang/modules/en.ts | 26 ++ frontend/src/lang/modules/zh.ts | 26 ++ frontend/src/utils/util.ts | 13 + frontend/src/views/monitor/index.vue | 510 ++++++++++++++++++++++---- 15 files changed, 674 insertions(+), 117 deletions(-) delete mode 100644 backend/app/api/v1/monitor_test.go create mode 100644 backend/router/ro_monitor.go create mode 100644 frontend/src/api/interface/monitor.ts create mode 100644 frontend/src/api/modules/monitor.ts diff --git a/backend/app.yaml b/backend/app.yaml index dfb1db868..e65cc9c93 100644 --- a/backend/app.yaml +++ b/backend/app.yaml @@ -1,6 +1,6 @@ system: port: 9999 - db_type: mysql + db_type: sqlite level: debug jwt: diff --git a/backend/app/api/v1/monitor.go b/backend/app/api/v1/monitor.go index 15e93d950..d1208c4c8 100644 --- a/backend/app/api/v1/monitor.go +++ b/backend/app/api/v1/monitor.go @@ -1,11 +1,15 @@ package v1 import ( + "time" + "github.com/1Panel-dev/1Panel/app/api/v1/helper" "github.com/1Panel-dev/1Panel/app/dto" + "github.com/1Panel-dev/1Panel/app/model" "github.com/1Panel-dev/1Panel/constant" "github.com/1Panel-dev/1Panel/global" "github.com/gin-gonic/gin" + "github.com/shirou/gopsutil/net" ) func (b *BaseApi) LoadMonitor(c *gin.Context) { @@ -18,7 +22,71 @@ func (b *BaseApi) LoadMonitor(c *gin.Context) { helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err) return } + if global.CONF.System.DbType == "sqlite" { + req.StartTime = req.StartTime.Add(8 * time.Hour) + req.EndTime = req.EndTime.Add(8 * time.Hour) + } - // stampStart := req.StartTime.Unix() - // stampEnd := req.EndTime.Unix() + var backdatas []dto.MonitorData + if req.Param == "all" || req.Param == "cpu" || req.Param == "memory" || req.Param == "load" { + var bases []model.MonitorBase + if err := global.DB. + Where("created_at > ? AND created_at < ?", req.StartTime, req.EndTime). + Find(&bases).Error; err != nil { + helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err) + return + } + + var itemData dto.MonitorData + itemData.Param = "base" + for _, base := range bases { + itemData.Date = append(itemData.Date, base.CreatedAt) + itemData.Value = append(itemData.Value, base) + } + backdatas = append(backdatas, itemData) + } + if req.Param == "all" || req.Param == "io" { + var bases []model.MonitorIO + if err := global.DB. + Where("created_at > ? AND created_at < ?", req.StartTime, req.EndTime). + Find(&bases).Error; err != nil { + helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err) + return + } + + var itemData dto.MonitorData + itemData.Param = "io" + for _, base := range bases { + itemData.Date = append(itemData.Date, base.CreatedAt) + itemData.Value = append(itemData.Value, base) + } + backdatas = append(backdatas, itemData) + } + if req.Param == "all" || req.Param == "network" { + var bases []model.MonitorNetwork + if err := global.DB. + Where("name = ? AND created_at > ? AND created_at < ?", req.Info, req.StartTime, req.EndTime). + Find(&bases).Error; err != nil { + helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err) + return + } + + var itemData dto.MonitorData + itemData.Param = "network" + for _, base := range bases { + itemData.Date = append(itemData.Date, base.CreatedAt) + itemData.Value = append(itemData.Value, base) + } + backdatas = append(backdatas, itemData) + } + helper.SuccessWithData(c, backdatas) +} + +func (b *BaseApi) GetNetworkOptions(c *gin.Context) { + netStat, _ := net.IOCounters(true) + var options []string + for _, net := range netStat { + options = append(options, net.Name) + } + helper.SuccessWithData(c, options) } diff --git a/backend/app/api/v1/monitor_test.go b/backend/app/api/v1/monitor_test.go deleted file mode 100644 index 61c08b952..000000000 --- a/backend/app/api/v1/monitor_test.go +++ /dev/null @@ -1,47 +0,0 @@ -package v1 - -import ( - "fmt" - "testing" - "time" - - "github.com/shirou/gopsutil/cpu" - "github.com/shirou/gopsutil/disk" - "github.com/shirou/gopsutil/load" - "github.com/shirou/gopsutil/mem" - "github.com/shirou/gopsutil/net" -) - -func TestMonito(t *testing.T) { - totalPercent, _ := cpu.Percent(3*time.Second, false) // 总 cpu 使用 - perPercents, _ := cpu.Percent(3*time.Second, true) // 各 cpu 使用 - fmt.Println("================totalPercent============", totalPercent) - fmt.Println("================perPercents=============", perPercents) - - info, _ := load.Avg() - info2, _ := load.Misc() - fmt.Printf("load: \n loadxx: %v load1: %v, load5: %v, load15: %v \n\n", info2, info.Load1, info.Load5, info.Load15) - - memory, _ := mem.VirtualMemory() - fmt.Printf("memory: \n memory used: %v, use persent: %v \n\n", memory.Used, memory.UsedPercent) - - diskPart, _ := disk.Partitions(true) - // fmt.Println("================disk=============", diskPart) - for _, part := range diskPart { - diskInfo, _ := disk.Usage(part.Mountpoint) - fmt.Printf("inode,disk(%v): \n inode persent: %v, disk used: %v, persent: %v \n", part.Mountpoint, diskInfo.InodesUsedPercent, diskInfo.Used, diskInfo.UsedPercent) - } - fmt.Println() - - ioStat, _ := disk.IOCounters() - for _, v := range ioStat { - fmt.Printf("io: \n name: %v, readCount: %v, writeCount: %v \n\n", v.Name, v.ReadCount, v.WriteCount) - } - fmt.Println() - - net, _ := net.IOCounters(false) - for _, v := range net { - fmt.Printf("netio: \n %v: send:%v recv:%v \n\n", v.Name, v.BytesSent, v.BytesRecv) - } - fmt.Println() -} diff --git a/backend/app/dto/monitor.go b/backend/app/dto/monitor.go index 5bd593f97..780b1c790 100644 --- a/backend/app/dto/monitor.go +++ b/backend/app/dto/monitor.go @@ -3,8 +3,14 @@ package dto import "time" type MonitorSearch struct { - Param string `json:"param" validate:"required,oneof=all cpu memory load disk inode io iops network"` + Param string `json:"param" validate:"required,oneof=all cpu memory load io network"` + Info string `json:"info"` StartTime time.Time `json:"startTime"` EndTime time.Time `json:"endTime"` - Unit string `josn:"unit"` +} + +type MonitorData struct { + Param string `json:"param" validate:"required,oneof=cpu memory load io network"` + Date []time.Time `json:"date"` + Value []interface{} `json:"value"` } diff --git a/backend/app/model/monitor.go b/backend/app/model/monitor.go index b6b6bbaa3..84b6f3be8 100644 --- a/backend/app/model/monitor.go +++ b/backend/app/model/monitor.go @@ -21,11 +21,18 @@ type MonitorIO struct { WriteTime uint64 `gorm:"type:decimal" json:"writeTime"` ReadByte uint64 `gorm:"type:decimal(32)" json:"readByte"` WriteByte uint64 `gorm:"type:decimal(32)" json:"writeByte"` + + Read uint64 `gorm:"type:decimal" json:"read"` + Write uint64 `gorm:"type:decimal" json:"write"` + Count uint64 `gorm:"type:decimal" json:"count"` + Time uint64 `gorm:"type:decimal" json:"time"` } type MonitorNetwork struct { BaseModel - Name string `json:"name"` - BytesSent uint64 `gorm:"type:decimal(32)" json:"bytesSent"` - BytesRecv uint64 `gorm:"type:decimal(32)" json:"bytesRecv"` + Name string `json:"name"` + BytesSent uint64 `gorm:"type:decimal(32)" json:"bytesSent"` + BytesRecv uint64 `gorm:"type:decimal(32)" json:"bytesRecv"` + Up float64 `gorm:"type:float" json:"up"` + Down float64 `gorm:"type:float" json:"down"` } diff --git a/backend/cron/job/monitor.go b/backend/cron/job/monitor.go index a3e560e11..1549d3cb4 100644 --- a/backend/cron/job/monitor.go +++ b/backend/cron/job/monitor.go @@ -47,15 +47,43 @@ func (m *monitor) Run() { itemIO.WriteByte = v.WriteBytes itemIO.ReadTime = v.ReadTime itemIO.WriteTime = v.WriteTime + var aheadData model.MonitorIO + if err := global.DB.Where("name = ?", v.Name).Order("created_at").Find(&aheadData).Error; err != nil { + _ = global.DB.Create(&itemIO) + continue + } + stime := time.Since(aheadData.CreatedAt).Seconds() + itemIO.Read = uint64(float64(v.ReadBytes-aheadData.ReadByte) / stime) + itemIO.Write = uint64(float64(v.WriteBytes-aheadData.WriteByte) / stime) + + itemIO.Count = uint64(float64(v.ReadCount-aheadData.ReadCount) / stime) + writeCount := uint64(float64(v.WriteCount-aheadData.WriteCount) / stime) + if writeCount > itemIO.Count { + itemIO.Count = writeCount + } + + itemIO.Time = uint64(float64(v.ReadTime-aheadData.ReadTime) / stime) + writeTime := uint64(float64(v.WriteTime-aheadData.WriteTime) / stime) + if writeTime > itemIO.Time { + itemIO.Time = writeTime + } _ = global.DB.Create(&itemIO) } netStat, _ := net.IOCounters(true) for _, v := range netStat { var itemNet model.MonitorNetwork + var aheadData model.MonitorNetwork itemNet.Name = v.Name itemNet.BytesSent = v.BytesSent itemNet.BytesRecv = v.BytesRecv + if err := global.DB.Where("name = ?", v.Name).Order("created_at").Find(&aheadData).Error; err != nil { + _ = global.DB.Create(&itemNet) + continue + } + stime := time.Since(aheadData.CreatedAt).Seconds() + itemNet.Up = float64(v.BytesSent-aheadData.BytesSent) / 1024 / stime + itemNet.Down = float64(v.BytesRecv-aheadData.BytesRecv) / 1024 / stime _ = global.DB.Create(&itemNet) } } diff --git a/backend/init/router/router.go b/backend/init/router/router.go index a3f75b973..f82ead830 100644 --- a/backend/init/router/router.go +++ b/backend/init/router/router.go @@ -43,6 +43,7 @@ func Routers() *gin.Engine { systemRouter.InitGroupRouter(PrivateGroup) systemRouter.InitCommandRouter(PrivateGroup) systemRouter.InitTerminalRouter(PrivateGroup) + systemRouter.InitMonitorRouter(PrivateGroup) systemRouter.InitOperationLogRouter(PrivateGroup) } diff --git a/backend/router/entry.go b/backend/router/entry.go index 1865a1bd8..f6320bce2 100644 --- a/backend/router/entry.go +++ b/backend/router/entry.go @@ -6,6 +6,7 @@ type RouterGroup struct { HostRouter GroupRouter CommandRouter + MonitorRouter OperationLogRouter } diff --git a/backend/router/ro_monitor.go b/backend/router/ro_monitor.go new file mode 100644 index 000000000..51f4bbfbd --- /dev/null +++ b/backend/router/ro_monitor.go @@ -0,0 +1,19 @@ +package router + +import ( + v1 "github.com/1Panel-dev/1Panel/app/api/v1" + "github.com/1Panel-dev/1Panel/middleware" + + "github.com/gin-gonic/gin" +) + +type MonitorRouter struct{} + +func (s *MonitorRouter) InitMonitorRouter(Router *gin.RouterGroup) { + monitorRouter := Router.Group("monitors").Use(middleware.JwtAuth()).Use(middleware.SessionAuth()) + baseApi := v1.ApiGroupApp.BaseApi + { + monitorRouter.POST("/search", baseApi.LoadMonitor) + monitorRouter.GET("/netoptions", baseApi.GetNetworkOptions) + } +} diff --git a/frontend/src/api/interface/monitor.ts b/frontend/src/api/interface/monitor.ts new file mode 100644 index 000000000..f153006fb --- /dev/null +++ b/frontend/src/api/interface/monitor.ts @@ -0,0 +1,13 @@ +export namespace Monitor { + export interface MonitorData { + param: string; + date: Array; + value: Array; + } + export interface MonitorSearch { + param: string; + info: string; + startTime: Date; + endTime: Date; + } +} diff --git a/frontend/src/api/modules/monitor.ts b/frontend/src/api/modules/monitor.ts new file mode 100644 index 000000000..ec566b293 --- /dev/null +++ b/frontend/src/api/modules/monitor.ts @@ -0,0 +1,10 @@ +import http from '@/api'; +import { Monitor } from '../interface/monitor'; + +export const loadMonitor = (param: Monitor.MonitorSearch) => { + return http.post>(`/monitors/search`, param); +}; + +export const getNetworkOptions = () => { + return http.get>(`/monitors/netoptions`); +}; diff --git a/frontend/src/lang/modules/en.ts b/frontend/src/lang/modules/en.ts index 9f39a7c8b..896f142e9 100644 --- a/frontend/src/lang/modules/en.ts +++ b/frontend/src/lang/modules/en.ts @@ -11,6 +11,13 @@ export default { login: 'Login', conn: 'Connect', }, + search: { + timeStart: 'Time start', + timeEnd: 'Time end', + timeRange: 'To', + dateStart: 'Date start', + dateEnd: 'Date end', + }, table: { name: 'Name', group: 'Group', @@ -92,6 +99,25 @@ export default { changePassword: 'Change Password', logout: 'Logout', }, + monitor: { + avgLoad: 'Average load', + loadDetail: 'Load detail', + resourceUsage: 'Resource utilization rate', + min: 'Minutes', + read: 'Read', + write: 'Write', + count: 'Times', + readWriteCount: 'Read or write Times', + readWriteTime: 'Read or write delay', + today: 'Today', + yestoday: 'Yestoday', + lastNDay: 'Last {0} day', + memory: 'Memory', + disk: 'Disk', + network: 'Network', + up: 'Up', + down: 'Down', + }, terminal: { conn: 'connection', testConn: 'Test connection', diff --git a/frontend/src/lang/modules/zh.ts b/frontend/src/lang/modules/zh.ts index dcb3b00f5..30f19792e 100644 --- a/frontend/src/lang/modules/zh.ts +++ b/frontend/src/lang/modules/zh.ts @@ -11,6 +11,13 @@ export default { login: '登陆', conn: '连接', }, + search: { + timeStart: '开始时间', + timeEnd: '结束时间', + timeRange: '至', + dateStart: '开始日期', + dateEnd: '结束日期', + }, table: { name: '名称', group: '组', @@ -92,6 +99,25 @@ export default { changePassword: '修改密码', logout: '退出登录', }, + monitor: { + avgLoad: '平均负载', + loadDetail: '负载详情', + resourceUsage: '资源使用率', + min: '分钟', + read: '读取', + write: '写入', + count: '次', + readWriteCount: '读写次数', + readWriteTime: '读写延迟', + today: '今天', + yestoday: '昨天', + lastNDay: '近 {0} 天', + memory: '内存', + disk: '磁盘', + network: '网络', + up: '上行', + down: '下行', + }, terminal: { conn: '连接', testConn: '连接测试', diff --git a/frontend/src/utils/util.ts b/frontend/src/utils/util.ts index f7fe5ba11..fef455765 100644 --- a/frontend/src/utils/util.ts +++ b/frontend/src/utils/util.ts @@ -48,3 +48,16 @@ export function dateFromat(row: number, col: number, dataStr: any) { second = second < 10 ? `0${String(second)}` : second; return `${String(y)}-${String(m)}-${String(d)} ${String(h)}:${String(minute)}:${String(second)}`; } + +export function dateFromatWithoutYear(dataStr: any) { + const date = new Date(dataStr); + let m: string | number = date.getMonth() + 1; + m = m < 10 ? `0${String(m)}` : m; + let d: string | number = date.getDate(); + d = d < 10 ? `0${String(d)}` : d; + let h: string | number = date.getHours(); + h = h < 10 ? `0${String(h)}` : h; + let minute: string | number = date.getMinutes(); + minute = minute < 10 ? `0${String(minute)}` : minute; + return `${String(m)}-${String(d)}\n${String(h)}:${String(minute)}`; +} diff --git a/frontend/src/views/monitor/index.vue b/frontend/src/views/monitor/index.vue index 33cd613e6..2a6456d6b 100644 --- a/frontend/src/views/monitor/index.vue +++ b/frontend/src/views/monitor/index.vue @@ -4,80 +4,116 @@ -
+
- + -
+
-
+
- + -
+
-
+
@@ -85,35 +121,385 @@