mirror of
https://github.com/1Panel-dev/1Panel.git
synced 2025-12-19 14:01:28 +08:00
parent
9242bf6482
commit
9a73095a8f
16 changed files with 404 additions and 113 deletions
|
|
@ -15,6 +15,15 @@ type MonitorData struct {
|
||||||
Value []interface{} `json:"value"`
|
Value []interface{} `json:"value"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type Process struct {
|
||||||
|
Name string `json:"name"`
|
||||||
|
Pid int32 `json:"pid"`
|
||||||
|
Percent float64 `json:"percent"`
|
||||||
|
Memory uint64 `json:"memory"`
|
||||||
|
Cmd string `json:"cmd"`
|
||||||
|
User string `json:"user"`
|
||||||
|
}
|
||||||
|
|
||||||
type MonitorSetting struct {
|
type MonitorSetting struct {
|
||||||
MonitorStatus string `json:"monitorStatus"`
|
MonitorStatus string `json:"monitorStatus"`
|
||||||
MonitorStoreDays string `json:"monitorStoreDays"`
|
MonitorStoreDays string `json:"monitorStoreDays"`
|
||||||
|
|
|
||||||
|
|
@ -3,13 +3,17 @@ package model
|
||||||
type MonitorBase struct {
|
type MonitorBase struct {
|
||||||
BaseModel
|
BaseModel
|
||||||
Cpu float64 `json:"cpu"`
|
Cpu float64 `json:"cpu"`
|
||||||
|
TopCPU string `json:"topCPU"`
|
||||||
|
TopCPUItems interface{} `gorm:"-" json:"topCPUItems"`
|
||||||
|
|
||||||
|
Memory float64 `json:"memory"`
|
||||||
|
TopMem string `json:"topMem"`
|
||||||
|
TopMemItems interface{} `gorm:"-" json:"topMemItems"`
|
||||||
|
|
||||||
LoadUsage float64 `json:"loadUsage"`
|
LoadUsage float64 `json:"loadUsage"`
|
||||||
CpuLoad1 float64 `json:"cpuLoad1"`
|
CpuLoad1 float64 `json:"cpuLoad1"`
|
||||||
CpuLoad5 float64 `json:"cpuLoad5"`
|
CpuLoad5 float64 `json:"cpuLoad5"`
|
||||||
CpuLoad15 float64 `json:"cpuLoad15"`
|
CpuLoad15 float64 `json:"cpuLoad15"`
|
||||||
|
|
||||||
Memory float64 `json:"memory"`
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type MonitorIO struct {
|
type MonitorIO struct {
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,7 @@ import (
|
||||||
"context"
|
"context"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"sort"
|
||||||
"strconv"
|
"strconv"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
|
@ -21,6 +22,7 @@ import (
|
||||||
"github.com/shirou/gopsutil/v4/load"
|
"github.com/shirou/gopsutil/v4/load"
|
||||||
"github.com/shirou/gopsutil/v4/mem"
|
"github.com/shirou/gopsutil/v4/mem"
|
||||||
"github.com/shirou/gopsutil/v4/net"
|
"github.com/shirou/gopsutil/v4/net"
|
||||||
|
"github.com/shirou/gopsutil/v4/process"
|
||||||
)
|
)
|
||||||
|
|
||||||
type MonitorService struct {
|
type MonitorService struct {
|
||||||
|
|
@ -64,6 +66,18 @@ func (m *MonitorService) LoadMonitorData(req dto.MonitorSearch) ([]dto.MonitorDa
|
||||||
itemData.Param = "base"
|
itemData.Param = "base"
|
||||||
for _, base := range bases {
|
for _, base := range bases {
|
||||||
itemData.Date = append(itemData.Date, base.CreatedAt)
|
itemData.Date = append(itemData.Date, base.CreatedAt)
|
||||||
|
if req.Param == "all" || req.Param == "cpu" {
|
||||||
|
var processes []dto.Process
|
||||||
|
_ = json.Unmarshal([]byte(base.TopCPU), &processes)
|
||||||
|
base.TopCPUItems = processes
|
||||||
|
base.TopCPU = ""
|
||||||
|
}
|
||||||
|
if req.Param == "all" || req.Param == "mem" {
|
||||||
|
var processes []dto.Process
|
||||||
|
_ = json.Unmarshal([]byte(base.TopMem), &processes)
|
||||||
|
base.TopMemItems = processes
|
||||||
|
base.TopMem = ""
|
||||||
|
}
|
||||||
itemData.Value = append(itemData.Value, base)
|
itemData.Value = append(itemData.Value, base)
|
||||||
}
|
}
|
||||||
data = append(data, itemData)
|
data = append(data, itemData)
|
||||||
|
|
@ -169,8 +183,14 @@ func (m *MonitorService) Run() {
|
||||||
if len(totalPercent) == 1 {
|
if len(totalPercent) == 1 {
|
||||||
itemModel.Cpu = totalPercent[0]
|
itemModel.Cpu = totalPercent[0]
|
||||||
}
|
}
|
||||||
|
topCPU := m.loadTopCPU()
|
||||||
|
if len(topCPU) != 0 {
|
||||||
|
topItemCPU, err := json.Marshal(topCPU)
|
||||||
|
if err == nil {
|
||||||
|
itemModel.TopCPU = string(topItemCPU)
|
||||||
|
}
|
||||||
|
}
|
||||||
cpuCount, _ := cpu.Counts(false)
|
cpuCount, _ := cpu.Counts(false)
|
||||||
|
|
||||||
loadInfo, _ := load.Avg()
|
loadInfo, _ := load.Avg()
|
||||||
itemModel.CpuLoad1 = loadInfo.Load1
|
itemModel.CpuLoad1 = loadInfo.Load1
|
||||||
itemModel.CpuLoad5 = loadInfo.Load5
|
itemModel.CpuLoad5 = loadInfo.Load5
|
||||||
|
|
@ -179,6 +199,13 @@ func (m *MonitorService) Run() {
|
||||||
|
|
||||||
memoryInfo, _ := mem.VirtualMemory()
|
memoryInfo, _ := mem.VirtualMemory()
|
||||||
itemModel.Memory = memoryInfo.UsedPercent
|
itemModel.Memory = memoryInfo.UsedPercent
|
||||||
|
topMem := m.loadTopMem()
|
||||||
|
if len(topMem) != 0 {
|
||||||
|
topMemItem, err := json.Marshal(topMem)
|
||||||
|
if err == nil {
|
||||||
|
itemModel.TopMem = string(topMemItem)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if err := settingRepo.CreateMonitorBase(itemModel); err != nil {
|
if err := settingRepo.CreateMonitorBase(itemModel); err != nil {
|
||||||
global.LOG.Errorf("Insert basic monitoring data failed, err: %v", err)
|
global.LOG.Errorf("Insert basic monitoring data failed, err: %v", err)
|
||||||
|
|
@ -323,6 +350,108 @@ func (m *MonitorService) saveNetDataToDB(ctx context.Context, interval float64)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (m *MonitorService) loadTopCPU() []dto.Process {
|
||||||
|
processes, err := process.Processes()
|
||||||
|
if err != nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
top5 := make([]dto.Process, 0, 5)
|
||||||
|
for _, p := range processes {
|
||||||
|
percent, err := p.CPUPercent()
|
||||||
|
if err != nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
minIndex := 0
|
||||||
|
if len(top5) >= 5 {
|
||||||
|
minCPU := top5[0].Percent
|
||||||
|
for i := 1; i < len(top5); i++ {
|
||||||
|
if top5[i].Percent < minCPU {
|
||||||
|
minCPU = top5[i].Percent
|
||||||
|
minIndex = i
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if percent < minCPU {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
name, err := p.Name()
|
||||||
|
if err != nil {
|
||||||
|
name = "undifine"
|
||||||
|
}
|
||||||
|
cmd, err := p.Cmdline()
|
||||||
|
if err != nil {
|
||||||
|
cmd = "undifine"
|
||||||
|
}
|
||||||
|
user, err := p.Username()
|
||||||
|
if err != nil {
|
||||||
|
user = "undifine"
|
||||||
|
}
|
||||||
|
if len(top5) == 5 {
|
||||||
|
top5[minIndex] = dto.Process{Percent: percent, Pid: p.Pid, User: user, Name: name, Cmd: cmd}
|
||||||
|
} else {
|
||||||
|
top5 = append(top5, dto.Process{Percent: percent, Pid: p.Pid, User: user, Name: name, Cmd: cmd})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
sort.Slice(top5, func(i, j int) bool {
|
||||||
|
return top5[i].Percent > top5[j].Percent
|
||||||
|
})
|
||||||
|
|
||||||
|
return top5
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *MonitorService) loadTopMem() []dto.Process {
|
||||||
|
processes, err := process.Processes()
|
||||||
|
if err != nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
top5 := make([]dto.Process, 0, 5)
|
||||||
|
for _, p := range processes {
|
||||||
|
stat, err := p.MemoryInfo()
|
||||||
|
if err != nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
memItem := stat.RSS
|
||||||
|
minIndex := 0
|
||||||
|
if len(top5) >= 5 {
|
||||||
|
min := top5[0].Memory
|
||||||
|
for i := 1; i < len(top5); i++ {
|
||||||
|
if top5[i].Memory < min {
|
||||||
|
min = top5[i].Memory
|
||||||
|
minIndex = i
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if memItem < min {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
name, err := p.Name()
|
||||||
|
if err != nil {
|
||||||
|
name = "undifine"
|
||||||
|
}
|
||||||
|
cmd, err := p.Cmdline()
|
||||||
|
if err != nil {
|
||||||
|
cmd = "undifine"
|
||||||
|
}
|
||||||
|
user, err := p.Username()
|
||||||
|
if err != nil {
|
||||||
|
user = "undifine"
|
||||||
|
}
|
||||||
|
percent, _ := p.MemoryPercent()
|
||||||
|
if len(top5) == 5 {
|
||||||
|
top5[minIndex] = dto.Process{Percent: float64(percent), Pid: p.Pid, User: user, Name: name, Cmd: cmd, Memory: memItem}
|
||||||
|
} else {
|
||||||
|
top5 = append(top5, dto.Process{Percent: float64(percent), Pid: p.Pid, User: user, Name: name, Cmd: cmd, Memory: memItem})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
sort.Slice(top5, func(i, j int) bool {
|
||||||
|
return top5[i].Memory > top5[j].Memory
|
||||||
|
})
|
||||||
|
return top5
|
||||||
|
}
|
||||||
|
|
||||||
func StartMonitor(removeBefore bool, interval string) error {
|
func StartMonitor(removeBefore bool, interval string) error {
|
||||||
if removeBefore {
|
if removeBefore {
|
||||||
monitorCancel()
|
monitorCancel()
|
||||||
|
|
|
||||||
|
|
@ -48,6 +48,7 @@ func InitAgentDB() {
|
||||||
migrations.UpdateWebsiteSSLAddColumn,
|
migrations.UpdateWebsiteSSLAddColumn,
|
||||||
migrations.AddTensorRTLLMModel,
|
migrations.AddTensorRTLLMModel,
|
||||||
migrations.UpdateMonitorInterval,
|
migrations.UpdateMonitorInterval,
|
||||||
|
migrations.AddMonitorProcess,
|
||||||
})
|
})
|
||||||
if err := m.Migrate(); err != nil {
|
if err := m.Migrate(); err != nil {
|
||||||
global.LOG.Error(err)
|
global.LOG.Error(err)
|
||||||
|
|
|
||||||
|
|
@ -659,3 +659,10 @@ var UpdateMonitorInterval = &gormigrate.Migration{
|
||||||
return nil
|
return nil
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var AddMonitorProcess = &gormigrate.Migration{
|
||||||
|
ID: "20251030-add-monitor-process",
|
||||||
|
Migrate: func(tx *gorm.DB) error {
|
||||||
|
return global.MonitorDB.AutoMigrate(&model.MonitorBase{})
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -104,6 +104,7 @@ const message = {
|
||||||
timeRange: 'To',
|
timeRange: 'To',
|
||||||
dateStart: 'Date start',
|
dateStart: 'Date start',
|
||||||
dateEnd: 'Date end',
|
dateEnd: 'Date end',
|
||||||
|
date: 'Date',
|
||||||
},
|
},
|
||||||
table: {
|
table: {
|
||||||
all: 'All',
|
all: 'All',
|
||||||
|
|
@ -1193,10 +1194,11 @@ const message = {
|
||||||
readWriteTime: 'I/O latency',
|
readWriteTime: 'I/O latency',
|
||||||
today: 'Today',
|
today: 'Today',
|
||||||
yesterday: 'Yesterday',
|
yesterday: 'Yesterday',
|
||||||
lastNDay: 'Last {0} day(s)',
|
lastNDay: 'Last {0} days',
|
||||||
lastNMonth: 'Last {0} months',
|
lastNMonth: 'Last {0} months',
|
||||||
lastHalfYear: 'Last half year',
|
lastHalfYear: 'Last half year',
|
||||||
memory: 'Memory',
|
memory: 'Memory',
|
||||||
|
percent: 'Percentage',
|
||||||
cache: 'Cache',
|
cache: 'Cache',
|
||||||
disk: 'Disk',
|
disk: 'Disk',
|
||||||
network: 'Network',
|
network: 'Network',
|
||||||
|
|
|
||||||
|
|
@ -103,6 +103,7 @@ const message = {
|
||||||
timeRange: 'Hasta',
|
timeRange: 'Hasta',
|
||||||
dateStart: 'Fecha de inicio',
|
dateStart: 'Fecha de inicio',
|
||||||
dateEnd: 'Fecha de fin',
|
dateEnd: 'Fecha de fin',
|
||||||
|
date: 'Fecha',
|
||||||
},
|
},
|
||||||
table: {
|
table: {
|
||||||
all: 'Todo',
|
all: 'Todo',
|
||||||
|
|
@ -1200,8 +1201,9 @@ const message = {
|
||||||
yesterday: 'Ayer',
|
yesterday: 'Ayer',
|
||||||
lastNDay: 'Últimos {0} días',
|
lastNDay: 'Últimos {0} días',
|
||||||
lastNMonth: 'Últimos {0} meses',
|
lastNMonth: 'Últimos {0} meses',
|
||||||
lastHalfYear: 'Últimos seis meses',
|
lastHalfYear: 'Último semestre',
|
||||||
memory: 'Memoria',
|
memory: 'Memoria',
|
||||||
|
percent: 'Porcentaje',
|
||||||
cache: 'Caché',
|
cache: 'Caché',
|
||||||
disk: 'Disco',
|
disk: 'Disco',
|
||||||
network: 'Red',
|
network: 'Red',
|
||||||
|
|
|
||||||
|
|
@ -101,6 +101,7 @@ const message = {
|
||||||
timeRange: 'に',
|
timeRange: 'に',
|
||||||
dateStart: '日付開始',
|
dateStart: '日付開始',
|
||||||
dateEnd: '日付の終わり',
|
dateEnd: '日付の終わり',
|
||||||
|
date: '日付',
|
||||||
},
|
},
|
||||||
table: {
|
table: {
|
||||||
all: '全て',
|
all: '全て',
|
||||||
|
|
@ -1157,8 +1158,11 @@ const message = {
|
||||||
readWriteTime: 'I/Oレイテンシ',
|
readWriteTime: 'I/Oレイテンシ',
|
||||||
today: '今日',
|
today: '今日',
|
||||||
yesterday: '昨日',
|
yesterday: '昨日',
|
||||||
lastNDay: '最後の{0}日',
|
lastNDay: '過去 {0} 日間',
|
||||||
|
lastNMonth: '過去 {0} ヶ月間',
|
||||||
|
lastHalfYear: '過去半年間',
|
||||||
memory: 'メモリ',
|
memory: 'メモリ',
|
||||||
|
percent: '割合',
|
||||||
cache: 'キャッシュ',
|
cache: 'キャッシュ',
|
||||||
disk: 'ディスク',
|
disk: 'ディスク',
|
||||||
network: 'ネットワーク',
|
network: 'ネットワーク',
|
||||||
|
|
|
||||||
|
|
@ -101,6 +101,7 @@ const message = {
|
||||||
timeRange: '부터',
|
timeRange: '부터',
|
||||||
dateStart: '시작 날짜',
|
dateStart: '시작 날짜',
|
||||||
dateEnd: '종료 날짜',
|
dateEnd: '종료 날짜',
|
||||||
|
date: '날짜',
|
||||||
},
|
},
|
||||||
table: {
|
table: {
|
||||||
all: '전체',
|
all: '전체',
|
||||||
|
|
@ -1150,7 +1151,10 @@ const message = {
|
||||||
today: '오늘',
|
today: '오늘',
|
||||||
yesterday: '어제',
|
yesterday: '어제',
|
||||||
lastNDay: '최근 {0}일',
|
lastNDay: '최근 {0}일',
|
||||||
|
lastNMonth: '최근 {0}개월',
|
||||||
|
lastHalfYear: '최근 반년',
|
||||||
memory: '메모리',
|
memory: '메모리',
|
||||||
|
percent: '비율',
|
||||||
cache: '캐시',
|
cache: '캐시',
|
||||||
disk: '디스크',
|
disk: '디스크',
|
||||||
network: '네트워크',
|
network: '네트워크',
|
||||||
|
|
|
||||||
|
|
@ -101,6 +101,7 @@ const message = {
|
||||||
timeRange: 'Hingga',
|
timeRange: 'Hingga',
|
||||||
dateStart: 'Tarikh mula',
|
dateStart: 'Tarikh mula',
|
||||||
dateEnd: 'Tarikh tamat',
|
dateEnd: 'Tarikh tamat',
|
||||||
|
date: 'Tarikh',
|
||||||
},
|
},
|
||||||
table: {
|
table: {
|
||||||
all: 'Semua',
|
all: 'Semua',
|
||||||
|
|
@ -1190,7 +1191,10 @@ const message = {
|
||||||
today: 'Hari ini',
|
today: 'Hari ini',
|
||||||
yesterday: 'Semalam',
|
yesterday: 'Semalam',
|
||||||
lastNDay: '{0} hari terakhir',
|
lastNDay: '{0} hari terakhir',
|
||||||
|
lastNMonth: '{0} bulan terakhir',
|
||||||
|
lastHalfYear: 'Setengah tahun terakhir',
|
||||||
memory: 'Memori',
|
memory: 'Memori',
|
||||||
|
percent: 'Peratusan',
|
||||||
cache: 'Cache',
|
cache: 'Cache',
|
||||||
disk: 'Cakera',
|
disk: 'Cakera',
|
||||||
network: 'Rangkaian',
|
network: 'Rangkaian',
|
||||||
|
|
|
||||||
|
|
@ -101,6 +101,7 @@ const message = {
|
||||||
timeRange: 'Até',
|
timeRange: 'Até',
|
||||||
dateStart: 'Data inicial',
|
dateStart: 'Data inicial',
|
||||||
dateEnd: 'Data final',
|
dateEnd: 'Data final',
|
||||||
|
date: 'Data',
|
||||||
},
|
},
|
||||||
table: {
|
table: {
|
||||||
all: 'Todos',
|
all: 'Todos',
|
||||||
|
|
@ -1181,8 +1182,11 @@ const message = {
|
||||||
readWriteTime: 'Latência de I/O',
|
readWriteTime: 'Latência de I/O',
|
||||||
today: 'Hoje',
|
today: 'Hoje',
|
||||||
yesterday: 'Ontem',
|
yesterday: 'Ontem',
|
||||||
lastNDay: 'Últimos {0} dia(s)',
|
lastNDay: 'Últimos {0} dias',
|
||||||
|
lastNMonth: 'Últimos {0} meses',
|
||||||
|
lastHalfYear: 'Último semestre',
|
||||||
memory: 'Memória',
|
memory: 'Memória',
|
||||||
|
percent: 'Percentual',
|
||||||
cache: 'Cache',
|
cache: 'Cache',
|
||||||
disk: 'Disco',
|
disk: 'Disco',
|
||||||
network: 'Rede',
|
network: 'Rede',
|
||||||
|
|
|
||||||
|
|
@ -101,6 +101,7 @@ const message = {
|
||||||
timeRange: 'До',
|
timeRange: 'До',
|
||||||
dateStart: 'Дата начала',
|
dateStart: 'Дата начала',
|
||||||
dateEnd: 'Дата окончания',
|
dateEnd: 'Дата окончания',
|
||||||
|
date: 'Дата',
|
||||||
},
|
},
|
||||||
table: {
|
table: {
|
||||||
all: 'Все',
|
all: 'Все',
|
||||||
|
|
@ -1186,7 +1187,10 @@ const message = {
|
||||||
today: 'Сегодня',
|
today: 'Сегодня',
|
||||||
yesterday: 'Вчера',
|
yesterday: 'Вчера',
|
||||||
lastNDay: 'Последние {0} дней',
|
lastNDay: 'Последние {0} дней',
|
||||||
|
lastNMonth: 'Последние {0} месяцев',
|
||||||
|
lastHalfYear: 'Последние полгода',
|
||||||
memory: 'Память',
|
memory: 'Память',
|
||||||
|
percent: 'Процент',
|
||||||
cache: 'Кэш',
|
cache: 'Кэш',
|
||||||
disk: 'Диск',
|
disk: 'Диск',
|
||||||
network: 'Сеть',
|
network: 'Сеть',
|
||||||
|
|
|
||||||
|
|
@ -104,6 +104,7 @@ const message = {
|
||||||
timeRange: 'İle',
|
timeRange: 'İle',
|
||||||
dateStart: 'Başlangıç tarihi',
|
dateStart: 'Başlangıç tarihi',
|
||||||
dateEnd: 'Bitiş tarihi',
|
dateEnd: 'Bitiş tarihi',
|
||||||
|
date: 'Tarih',
|
||||||
},
|
},
|
||||||
table: {
|
table: {
|
||||||
all: 'Tümü',
|
all: 'Tümü',
|
||||||
|
|
@ -1209,8 +1210,9 @@ const message = {
|
||||||
yesterday: 'Dün',
|
yesterday: 'Dün',
|
||||||
lastNDay: 'Son {0} gün',
|
lastNDay: 'Son {0} gün',
|
||||||
lastNMonth: 'Son {0} ay',
|
lastNMonth: 'Son {0} ay',
|
||||||
lastHalfYear: 'Son yarı yıl',
|
lastHalfYear: 'Son yarım yıl',
|
||||||
memory: 'Bellek',
|
memory: 'Bellek',
|
||||||
|
percent: 'Yüzde',
|
||||||
cache: 'Önbellek',
|
cache: 'Önbellek',
|
||||||
disk: 'Disk',
|
disk: 'Disk',
|
||||||
network: 'Ağ',
|
network: 'Ağ',
|
||||||
|
|
|
||||||
|
|
@ -104,6 +104,7 @@ const message = {
|
||||||
timeRange: '至',
|
timeRange: '至',
|
||||||
dateStart: '開始日期',
|
dateStart: '開始日期',
|
||||||
dateEnd: '結束日期',
|
dateEnd: '結束日期',
|
||||||
|
date: '日期',
|
||||||
},
|
},
|
||||||
table: {
|
table: {
|
||||||
all: '所有',
|
all: '所有',
|
||||||
|
|
@ -1134,6 +1135,7 @@ const message = {
|
||||||
lastNMonth: '近 {0} 月',
|
lastNMonth: '近 {0} 月',
|
||||||
lastHalfYear: '近半年',
|
lastHalfYear: '近半年',
|
||||||
memory: '記憶體',
|
memory: '記憶體',
|
||||||
|
percent: '佔比',
|
||||||
cache: '快取',
|
cache: '快取',
|
||||||
disk: '磁碟',
|
disk: '磁碟',
|
||||||
network: '網路',
|
network: '網路',
|
||||||
|
|
|
||||||
|
|
@ -104,6 +104,7 @@ const message = {
|
||||||
timeRange: '至',
|
timeRange: '至',
|
||||||
dateStart: '开始日期',
|
dateStart: '开始日期',
|
||||||
dateEnd: '结束日期',
|
dateEnd: '结束日期',
|
||||||
|
date: '日期',
|
||||||
},
|
},
|
||||||
table: {
|
table: {
|
||||||
all: '所有',
|
all: '所有',
|
||||||
|
|
@ -1136,6 +1137,7 @@ const message = {
|
||||||
lastNMonth: '近 {0} 月',
|
lastNMonth: '近 {0} 月',
|
||||||
lastHalfYear: '近半年',
|
lastHalfYear: '近半年',
|
||||||
memory: '内存',
|
memory: '内存',
|
||||||
|
percent: '占比',
|
||||||
cache: '缓存',
|
cache: '缓存',
|
||||||
disk: '磁盘',
|
disk: '磁盘',
|
||||||
network: '网络',
|
network: '网络',
|
||||||
|
|
|
||||||
|
|
@ -220,7 +220,7 @@
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { ref, reactive, onMounted, computed } from 'vue';
|
import { ref, reactive, onMounted, computed } from 'vue';
|
||||||
import { loadMonitor, getNetworkOptions, getIOOptions } from '@/api/modules/host';
|
import { loadMonitor, getNetworkOptions, getIOOptions } from '@/api/modules/host';
|
||||||
import { computeSizeFromKBs, dateFormatWithoutYear } from '@/utils/util';
|
import { computeSize, computeSizeFromKBs, dateFormat } from '@/utils/util';
|
||||||
import i18n from '@/lang';
|
import i18n from '@/lang';
|
||||||
import MonitorRouter from '@/views/host/monitor/index.vue';
|
import MonitorRouter from '@/views/host/monitor/index.vue';
|
||||||
import { GlobalStore } from '@/store';
|
import { GlobalStore } from '@/store';
|
||||||
|
|
@ -233,7 +233,6 @@ const mobile = computed(() => {
|
||||||
return globalStore.isMobile();
|
return globalStore.isMobile();
|
||||||
});
|
});
|
||||||
|
|
||||||
const zoomStart = ref();
|
|
||||||
const monitorBase = ref();
|
const monitorBase = ref();
|
||||||
const timeRangeGlobal = ref<[Date, Date]>([new Date(new Date().setHours(0, 0, 0, 0)), new Date()]);
|
const timeRangeGlobal = ref<[Date, Date]>([new Date(new Date().setHours(0, 0, 0, 0)), new Date()]);
|
||||||
const timeRangeLoad = ref<[Date, Date]>([new Date(new Date().setHours(0, 0, 0, 0)), new Date()]);
|
const timeRangeLoad = ref<[Date, Date]>([new Date(new Date().setHours(0, 0, 0, 0)), new Date()]);
|
||||||
|
|
@ -304,41 +303,13 @@ const search = async (param: string) => {
|
||||||
case 'base':
|
case 'base':
|
||||||
let baseDate = item.date.length === 0 ? loadEmptyDate(timeRangeCpu.value) : item.date;
|
let baseDate = item.date.length === 0 ? loadEmptyDate(timeRangeCpu.value) : item.date;
|
||||||
baseDate = baseDate.map(function (item: any) {
|
baseDate = baseDate.map(function (item: any) {
|
||||||
return dateFormatWithoutYear(item);
|
return dateFormat(null, null, item);
|
||||||
});
|
});
|
||||||
if (param === 'cpu' || param === 'all') {
|
if (param === 'cpu' || param === 'all') {
|
||||||
let cpuData = item.value.map(function (item: any) {
|
initCPUCharts(baseDate, item);
|
||||||
return item.cpu.toFixed(2);
|
|
||||||
});
|
|
||||||
cpuData = cpuData.length === 0 ? loadEmptyData() : cpuData;
|
|
||||||
chartsOption.value['loadCPUChart'] = {
|
|
||||||
xData: baseDate,
|
|
||||||
yData: [
|
|
||||||
{
|
|
||||||
name: 'CPU',
|
|
||||||
data: cpuData,
|
|
||||||
},
|
|
||||||
],
|
|
||||||
|
|
||||||
formatStr: '%',
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
if (param === 'memory' || param === 'all') {
|
if (param === 'memory' || param === 'all') {
|
||||||
let memoryData = item.value.map(function (item: any) {
|
initMemCharts(baseDate, item);
|
||||||
return item.memory.toFixed(2);
|
|
||||||
});
|
|
||||||
memoryData = memoryData.length === 0 ? loadEmptyData() : memoryData;
|
|
||||||
chartsOption.value['loadMemoryChart'] = {
|
|
||||||
xData: baseDate,
|
|
||||||
yData: [
|
|
||||||
{
|
|
||||||
name: i18n.global.t('monitor.memory'),
|
|
||||||
data: memoryData,
|
|
||||||
},
|
|
||||||
],
|
|
||||||
|
|
||||||
formatStr: '%',
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
if (param === 'load' || param === 'all') {
|
if (param === 'load' || param === 'all') {
|
||||||
initLoadCharts(item);
|
initLoadCharts(item);
|
||||||
|
|
@ -348,38 +319,8 @@ const search = async (param: string) => {
|
||||||
initIOCharts(item);
|
initIOCharts(item);
|
||||||
break;
|
break;
|
||||||
case 'network':
|
case 'network':
|
||||||
let networkDate = item.date.length === 0 ? loadEmptyDate(timeRangeNetwork.value) : item.date;
|
initNetCharts(item);
|
||||||
networkDate = networkDate.map(function (item: any) {
|
break;
|
||||||
return dateFormatWithoutYear(item);
|
|
||||||
});
|
|
||||||
let networkUp = item.value.map(function (item: any) {
|
|
||||||
return item.up.toFixed(2);
|
|
||||||
});
|
|
||||||
networkUp = networkUp.length === 0 ? loadEmptyData() : networkUp;
|
|
||||||
let networkOut = item.value.map(function (item: any) {
|
|
||||||
return item.down.toFixed(2);
|
|
||||||
});
|
|
||||||
networkOut = networkOut.length === 0 ? loadEmptyData() : networkOut;
|
|
||||||
|
|
||||||
chartsOption.value['loadNetworkChart'] = {
|
|
||||||
xData: networkDate,
|
|
||||||
yData: [
|
|
||||||
{
|
|
||||||
name: i18n.global.t('monitor.up'),
|
|
||||||
data: networkUp,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: i18n.global.t('monitor.down'),
|
|
||||||
data: networkOut,
|
|
||||||
},
|
|
||||||
],
|
|
||||||
grid: {
|
|
||||||
left: getSideWidth(true),
|
|
||||||
right: getSideWidth(true),
|
|
||||||
bottom: '20%',
|
|
||||||
},
|
|
||||||
formatStr: 'KB/s',
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
@ -413,7 +354,7 @@ const loadIOOptions = async () => {
|
||||||
function initLoadCharts(item: Host.MonitorData) {
|
function initLoadCharts(item: Host.MonitorData) {
|
||||||
let itemLoadDate = item.date.length === 0 ? loadEmptyDate(timeRangeLoad.value) : item.date;
|
let itemLoadDate = item.date.length === 0 ? loadEmptyDate(timeRangeLoad.value) : item.date;
|
||||||
let loadDate = itemLoadDate.map(function (item: any) {
|
let loadDate = itemLoadDate.map(function (item: any) {
|
||||||
return dateFormatWithoutYear(item);
|
return dateFormat(null, null, item);
|
||||||
});
|
});
|
||||||
let load1Data = item.value.map(function (item: any) {
|
let load1Data = item.value.map(function (item: any) {
|
||||||
return item.cpuLoad1.toFixed(2);
|
return item.cpuLoad1.toFixed(2);
|
||||||
|
|
@ -428,9 +369,9 @@ function initLoadCharts(item: Host.MonitorData) {
|
||||||
});
|
});
|
||||||
load15Data = load15Data.length === 0 ? loadEmptyData() : load15Data;
|
load15Data = load15Data.length === 0 ? loadEmptyData() : load15Data;
|
||||||
let loadUsage = item.value.map(function (item: any) {
|
let loadUsage = item.value.map(function (item: any) {
|
||||||
return item.loadUsage.toFixed(2);
|
return { value: item.loadUsage.toFixed(2), top: item.topCPUItems, unit: '%' };
|
||||||
});
|
});
|
||||||
loadUsage = loadUsage.length === 0 ? loadEmptyData() : loadUsage;
|
loadUsage = loadUsage.length === 0 ? loadTopEmptyData() : loadUsage;
|
||||||
chartsOption.value['loadLoadChart'] = {
|
chartsOption.value['loadLoadChart'] = {
|
||||||
xData: loadDate,
|
xData: loadDate,
|
||||||
yData: [
|
yData: [
|
||||||
|
|
@ -465,26 +406,109 @@ function initLoadCharts(item: Host.MonitorData) {
|
||||||
tooltip: {
|
tooltip: {
|
||||||
trigger: 'axis',
|
trigger: 'axis',
|
||||||
formatter: function (datas: any) {
|
formatter: function (datas: any) {
|
||||||
let res = datas[0].name + '<br/>';
|
return withCPUProcess(datas);
|
||||||
for (const item of datas) {
|
},
|
||||||
if (item.seriesName === i18n.global.t('monitor.resourceUsage')) {
|
},
|
||||||
res +=
|
};
|
||||||
item.marker + ' ' + item.seriesName + i18n.global.t('commons.colon') + item.data + '%<br/>';
|
|
||||||
} else {
|
|
||||||
res +=
|
|
||||||
item.marker + ' ' + item.seriesName + i18n.global.t('commons.colon') + item.data + '<br/>';
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function initCPUCharts(baseDate: any, items: Host.MonitorData) {
|
||||||
|
let data = items.value.map(function (item: any) {
|
||||||
|
return { value: item.cpu.toFixed(2), top: item.topCPUItems, unit: '%' };
|
||||||
|
});
|
||||||
|
data = data.length === 0 ? loadTopEmptyData() : data;
|
||||||
|
chartsOption.value['loadCPUChart'] = {
|
||||||
|
xData: baseDate,
|
||||||
|
yData: [
|
||||||
|
{
|
||||||
|
name: 'CPU',
|
||||||
|
data: data,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
tooltip: {
|
||||||
|
trigger: 'axis',
|
||||||
|
formatter: function (datas: any) {
|
||||||
|
return withCPUProcess(datas);
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
formatStr: '%',
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
function initMemCharts(baseDate: any, items: Host.MonitorData) {
|
||||||
|
let data = items.value.map(function (item: any) {
|
||||||
|
return { value: item.memory.toFixed(2), top: item.topMemItems };
|
||||||
|
});
|
||||||
|
data = data.length === 0 ? loadTopEmptyData() : data;
|
||||||
|
chartsOption.value['loadMemoryChart'] = {
|
||||||
|
xData: baseDate,
|
||||||
|
yData: [
|
||||||
|
{
|
||||||
|
name: i18n.global.t('monitor.memory'),
|
||||||
|
data: data,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
tooltip: {
|
||||||
|
trigger: 'axis',
|
||||||
|
formatter: function (datas: any) {
|
||||||
|
return withMemProcess(datas);
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
formatStr: '%',
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
function initNetCharts(item: Host.MonitorData) {
|
||||||
|
let networkDate = item.date.length === 0 ? loadEmptyDate(timeRangeNetwork.value) : item.date;
|
||||||
|
let date = networkDate.map(function (item: any) {
|
||||||
|
return dateFormat(null, null, item);
|
||||||
|
});
|
||||||
|
let networkUp = item.value.map(function (item: any) {
|
||||||
|
return item.up.toFixed(2);
|
||||||
|
});
|
||||||
|
networkUp = networkUp.length === 0 ? loadEmptyData() : networkUp;
|
||||||
|
let networkOut = item.value.map(function (item: any) {
|
||||||
|
return item.down.toFixed(2);
|
||||||
|
});
|
||||||
|
networkOut = networkOut.length === 0 ? loadEmptyData() : networkOut;
|
||||||
|
|
||||||
|
chartsOption.value['loadNetworkChart'] = {
|
||||||
|
xData: date,
|
||||||
|
yData: [
|
||||||
|
{
|
||||||
|
name: i18n.global.t('monitor.up'),
|
||||||
|
data: networkUp,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: i18n.global.t('monitor.down'),
|
||||||
|
data: networkOut,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
tooltip: {
|
||||||
|
trigger: 'axis',
|
||||||
|
formatter: function (datas: any) {
|
||||||
|
let res = loadDate(datas[0].name);
|
||||||
|
for (const item of datas) {
|
||||||
|
res += loadSeries(item, computeSizeFromKBs(item.data), '');
|
||||||
}
|
}
|
||||||
return res;
|
return res;
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
grid: {
|
||||||
|
left: getSideWidth(true),
|
||||||
|
right: getSideWidth(true),
|
||||||
|
bottom: '20%',
|
||||||
|
},
|
||||||
|
formatStr: 'KB/s',
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
function initIOCharts(item: Host.MonitorData) {
|
function initIOCharts(item: Host.MonitorData) {
|
||||||
let itemIODate = item.date?.length === 0 ? loadEmptyDate(timeRangeIO.value) : item.date;
|
let itemIODate = item.date?.length === 0 ? loadEmptyDate(timeRangeIO.value) : item.date;
|
||||||
let ioDate = itemIODate.map(function (item: any) {
|
let ioDate = itemIODate.map(function (item: any) {
|
||||||
return dateFormatWithoutYear(item);
|
return dateFormat(null, null, item);
|
||||||
});
|
});
|
||||||
let ioRead = item.value.map(function (item: any) {
|
let ioRead = item.value.map(function (item: any) {
|
||||||
return Number((item.read / 1024).toFixed(2));
|
return Number((item.read / 1024).toFixed(2));
|
||||||
|
|
@ -527,41 +551,19 @@ function initIOCharts(item: Host.MonitorData) {
|
||||||
tooltip: {
|
tooltip: {
|
||||||
trigger: 'axis',
|
trigger: 'axis',
|
||||||
formatter: function (datas: any) {
|
formatter: function (datas: any) {
|
||||||
let res = datas[0].name + '<br/>';
|
let res = loadDate(datas[0].name);
|
||||||
for (const item of datas) {
|
for (const item of datas) {
|
||||||
if (
|
if (
|
||||||
item.seriesName === i18n.global.t('monitor.read') ||
|
item.seriesName === i18n.global.t('monitor.read') ||
|
||||||
item.seriesName === i18n.global.t('monitor.write')
|
item.seriesName === i18n.global.t('monitor.write')
|
||||||
) {
|
) {
|
||||||
res +=
|
res += loadSeries(item, computeSizeFromKBs(item.data), '');
|
||||||
item.marker +
|
|
||||||
' ' +
|
|
||||||
item.seriesName +
|
|
||||||
i18n.global.t('commons.colon') +
|
|
||||||
computeSizeFromKBs(item.data) +
|
|
||||||
'<br/>';
|
|
||||||
}
|
}
|
||||||
if (item.seriesName === i18n.global.t('monitor.readWriteCount')) {
|
if (item.seriesName === i18n.global.t('monitor.readWriteCount')) {
|
||||||
res +=
|
res += loadSeries(item, item.data, i18n.global.t('commons.units.time') + '/s');
|
||||||
item.marker +
|
|
||||||
' ' +
|
|
||||||
item.seriesName +
|
|
||||||
i18n.global.t('commons.colon') +
|
|
||||||
item.data +
|
|
||||||
' ' +
|
|
||||||
i18n.global.t('commons.units.time') +
|
|
||||||
'/s' +
|
|
||||||
'<br/>';
|
|
||||||
}
|
}
|
||||||
if (item.seriesName === i18n.global.t('monitor.readWriteTime')) {
|
if (item.seriesName === i18n.global.t('monitor.readWriteTime')) {
|
||||||
res +=
|
res += loadSeries(item, item.data, ' ms');
|
||||||
item.marker +
|
|
||||||
' ' +
|
|
||||||
item.seriesName +
|
|
||||||
i18n.global.t('commons.colon') +
|
|
||||||
item.data +
|
|
||||||
' ms' +
|
|
||||||
'<br/>';
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return res;
|
return res;
|
||||||
|
|
@ -593,13 +595,122 @@ function loadEmptyDate(timeRange: any) {
|
||||||
function loadEmptyData() {
|
function loadEmptyData() {
|
||||||
return [0, 0];
|
return [0, 0];
|
||||||
}
|
}
|
||||||
|
function loadTopEmptyData() {
|
||||||
|
return [{ value: 0, top: 0, unit: '' }];
|
||||||
|
}
|
||||||
|
|
||||||
|
function withCPUProcess(datas: any) {
|
||||||
|
let tops;
|
||||||
|
let res = loadDate(datas[0].name);
|
||||||
|
for (const item of datas) {
|
||||||
|
if (item.data?.top) {
|
||||||
|
tops = item.data?.top;
|
||||||
|
}
|
||||||
|
res += loadSeries(item, item.data.value ? item.data.value : item.data, item.data.unit || '');
|
||||||
|
}
|
||||||
|
if (!tops) {
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
res += `
|
||||||
|
<div style="margin-top: 10px; border-bottom: 1px dashed black;"></div>
|
||||||
|
<table style="border-collapse: collapse; margin-top: 20px; font-size: 12px;">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th style="padding: 6px 8px;">PID</th>
|
||||||
|
<th style="padding: 6px 8px;">${i18n.global.t('commons.table.user')}</th>
|
||||||
|
<th style="padding: 6px 8px;">${i18n.global.t('menu.process')}</th>
|
||||||
|
<th style="padding: 6px 8px;">${i18n.global.t('monitor.percent')}</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
`;
|
||||||
|
for (const row of tops) {
|
||||||
|
res += `
|
||||||
|
<tr>
|
||||||
|
<td style="padding: 6px 8px; text-align: center;">
|
||||||
|
${row.pid}
|
||||||
|
</td>
|
||||||
|
<td style="padding: 6px 8px; text-align: center;">
|
||||||
|
${row.user}
|
||||||
|
</td>
|
||||||
|
<td style="padding: 6px 8px; text-align: center;">
|
||||||
|
${row.name}
|
||||||
|
</td>
|
||||||
|
<td style="padding: 6px 8px; text-align: center;">
|
||||||
|
${row.percent.toFixed(2)}%
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
`;
|
||||||
|
}
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
function withMemProcess(datas: any) {
|
||||||
|
let res = loadDate(datas[0].name);
|
||||||
|
for (const item of datas) {
|
||||||
|
res += loadSeries(item, item.data.value ? item.data.value : item.data, ' %');
|
||||||
|
}
|
||||||
|
if (!datas[0].data.top) {
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
res += `
|
||||||
|
<div style="margin-top: 10px; border-bottom: 1px dashed black;"></div>
|
||||||
|
<table style="border-collapse: collapse; margin-top: 20px; font-size: 12px;">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th style="padding: 6px 8px;">PID</th>
|
||||||
|
<th style="padding: 6px 8px;">${i18n.global.t('commons.table.user')}</th>
|
||||||
|
<th style="padding: 6px 8px;">${i18n.global.t('menu.process')}</th>
|
||||||
|
<th style="padding: 6px 8px;">${i18n.global.t('monitor.memory')}</th>
|
||||||
|
<th style="padding: 6px 8px;">${i18n.global.t('monitor.percent')}</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
`;
|
||||||
|
for (const item of datas) {
|
||||||
|
for (const row of item.data.top) {
|
||||||
|
res += `
|
||||||
|
<tr>
|
||||||
|
<td style="padding: 6px 8px; text-align: center;">
|
||||||
|
<span style="display: inline-block;"></span>
|
||||||
|
${row.pid}
|
||||||
|
</td>
|
||||||
|
<td style="padding: 6px 8px; text-align: center;">
|
||||||
|
${row.user}
|
||||||
|
</td>
|
||||||
|
<td style="padding: 6px 8px; text-align: center;">
|
||||||
|
${row.name}
|
||||||
|
</td>
|
||||||
|
<td style="padding: 6px 8px; text-align: center;">
|
||||||
|
${computeSize(row.memory)}
|
||||||
|
</td>
|
||||||
|
<td style="padding: 6px 8px; text-align: center;">
|
||||||
|
${row.percent.toFixed(2)}%
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
`;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
function loadDate(name: any) {
|
||||||
|
return ` <div style="display: inline-block; width: 100%; padding-bottom: 10px;">
|
||||||
|
${i18n.global.t('commons.search.date')}: ${name}
|
||||||
|
</div>`;
|
||||||
|
}
|
||||||
|
|
||||||
|
function loadSeries(item: any, data: any, unit: any) {
|
||||||
|
return `<div style="width: 100%;">
|
||||||
|
${item.marker} ${item.seriesName}: ${data} ${unit}
|
||||||
|
</div>`;
|
||||||
|
}
|
||||||
|
|
||||||
function getSideWidth(b: boolean) {
|
function getSideWidth(b: boolean) {
|
||||||
return !b || document.body.clientWidth > 1600 ? '7%' : '10%';
|
return !b || document.body.clientWidth > 1600 ? '7%' : '10%';
|
||||||
}
|
}
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
zoomStart.value = dateFormatWithoutYear(new Date(new Date().setHours(0, 0, 0, 0)));
|
|
||||||
loadNetworkOptions();
|
loadNetworkOptions();
|
||||||
loadIOOptions();
|
loadIOOptions();
|
||||||
});
|
});
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue