diff --git a/src/dashboard.py b/src/dashboard.py index b861ae2..fde3e0d 100644 --- a/src/dashboard.py +++ b/src/dashboard.py @@ -2948,74 +2948,77 @@ def API_Email_PreviewBody(): except Exception as e: return ResponseObject(False, message=str(e)) - +from modules.SystemStatus import SystemStatus +SystemStatus = SystemStatus() @app.get(f'{APP_PREFIX}/api/systemStatus') def API_SystemStatus(): - cpu_percpu = psutil.cpu_percent(interval=0.5, percpu=True) - cpu = psutil.cpu_percent(interval=0.5) - memory = psutil.virtual_memory() - swap_memory = psutil.swap_memory() - disks = psutil.disk_partitions() - network = psutil.net_io_counters(pernic=True, nowrap=True) - - status = { - "cpu": { - "cpu_percent": cpu, - "cpu_percent_per_cpu": cpu_percpu, - }, - "memory": { - "virtual_memory": { - "total": memory.total, - "available": memory.available, - "percent": memory.percent - }, - "swap_memory": { - "total": swap_memory.total, - "used": swap_memory.used, - "percent": swap_memory.percent - } - }, - "disk": {}, - "network": {}, - "process": { - "cpu_top_10": [], - "memory_top_10": [] - } - } - for d in disks: - detail = psutil.disk_usage(d.mountpoint) - status['disk'][d.mountpoint] = { - "total": detail.total, - "used": detail.used, - "free": detail.free, - "percent": detail.percent - } - for i in network.keys(): - status["network"][i] = { - "byte_sent": network[i].bytes_sent, - "byte_recv": network[i].bytes_recv - } - - while True: - try: - processes = list(psutil.process_iter()) - status["process"]["cpu_top_10"] = sorted(list(map(lambda x : { - "name": x.name(), - "command": " ".join(x.cmdline()), - "pid": x.pid, - "cpu_percent": x.cpu_percent() - }, processes)), key=lambda x : x['cpu_percent'], reverse=True)[:10] - status["process"]["memory_top_10"] = sorted(list(map(lambda x : { - "name": x.name(), - "command": " ".join(x.cmdline()), - "pid": x.pid, - "memory_percent": x.memory_percent() - }, processes)), key=lambda x : x['memory_percent'], reverse=True)[:10] - break - except Exception as e: - continue - return ResponseObject(data=status) + # cpu_percpu = psutil.cpu_percent(interval=0.5, percpu=True) + # cpu = psutil.cpu_percent(interval=0.5) + # memory = psutil.virtual_memory() + # swap_memory = psutil.swap_memory() + # disks = psutil.disk_partitions() + # network = psutil.net_io_counters(pernic=True, nowrap=True) + # + # + # status = { + # "cpu": { + # "cpu_percent": cpu, + # "cpu_percent_per_cpu": cpu_percpu, + # }, + # "memory": { + # "virtual_memory": { + # "total": memory.total, + # "available": memory.available, + # "percent": memory.percent + # }, + # "swap_memory": { + # "total": swap_memory.total, + # "used": swap_memory.used, + # "percent": swap_memory.percent + # } + # }, + # "disk": {}, + # "network": {}, + # "process": { + # "cpu_top_10": [], + # "memory_top_10": [] + # }, + # "SystemStatus": systemStatus + # } + # for d in disks: + # detail = psutil.disk_usage(d.mountpoint) + # status['disk'][d.mountpoint] = { + # "total": detail.total, + # "used": detail.used, + # "free": detail.free, + # "percent": detail.percent + # } + # for i in network.keys(): + # status["network"][i] = { + # "byte_sent": network[i].bytes_sent, + # "byte_recv": network[i].bytes_recv + # } + # + # while True: + # try: + # processes = list(psutil.process_iter()) + # status["process"]["cpu_top_10"] = sorted(list(map(lambda x : { + # "name": x.name(), + # "command": " ".join(x.cmdline()), + # "pid": x.pid, + # "cpu_percent": x.cpu_percent() + # }, processes)), key=lambda x : x['cpu_percent'], reverse=True)[:10] + # status["process"]["memory_top_10"] = sorted(list(map(lambda x : { + # "name": x.name(), + # "command": " ".join(x.cmdline()), + # "pid": x.pid, + # "memory_percent": x.memory_percent() + # }, processes)), key=lambda x : x['memory_percent'], reverse=True)[:10] + # break + # except Exception as e: + # continue + return ResponseObject(data=SystemStatus) @app.get(f'{APP_PREFIX}/api/protocolsEnabled') def API_ProtocolsEnabled(): diff --git a/src/modules/SystemStatus.py b/src/modules/SystemStatus.py index 95b2257..adffe8b 100644 --- a/src/modules/SystemStatus.py +++ b/src/modules/SystemStatus.py @@ -3,7 +3,25 @@ from asyncio.subprocess import Process import psutil class SystemStatus: - pass + def __init__(self): + self.CPU = CPU() + self.MemoryVirtual = Memory('virtual') + self.MemorySwap = Memory('swap') + self.Disks = Disks() + self.NetworkInterfaces = NetworkInterfaces() + self.Processes = Processes() + def toJson(self): + return { + "CPU": self.CPU, + "Memory": { + "VirtualMemory": self.MemoryVirtual, + "SwapMemory": self.MemorySwap + }, + "Disks": self.Disks, + "NetworkInterfaces": self.NetworkInterfaces, + "Processes": self.Processes + } + class CPU: def __init__(self): @@ -11,8 +29,8 @@ class CPU: self.cpu_percent_per_cpu: list[float] = [] def getData(self): try: - self.cpu_percent = psutil.cpu_percent(interval=0.5, percpu=True) - self.cpu_percent_per_cpu = psutil.cpu_percent(interval=0.5) + self.cpu_percent_per_cpu = psutil.cpu_percent(interval=0.5, percpu=True) + self.cpu_percent = psutil.cpu_percent(interval=0.5) except Exception as e: pass def toJson(self): @@ -21,22 +39,37 @@ class CPU: class Memory: def __init__(self, memoryType: str): - self.__memoryType = memoryType + self.__memoryType__ = memoryType self.total = 0 self.available = 0 self.percent = 0 def getData(self): - if self.__memoryType == "virtual": - memory = psutil.virtual_memory() - else: - memory = psutil.swap_memory() - self.total = memory.total - self.available = memory.available - self.percent = memory.percent + try: + if self.__memoryType__ == "virtual": + memory = psutil.virtual_memory() + else: + memory = psutil.swap_memory() + self.total = memory.total + self.available = memory.available + self.percent = memory.percent + except Exception as e: + pass def toJson(self): self.getData() return self.__dict__ - + +class Disks: + def __init__(self): + self.disks : list[Disk] = [] + def getData(self): + try: + self.disks = list(map(lambda x : Disk(x.mountpoint), psutil.disk_partitions())) + except Exception as e: + pass + def toJson(self): + self.getData() + return self.disks + class Disk: def __init__(self, mountPoint: str): self.total = 0 @@ -45,11 +78,14 @@ class Disk: self.percent = 0 self.mountPoint = mountPoint def getData(self): - disk = psutil.disk_usage(self.mountPoint) - self.total = disk.total - self.free = disk.free - self.used = disk.used - self.percent = disk.percent + try: + disk = psutil.disk_usage(self.mountPoint) + self.total = disk.total + self.free = disk.free + self.used = disk.used + self.percent = disk.percent + except Exception as e: + pass def toJson(self): self.getData() return self.__dict__ @@ -58,9 +94,12 @@ class NetworkInterfaces: def __init__(self): self.interfaces = {} def getData(self): - network = psutil.net_io_counters(pernic=True, nowrap=True) - for i in network.keys(): - self.interfaces[i] = network[i]._asdict() + try: + network = psutil.net_io_counters(pernic=True, nowrap=True) + for i in network.keys(): + self.interfaces[i] = network[i]._asdict() + except Exception as e: + pass def toJson(self): self.getData() return self.interfaces @@ -78,19 +117,21 @@ class Processes: self.CPU_Top_10_Processes: list[Processes.Process] = [] self.Memory_Top_10_Processes: list[Processes.Process] = [] def getData(self): - processes = list(psutil.process_iter()) - self.CPU_Top_10_Processes = sorted(list(map(lambda x : - Processes.Process(x.name(), " ".join(x.cmdline()), x.pid, x.cpu_percent()), processes)), - key=lambda x : x.percent, reverse=True)[:10] - self.Memory_Top_10_Processes = sorted(list(map(lambda x : - Processes.Process(x.name(), " ".join(x.cmdline()), x.pid, x.memory_percent()), processes)), - key=lambda x : x.percent, reverse=True)[:10] + while True: + try: + processes = list(psutil.process_iter()) + self.CPU_Top_10_Processes = sorted( + list(map(lambda x : Processes.Process(x.name(), " ".join(x.cmdline()), x.pid, x.cpu_percent()), processes)), + key=lambda x : x.percent, reverse=True)[:20] + self.Memory_Top_10_Processes = sorted( + list(map(lambda x : Processes.Process(x.name(), " ".join(x.cmdline()), x.pid, x.memory_percent()), processes)), + key=lambda x : x.percent, reverse=True)[:20] + break + except Exception as e: + continue def toJson(self): self.getData() return { "cpu_top_10": self.CPU_Top_10_Processes, "memory_top_10": self.Memory_Top_10_Processes - } - -p = Processes() -print(p.toJson()) \ No newline at end of file + } \ No newline at end of file diff --git a/src/static/app/src/components/systemStatusComponents/process.vue b/src/static/app/src/components/systemStatusComponents/process.vue index 63c0c23..6115cc2 100644 --- a/src/static/app/src/components/systemStatusComponents/process.vue +++ b/src/static/app/src/components/systemStatusComponents/process.vue @@ -10,7 +10,7 @@ const props = defineProps(["process", "cpu"]) {{process.command ? process.command : process.name}} - {{cpu ? process.cpu_percent : (Math.round((process.memory_percent + Number.EPSILON) * 10) / 10)}}% + {{(Math.round((process.percent + Number.EPSILON) * 10) / 10)}}% diff --git a/src/static/app/src/components/systemStatusComponents/storageMount.vue b/src/static/app/src/components/systemStatusComponents/storageMount.vue index 488cbe7..8e03260 100644 --- a/src/static/app/src/components/systemStatusComponents/storageMount.vue +++ b/src/static/app/src/components/systemStatusComponents/storageMount.vue @@ -2,8 +2,7 @@ import {computed, ref} from "vue"; const props = defineProps({ - mount: String, - percentage: Number, + mount: Object, align: Boolean, square: Boolean }) @@ -19,7 +18,7 @@ const squareHeight = computed(() => {
+ :style="{'background-color': `rgb(25 135 84 / ${mount.percent}%)`}">
{ :class="[align ? 'end-0':'start-0']" > - {{mount}} + {{mount.mountPoint}} - {{percentage}}% + {{mount.percent}}%
diff --git a/src/static/app/src/components/systemStatusComponents/systemStatusWidget.vue b/src/static/app/src/components/systemStatusComponents/systemStatusWidget.vue index 545db64..4f923c0 100644 --- a/src/static/app/src/components/systemStatusComponents/systemStatusWidget.vue +++ b/src/static/app/src/components/systemStatusComponents/systemStatusWidget.vue @@ -7,8 +7,6 @@ import StorageMount from "@/components/systemStatusComponents/storageMount.vue"; import {DashboardConfigurationStore} from "@/stores/DashboardConfigurationStore.js"; const dashboardStore = DashboardConfigurationStore() - -// const data = ref(undefined) let interval = null; onMounted(() => { @@ -43,19 +41,19 @@ const data = computed(() => {
- {{ data.cpu.cpu_percent }}% + {{ data.CPU.cpu_percent }}%
-
+
@@ -68,20 +66,20 @@ const data = computed(() => {
- {{ data?.disk['/'].percent }}% + {{ data?.Disks.find(x => x.mountPoint === '/').percent }}%
-
+
-
@@ -93,13 +91,13 @@ const data = computed(() => {
- {{ data?.memory.virtual_memory.percent }}% + {{ data?.Memory.VirtualMemory.percent }}%
-
+
@@ -110,13 +108,13 @@ const data = computed(() => {
- {{ data?.memory.swap_memory.percent }}% + {{ data?.Memory.SwapMemory.percent }}%
-
+
diff --git a/src/static/app/src/views/systemStatus.vue b/src/static/app/src/views/systemStatus.vue index 84903ad..50d9f77 100644 --- a/src/static/app/src/views/systemStatus.vue +++ b/src/static/app/src/views/systemStatus.vue @@ -12,6 +12,36 @@ const data = computed(() => { return dashboardStore.SystemStatus }) let interval = null; +import { + Chart, + LineElement, + BarElement, + BarController, + LineController, + LinearScale, + Legend, + Title, + Tooltip, + CategoryScale, + PointElement, + Filler +} from 'chart.js'; +import {Line} from "vue-chartjs"; +import dayjs from "dayjs"; +import {GetLocale} from "@/utilities/locale.js"; +Chart.register( + LineElement, + BarElement, + BarController, + LineController, + LinearScale, + Legend, + Title, + Tooltip, + CategoryScale, + PointElement, + Filler +); onMounted(() => { getData() @@ -24,11 +54,97 @@ onBeforeUnmount(() => { clearInterval(interval) }) +const historicalChartTimestamp = ref([]) +const historicalCpuUsage = ref([]) +const historicalVirtualMemoryUsage = ref([]) +const historicalSwapMemoryUsage = ref([]) +let i = 0.1 const getData = () => { fetchGet("/api/systemStatus", {}, (res) => { + historicalChartTimestamp.value.push(dayjs().format("HH:mm:ss A")) dashboardStore.SystemStatus = res.data + historicalCpuUsage.value.push(res.data.CPU.cpu_percent) + historicalVirtualMemoryUsage.value.push(res.data.Memory.VirtualMemory.percent) + historicalSwapMemoryUsage.value.push(res.data.Memory.SwapMemory.percent) }) } + +const chartOption = computed(() => { + return { + responsive: true, + plugins: { + legend: { + display: true + }, + tooltip: { + callbacks: { + label: (tooltipItem) => { + return `${tooltipItem.formattedValue}%` + } + } + } + }, + scales: { + x: { + ticks: { + display: false, + }, + grid: { + display: false + }, + }, + y:{ + ticks: { + callback: (val, index) => { + return `${val}%` + } + }, + grid: { + display: false + }, + } + } + } +}) +const cpuHistoricalChartData = computed(() => { + return { + labels: [...historicalChartTimestamp.value], + datasets: [ + { + label: GetLocale('CPU Usage'), + data: [...historicalCpuUsage.value], + fill: 'start', + backgroundColor: '#0d6efd50', + borderColor: '#0d6efd', + tension: 0 + } + ] + } +}) + +const memoryHistoricalChartData = computed(() => { + return { + labels: [...historicalChartTimestamp.value], + datasets: [ + { + label: GetLocale('Memory Usage'), + data: [...historicalVirtualMemoryUsage.value], + fill: 1, + borderColor: '#0dcaf0', + backgroundColor: '#0dcaf050', + tension: 0 + }, + { + label: GetLocale('Swap Memory Usage'), + data: [...historicalSwapMemoryUsage.value], + fill: 'start', + backgroundColor: '#ffc10750', + borderColor: '#ffc107', + tension: 0 + } + ] + } +})