diff --git a/glances/plugins/cpu/__init__.py b/glances/plugins/cpu/__init__.py index b534a0df..faec352c 100644 --- a/glances/plugins/cpu/__init__.py +++ b/glances/plugins/cpu/__init__.py @@ -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.""" diff --git a/glances/plugins/irq/__init__.py b/glances/plugins/irq/__init__.py index 0e2bda19..3e7001fd 100644 --- a/glances/plugins/irq/__init__.py +++ b/glances/plugins/irq/__init__.py @@ -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 diff --git a/glances/plugins/mem/__init__.py b/glances/plugins/mem/__init__.py index e4404ab2..7eea9694 100644 --- a/glances/plugins/mem/__init__.py +++ b/glances/plugins/mem/__init__.py @@ -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.""" diff --git a/glances/plugins/plugin/model.py b/glances/plugins/plugin/model.py index 17c7dc4f..45e9805f 100644 --- a/glances/plugins/plugin/model.py +++ b/glances/plugins/plugin/model.py @@ -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 diff --git a/glances/plugins/quicklook/__init__.py b/glances/plugins/quicklook/__init__.py index d69647e8..f6152993 100644 --- a/glances/plugins/quicklook/__init__.py +++ b/glances/plugins/quicklook/__init__.py @@ -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 diff --git a/glances/plugins/wifi/__init__.py b/glances/plugins/wifi/__init__.py index 189c2401..4fe7ed4b 100644 --- a/glances/plugins/wifi/__init__.py +++ b/glances/plugins/wifi/__init__.py @@ -45,6 +45,7 @@ fields_description = { 'quality_level': { 'description': 'Signal strong level.', 'unit': 'dBm', + 'alert': True, }, }