Refactor code to limit the complexity of update_views method in plugins #3171

This commit is contained in:
nicolargo 2025-05-02 15:01:29 +02:00
parent 03f23a582d
commit dc165930b4
6 changed files with 78 additions and 85 deletions

View File

@ -16,59 +16,65 @@ from glances.plugins.core import CorePlugin
from glances.plugins.plugin.model import GlancesPluginModel
# Fields description
# description: human readable description
# short_name: shortname to use un UI
# unit: unit type
# rate: if True then compute and add *_gauge and *_rate_per_is fields
# min_symbol: Auto unit should be used if value > than 1 'X' (K, M, G)...
# https://github.com/nicolargo/glances/wiki/How-to-create-a-new-plugin-%3F#create-the-plugin-script
fields_description = {
'total': {'description': 'Sum of all CPU percentages (except idle).', 'unit': 'percent'},
'total': {'description': 'Sum of all CPU percentages (except idle).', 'unit': 'percent', 'log': True},
'system': {
'description': 'Percent time spent in kernel space. System CPU time is the \
time spent running code in the Operating System kernel.',
'unit': 'percent',
'log': True,
},
'user': {
'description': 'CPU percent time spent in user space. \
User CPU time is the time spent on the processor running your program\'s code (or code in libraries).',
'unit': 'percent',
'log': True,
},
'iowait': {
'description': '*(Linux)*: percent time spent by the CPU waiting for I/O \
operations to complete.',
'unit': 'percent',
'log': True,
},
'dpc': {
'description': '*(Windows)*: time spent servicing deferred procedure calls (DPCs)',
'unit': 'percent',
'log': True,
},
'idle': {
'description': 'percent of CPU used by any program. Every program or task \
that runs on a computer system occupies a certain amount of processing \
time on the CPU. If the CPU has completed all tasks it is idle.',
'unit': 'percent',
'optional': True,
},
'irq': {
'description': '*(Linux and BSD)*: percent time spent servicing/handling \
hardware/software interrupts. Time servicing interrupts (hardware + \
software).',
'unit': 'percent',
'optional': True,
},
'nice': {
'description': '*(Unix)*: percent time occupied by user level processes with \
a positive nice value. The time the CPU has spent running users\' \
processes that have been *niced*.',
'unit': 'percent',
'optional': True,
},
'steal': {
'description': '*(Linux)*: percentage of time a virtual CPU waits for a real \
CPU while the hypervisor is servicing another virtual processor.',
'unit': 'percent',
'alert': True,
'optional': True,
},
'guest': {
'description': '*(Linux)*: time spent running a virtual CPU for guest operating \
systems under the control of the Linux kernel.',
'unit': 'percent',
'optional': True,
},
'ctx_switches': {
'description': 'number of context switches (voluntary + involuntary) per \
@ -79,6 +85,7 @@ another while ensuring that the tasks do not conflict.',
'rate': True,
'min_symbol': 'K',
'short_name': 'ctx_sw',
'optional': True,
},
'interrupts': {
'description': 'number of interrupts per second.',
@ -86,6 +93,7 @@ another while ensuring that the tasks do not conflict.',
'rate': True,
'min_symbol': 'K',
'short_name': 'inter',
'optional': True,
},
'soft_interrupts': {
'description': 'number of software interrupts per second. Always set to \
@ -94,6 +102,7 @@ another while ensuring that the tasks do not conflict.',
'rate': True,
'min_symbol': 'K',
'short_name': 'sw_int',
'optional': True,
},
'syscalls': {
'description': 'number of system calls per second. Always 0 on Linux OS.',
@ -101,6 +110,7 @@ another while ensuring that the tasks do not conflict.',
'rate': True,
'min_symbol': 'K',
'short_name': 'sys_call',
'optional': True,
},
'cpucore': {'description': 'Total number of CPU core.', 'unit': 'number'},
'time_since_update': {'description': 'Number of seconds since last update.', 'unit': 'seconds'},
@ -273,15 +283,6 @@ class CpuPlugin(GlancesPluginModel):
super().update_views()
# Add specifics information
# Alert and log
for key in ['user', 'system', 'iowait', 'dpc', 'total']:
if key in self.stats:
self.views[key]['decoration'] = self.get_alert_log(self.stats[key], header=key)
# Alert only
for key in ['steal']:
if key in self.stats:
self.views[key]['decoration'] = self.get_alert(self.stats[key], header=key)
# Alert only but depend on Core number
for key in ['ctx_switches']:
# Skip alert if no timespan to measure
if self.stats.get('time_since_update', 0) == 0:
@ -290,20 +291,6 @@ class CpuPlugin(GlancesPluginModel):
self.views[key]['decoration'] = self.get_alert(
self.stats[key], maximum=100 * self.stats['cpucore'], header=key
)
# Optional
for key in [
'nice',
'irq',
'idle',
'steal',
'guest',
'ctx_switches',
'interrupts',
'soft_interrupts',
'syscalls',
]:
if key in self.stats:
self.views[key]['optional'] = True
def msg_curse(self, args=None, max_width=None):
"""Return the list to display in the UI."""

View File

@ -80,11 +80,6 @@ class IrqPlugin(GlancesPluginModel):
return self.stats
def update_views(self):
"""Update stats views."""
# Call the father's method
super().update_views()
def msg_curse(self, args=None, max_width=None):
"""Return the dict to display in the curse interface."""
# Init the return message

View File

@ -43,20 +43,28 @@ note that this doesn\'t reflect the actual memory available (use \'available\' i
'description': '*(UNIX)*: memory currently in use or very recently used, and so it is in RAM.',
'unit': 'bytes',
'min_symbol': 'K',
'optional': True,
},
'inactive': {
'description': '*(UNIX)*: memory that is marked as not used.',
'unit': 'bytes',
'min_symbol': 'K',
'short_name': 'inacti',
'optional': True,
},
'buffers': {
'description': '*(Linux, BSD)*: cache for things like file system metadata.',
'unit': 'bytes',
'min_symbol': 'K',
'short_name': 'buffer',
'optional': True,
},
'cached': {
'description': '*(Linux, BSD)*: cache for various things.',
'unit': 'bytes',
'min_symbol': 'K',
'optional': True,
},
'cached': {'description': '*(Linux, BSD)*: cache for various things.', 'unit': 'bytes', 'min_symbol': 'K'},
'wired': {
'description': '*(BSD, macOS)*: memory that is marked to always stay in RAM. It is never moved to disk.',
'unit': 'bytes',
@ -237,10 +245,6 @@ class MemPlugin(GlancesPluginModel):
# Add specifics information
# Alert and log
self.views['percent']['decoration'] = self.get_alert_log(self.stats['used'], maximum=self.stats['total'])
# Optional
for key in ['active', 'inactive', 'buffers', 'cached']:
if key in self.stats:
self.views[key]['optional'] = True
def msg_curse(self, args=None, max_width=None):
"""Return the dict to display in the curse interface."""

View File

@ -440,6 +440,54 @@ class GlancesPluginModel:
return default
return self.fields_description[item].get(key, default)
def _build_field_decoration(self, field):
"""Return the field decoration.
The decoration is used to display the field in the UI.
"""
# Manage the decoration
if self.fields_description and field in self.fields_description:
if (
self.fields_description[field].get('rate') is True
and isinstance(self.stats, dict)
and self.stats.get('time_since_update', 0) == 0
):
return 'DEFAULT'
if self.fields_description[field].get('log') is True:
return self.get_alert_log(self.stats[field], header=field)
if self.fields_description[field].get('alert') is True:
return self.get_alert(self.stats[field], header=field)
return 'DEFAULT'
def _build_field_optional(self, field):
"""Return true if the field is optional."""
if self.fields_description and field in self.fields_description:
return self.fields_description[field].get('optional', False)
return False
def _build_view_for_field(self, field):
value = {
'decoration': self._build_field_decoration(field),
'optional': self._build_field_optional(field),
'additional': False,
'splittable': False,
'hidden': False,
}
# Manage the hidden feature
# Allow to automatically hide fields when values is never different than 0
# Refactoring done for #2929
if not self.hide_zero:
value['hidden'] = False
elif field in self.views and 'hidden' in self.views[field]:
value['hidden'] = self.views[field]['hidden']
if field in self.hide_zero_fields and self.get_raw()[field] >= self.hide_threshold_bytes:
value['hidden'] = False
else:
value['hidden'] = field in self.hide_zero_fields
return value
def update_views(self):
"""Update the stats views.
@ -454,56 +502,17 @@ class GlancesPluginModel:
"""
ret = {}
if isinstance(self.get_raw(), list) and self.get_raw() is not None and self.get_key() is not None:
if self.get_raw() is not None and isinstance(self.get_raw(), list) and self.get_key() is not None:
# Stats are stored in a list of dict (ex: DISKIO, NETWORK, FS...)
for i in self.get_raw():
key = i[self.get_key()]
ret[key] = {}
for field in listkeys(i):
value = {
'decoration': 'DEFAULT',
'optional': False,
'additional': False,
'splittable': False,
}
# Manage the hidden feature
# Allow to automatically hide fields when values is never different than 0
# Refactoring done for #2929
if not self.hide_zero:
value['hidden'] = False
elif key in self.views and field in self.views[key] and 'hidden' in self.views[key][field]:
value['hidden'] = self.views[key][field]['hidden']
if (
field in self.hide_zero_fields
and i[field] is not None
and i[field] > self.hide_threshold_bytes
):
value['hidden'] = False
else:
value['hidden'] = field in self.hide_zero_fields
ret[key][field] = value
ret[key][field] = self._build_view_for_field(field)
elif isinstance(self.get_raw(), dict) and self.get_raw() is not None:
# Stats are stored in a dict (ex: CPU, LOAD...)
for field in listkeys(self.get_raw()):
value = {
'decoration': 'DEFAULT',
'optional': False,
'additional': False,
'splittable': False,
'hidden': False,
}
# Manage the hidden feature
# Allow to automatically hide fields when values is never different than 0
# Refactoring done for #2929
if not self.hide_zero:
value['hidden'] = False
elif field in self.views and 'hidden' in self.views[field]:
value['hidden'] = self.views[field]['hidden']
if field in self.hide_zero_fields and self.get_raw()[field] >= self.hide_threshold_bytes:
value['hidden'] = False
else:
value['hidden'] = field in self.hide_zero_fields
ret[field] = value
ret[field] = self._build_view_for_field(field)
self.views = ret

View File

@ -39,6 +39,7 @@ fields_description = {
'load': {
'description': 'LOAD percent usage',
'unit': 'percent',
'alert': True,
},
'cpu_log_core': {
'description': 'Number of logical CPU core',
@ -158,10 +159,6 @@ class QuicklookPlugin(GlancesPluginModel):
if key in self.stats:
self.views[key]['decoration'] = self.get_alert(self.stats[key], header=key)
# Alert for LOAD
if 'load' in self.stats:
self.views['load']['decoration'] = self.get_alert(self.stats['load'], header='load')
# Define the list of stats to display
self.views['list'] = self.stats_list

View File

@ -45,6 +45,7 @@ fields_description = {
'quality_level': {
'description': 'Signal strong level.',
'unit': 'dBm',
'alert': True,
},
}