Add support for a configuration file.
Adding a coniguration file (/etc/sysmon.ini). This will allow users to no monitor the temperature of speciic drives by ignoring them, as well as ignoring the performance from specific drives. For instance on a system running mdraid, you could ignore performance on all of the drives that make up the raid array, and ignore the temperature of the raid device.
This commit is contained in:
82
monitor/configfile.py
Normal file
82
monitor/configfile.py
Normal file
@@ -0,0 +1,82 @@
|
||||
import configparser
|
||||
|
||||
|
||||
class ConfigClass:
|
||||
'''
|
||||
Handle a .INI style configuration file. Every function is designed to not
|
||||
crash, and always return a default of the items are not present.
|
||||
|
||||
Currently support read-only.
|
||||
'''
|
||||
def __init__( self, filename ):
|
||||
self.filename = filename
|
||||
self.config = configparser.ConfigParser()
|
||||
self.readFile = False
|
||||
self._openConfig()
|
||||
|
||||
def _openConfig(self) -> None:
|
||||
'''
|
||||
Open,, and read in the configuation file. If the file does not exist, keep
|
||||
trying to reopen the file until the file does exist. While this approach does
|
||||
not always help, it does allow for an application polls the configuration file
|
||||
occasionally.
|
||||
|
||||
'''
|
||||
if not self.readFile:
|
||||
_result = self.config.read( self.filename )
|
||||
if len(_result) > 0:
|
||||
self.readFile = True
|
||||
|
||||
def getValue( self, section : str, key : str, default="" ) -> str:
|
||||
'''
|
||||
This routine obtains the value of the key within the specified section, if there
|
||||
is such a item.
|
||||
|
||||
Parameter:
|
||||
section - Name of the section to look for
|
||||
key - Key of the value desired
|
||||
default - Value to return if there is no key
|
||||
|
||||
Returns:
|
||||
The value of the key from the section read.
|
||||
'''
|
||||
value = default
|
||||
self._openConfig()
|
||||
try:
|
||||
value = self.config[section][key].replace('"','').strip()
|
||||
except:
|
||||
value = default
|
||||
return value
|
||||
|
||||
def getValueAsList( self, section : str, name : str, default = [] ) -> list[str]:
|
||||
'''
|
||||
This routine looks for the key in the specified section and returns the data if
|
||||
it exists, if not the default value is returned.
|
||||
|
||||
Parameters:
|
||||
section - Section to look for
|
||||
key - Key to return the value of
|
||||
default - If they key or section does not exist, return this value
|
||||
|
||||
Returns:
|
||||
a List of items
|
||||
'''
|
||||
value = default
|
||||
self._openConfig()
|
||||
try:
|
||||
temp = self.config[section][name]
|
||||
value = [ n.replace('"','').strip() for n in temp.split(",")]
|
||||
except:
|
||||
value = default
|
||||
return value
|
||||
|
||||
if __name__ == "__main__":
|
||||
cfg = ConfigClass( "test.ini" )
|
||||
print( f"Value = {cfg.getValue( 'temperature', 'ignore' )}" )
|
||||
print( f"Value = {cfg.getValueAsList( 'temperature', 'ignore' )}" )
|
||||
print( f"Value = {cfg.getValue( 'performance', 'ignore' )}" )
|
||||
print( f"Value = {cfg.getValueAsList( 'performance', 'ignore' )}" )
|
||||
|
||||
cfg = ConfigClass( "missingfile.ini" )
|
||||
|
||||
|
||||
@@ -9,13 +9,11 @@ Requires: PyQt5 (including QtCharts)
|
||||
|
||||
import sys
|
||||
from systemsupport import CPUInfo, CPULoad, multiDriveStat
|
||||
from configfile import ConfigClass
|
||||
|
||||
# --------------------------
|
||||
# Globals
|
||||
# --------------------------
|
||||
cpuinfo = CPUInfo()
|
||||
cpuload = CPULoad()
|
||||
multiDrive = multiDriveStat()
|
||||
|
||||
# --------------------------
|
||||
# UI
|
||||
@@ -25,6 +23,7 @@ from PyQt5.QtCore import Qt, QTimer
|
||||
from PyQt5.QtGui import QPainter
|
||||
from PyQt5.QtWidgets import QApplication, QMainWindow, QWidget, QGridLayout
|
||||
from PyQt5.QtChart import QChart, QChartView, QLineSeries, QValueAxis
|
||||
from PyQt5 import QtGui
|
||||
|
||||
class RollingChart(QWidget):
|
||||
'''
|
||||
@@ -260,6 +259,16 @@ class MonitorWindow(QMainWindow):
|
||||
def __init__(self, refresh_ms: int = 1000, window = 120, parent=None):
|
||||
super().__init__(parent)
|
||||
|
||||
# Get all the filters loaded
|
||||
self.config = ConfigClass("/etc/sysmon.ini")
|
||||
self.driveTempFilter = self.config.getValueAsList( 'temperature', 'ignore' )
|
||||
self.drivePerfFilter = self.config.getValueAsList( 'performance', 'ignore' )
|
||||
|
||||
# Get supporting objects
|
||||
self.cpuinfo = CPUInfo()
|
||||
self.cpuload = CPULoad()
|
||||
self.multiDrive = multiDriveStat()
|
||||
|
||||
self.setWindowTitle("System Monitor")
|
||||
self.setMinimumSize(900, 900)
|
||||
|
||||
@@ -273,14 +282,16 @@ class MonitorWindow(QMainWindow):
|
||||
# Charts
|
||||
self.use_chart = RollingChart(
|
||||
title="CPU Utilization",
|
||||
series_defs=[ (name, None) for name in cpuload.cpuNames ],
|
||||
series_defs=[ (name, None) for name in self.cpuload.cpuNames ],
|
||||
y_min=0, y_max=100,
|
||||
window=120
|
||||
)
|
||||
|
||||
series = [("CPU", None)]
|
||||
for name in multiDrive.drives:
|
||||
series.append( (name,None) )
|
||||
for name in self.multiDrive.drives:
|
||||
if not name in self.driveTempFilter:
|
||||
series.append( (name,None) )
|
||||
|
||||
self.cpu_chart = RollingChart(
|
||||
title="Temperature (°C)",
|
||||
series_defs= series,
|
||||
@@ -296,9 +307,10 @@ class MonitorWindow(QMainWindow):
|
||||
)
|
||||
|
||||
series = []
|
||||
for name in multiDrive.drives:
|
||||
series.append( (f"{name} Read", None) )
|
||||
series.append( (f"{name} Write", None ) )
|
||||
for name in self.multiDrive.drives:
|
||||
if not name in self.drivePerfFilter:
|
||||
series.append( (f"{name} Read", None) )
|
||||
series.append( (f"{name} Write", None ) )
|
||||
|
||||
self.io_chart = RollingChartDynamic(
|
||||
title="Disk I/O",
|
||||
@@ -331,39 +343,42 @@ class MonitorWindow(QMainWindow):
|
||||
|
||||
# Obtain the current fan speed
|
||||
try:
|
||||
fan_speed = cpuinfo.CPUFanSpeed
|
||||
fan_speed = self.cpuinfo.CPUFanSpeed
|
||||
except Exception:
|
||||
fan_speed = None
|
||||
|
||||
# Setup the temperature for the CPU and Drives
|
||||
temperatures = []
|
||||
try:
|
||||
temperatures.append( float(cpuinfo.temperature) )
|
||||
temperatures.append( float(self.cpuinfo.temperature) )
|
||||
except Exception:
|
||||
temperatures.append( 0.0 )
|
||||
|
||||
# Obtain the NVMe device temperature
|
||||
# Obtain the drive temperatures
|
||||
try:
|
||||
for _drive in multiDrive.drives:
|
||||
temperatures.append( multiDrive.driveTemp( _drive ) )
|
||||
for _drive in self.multiDrive.drives:
|
||||
if not _drive in self.driveTempFilter:
|
||||
temperatures.append( self.multiDrive.driveTemp( _drive ) )
|
||||
except Exception:
|
||||
temperatures = [ 0.0 for _ in multiDrive.drives ]
|
||||
temperatures = [ 0.0 for _ in self.multiDrive.drives ]
|
||||
|
||||
# Obtain the NVMe Device read and write rates
|
||||
try:
|
||||
rwData = []
|
||||
drives = multiDrive.readWriteBytes()
|
||||
drives = self.multiDrive.readWriteBytes()
|
||||
for drive in drives:
|
||||
rwData.append( float(drives[drive][0]))
|
||||
rwData.append( float(drives[drive][1]))
|
||||
if not drive in self.drivePerfFilter:
|
||||
rwData.append( float(drives[drive][0]))
|
||||
rwData.append( float(drives[drive][1]))
|
||||
except Exception :
|
||||
rwData = [ None, None ]
|
||||
|
||||
# Get the CPU load precentages
|
||||
try:
|
||||
p = cpuload.getPercentages()
|
||||
values = [p[name] for name in cpuload.cpuNames]
|
||||
p = self.cpuload.getPercentages()
|
||||
values = [p[name] for name in self.cpuload.cpuNames]
|
||||
except Exception:
|
||||
values = [ None for name in cpuload.cpuNames ]
|
||||
values = [ None for name in self.cpuload.cpuNames ]
|
||||
|
||||
# Append to charts
|
||||
self.cpu_chart.append( temperatures )
|
||||
|
||||
@@ -124,14 +124,18 @@ class multiDriveStat():
|
||||
If there is a missing drive from the filter, that drive is eliminated.
|
||||
|
||||
'''
|
||||
def __init__(self):
|
||||
def __init__(self,driveIgnoreList : list[str]=[]):
|
||||
#
|
||||
# Get all drives
|
||||
#
|
||||
self._drives = []
|
||||
with os.popen( 'ls -1 /sys/block | grep -v -e loop -e ram') as command:
|
||||
lsblk_raw = command.read()
|
||||
self._drives = [ l for l in lsblk_raw.split('\n') if l]
|
||||
for l in lsblk_raw.split('\n'):
|
||||
if len(l) == 0:
|
||||
continue
|
||||
if not l in driveIgnoreList:
|
||||
self._drives.append( l )
|
||||
self._stats = [ DriveStats(_) for _ in self._drives ]
|
||||
|
||||
@property
|
||||
|
||||
5
monitor/test.ini
Normal file
5
monitor/test.ini
Normal file
@@ -0,0 +1,5 @@
|
||||
[temperature]
|
||||
ignore = "mmcblk0"
|
||||
|
||||
[performance]
|
||||
ignore = "mmcblk0"
|
||||
Reference in New Issue
Block a user