From ef9694cd6ada357c56b338bb5aa069575a7c397b Mon Sep 17 00:00:00 2001 From: nicolargo Date: Sat, 20 Jan 2024 14:56:57 +0100 Subject: [PATCH 1/7] First version of the #2662 - Need to study how to display the swap --- conf/glances.conf | 4 ++ glances/outputs/glances_bars.py | 31 ++++++++----- glances/plugins/load/__init__.py | 66 +++++++++++++++++---------- glances/plugins/quicklook/__init__.py | 49 ++++++++++++++------ 4 files changed, 102 insertions(+), 48 deletions(-) diff --git a/conf/glances.conf b/conf/glances.conf index 4f07a8b0..75512743 100644 --- a/conf/glances.conf +++ b/conf/glances.conf @@ -57,6 +57,10 @@ mem_critical=90 swap_careful=50 swap_warning=70 swap_critical=90 +# Source: http://blog.scoutapp.com/articles/2009/07/31/understanding-load-averages +load_careful=70 +load_warning=100 +load_critical=500 [system] # This plugin display the first line in the Glances UI with: diff --git a/glances/outputs/glances_bars.py b/glances/outputs/glances_bars.py index 75899480..8e803fd6 100644 --- a/glances/outputs/glances_bars.py +++ b/glances/outputs/glances_bars.py @@ -28,7 +28,12 @@ class Bar(object): sys.stdout.flush() """ - def __init__(self, size, percentage_char='|', empty_char=' ', pre_char='[', post_char=']', with_text=True): + def __init__(self, size, + percentage_char='|', + empty_char=' ', + pre_char='[', post_char=']', + display_value=True, + min_value=0, max_value=100): # Build curses_bars self.__curses_bars = [empty_char] * 5 + [percentage_char] * 5 # Bar size @@ -36,20 +41,20 @@ class Bar(object): # Bar current percent self.__percent = 0 # Min and max value - self.min_value = 0 - self.max_value = 100 + self.min_value = min_value + self.max_value = max_value # Char used for the decoration self.__pre_char = pre_char self.__post_char = post_char self.__empty_char = empty_char - self.__with_text = with_text + self.__display_value = display_value @property def size(self, with_decoration=False): # Return the bar size, with or without decoration if with_decoration: return self.__size - if self.__with_text: + if self.__display_value: return self.__size - 6 @property @@ -58,10 +63,8 @@ class Bar(object): @percent.setter def percent(self, value): - if value <= self.min_value: + if value < self.min_value: value = self.min_value - if value >= self.max_value: - value = self.max_value self.__percent = value @property @@ -74,14 +77,20 @@ class Bar(object): def get(self): """Return the bars.""" - frac, whole = modf(self.size * self.percent / 100.0) + value = self.percent + if value > self.max_value: + value = self.max_value + frac, whole = modf(self.size * value / 100.0) ret = self.__curses_bars[8] * int(whole) if frac > 0: ret += self.__curses_bars[int(frac * 8)] whole += 1 ret += self.__empty_char * int(self.size - whole) - if self.__with_text: - ret = '{}{:5.1f}%'.format(ret, self.percent) + if self.__display_value: + if self.percent > self.max_value: + ret = '{}>{:4.0f}%'.format(ret, self.max_value) + else: + ret = '{}{:5.1f}%'.format(ret, self.percent) return ret def __str__(self): diff --git a/glances/plugins/load/__init__.py b/glances/plugins/load/__init__.py index 292821dd..cc936078 100644 --- a/glances/plugins/load/__init__.py +++ b/glances/plugins/load/__init__.py @@ -58,6 +58,14 @@ items_history_list = [ {'name': 'min15', 'description': '15 minutes load'}, ] +# Get the number of logical CPU core only once +# the variable is also shared with the QuickLook plugin +try: + nb_log_core = CorePluginModel().update()["log"] +except Exception as e: + logger.warning('Error: Can not retrieve the CPU core number (set it to 1) ({})'.format(e)) + nb_log_core = 1 + class PluginModel(GlancesPluginModel): """Glances load plugin. @@ -74,24 +82,6 @@ class PluginModel(GlancesPluginModel): # We want to display the stat in the curse interface self.display_curse = True - # Call CorePluginModel in order to display the core number - try: - self.nb_log_core = CorePluginModel(args=self.args).update()["log"] - except Exception as e: - logger.warning('Error: Can not retrieve the CPU core number (set it to 1) ({})'.format(e)) - self.nb_log_core = 1 - - def _getloadavg(self): - """Get load average. On both Linux and Windows thanks to PsUtil""" - try: - return psutil.getloadavg() - except (AttributeError, OSError): - pass - try: - return os.getloadavg() - except (AttributeError, OSError): - return None - @GlancesPluginModel._check_decorator @GlancesPluginModel._log_result_decorator def update(self): @@ -103,11 +93,16 @@ class PluginModel(GlancesPluginModel): # Update stats using the standard system lib # Get the load using the os standard lib - load = self._getloadavg() + load = get_load_average() if load is None: stats = self.get_init_value() else: - stats = {'min1': load[0], 'min5': load[1], 'min15': load[2], 'cpucore': self.nb_log_core} + stats = { + 'min1': load[0], + 'min5': load[1], + 'min15': load[2], + 'cpucore': get_nb_log_core() + } elif self.input_method == 'snmp': # Update stats using SNMP @@ -122,7 +117,7 @@ class PluginModel(GlancesPluginModel): for k, v in iteritems(stats): stats[k] = float(v) - stats['cpucore'] = self.nb_log_core + stats['cpucore'] = get_nb_log_core() # Update the stats self.stats = stats @@ -170,9 +165,9 @@ class PluginModel(GlancesPluginModel): ret.append(self.curse_new_line()) msg = '{:7}'.format('{} min'.format(load_time)) ret.append(self.curse_add_line(msg)) - if args.disable_irix and self.nb_log_core != 0: + if args.disable_irix and get_nb_log_core() != 0: # Enable Irix mode for load (see issue #1554) - load_stat = self.stats['min{}'.format(load_time)] / self.nb_log_core * 100 + load_stat = self.stats['min{}'.format(load_time)] / get_nb_log_core() * 100 msg = '{:>5.1f}%'.format(load_stat) else: # Default mode for load @@ -181,3 +176,28 @@ class PluginModel(GlancesPluginModel): ret.append(self.curse_add_line(msg, self.get_views(key='min{}'.format(load_time), option='decoration'))) return ret + + +def get_nb_log_core(): + """Get the number of logical CPU core.""" + return nb_log_core + + +def get_load_average(percent: bool = False): + """Get load average. On both Linux and Windows thanks to PsUtil + + if percent is True, return the load average in percent + Ex: if you only have one CPU core and the load average is 1.0, then return 100%""" + load_average = None + try: + load_average = psutil.getloadavg() + except (AttributeError, OSError): + try: + load_average = os.getloadavg() + except (AttributeError, OSError): + pass + + if load_average and percent: + return tuple([i / get_nb_log_core() * 100 for i in load_average]) + else: + return load_average diff --git a/glances/plugins/quicklook/__init__.py b/glances/plugins/quicklook/__init__.py index 862eb243..083a5939 100644 --- a/glances/plugins/quicklook/__init__.py +++ b/glances/plugins/quicklook/__init__.py @@ -2,7 +2,7 @@ # # This file is part of Glances. # -# SPDX-FileCopyrightText: 2022 Nicolas Hennion +# SPDX-FileCopyrightText: 2024 Nicolas Hennion # # SPDX-License-Identifier: LGPL-3.0-only # @@ -11,6 +11,7 @@ from glances.logger import logger from glances.cpu_percent import cpu_percent +from glances.plugins.load import get_load_average, get_nb_log_core from glances.outputs.glances_bars import Bar from glances.outputs.glances_sparklines import Sparkline from glances.plugins.plugin.model import GlancesPluginModel @@ -84,11 +85,20 @@ class PluginModel(GlancesPluginModel): # Grab quicklook stats: CPU, MEM and SWAP if self.input_method == 'local': - # Get the latest CPU percent value + # Get system information + cpu_info = cpu_percent.get_info() + stats['cpu_name'] = cpu_info['cpu_name'] + stats['cpu_hz_current'] = ( + self._mhz_to_hz(cpu_info['cpu_hz_current']) if cpu_info['cpu_hz_current'] is not None else None + ) + stats['cpu_hz'] = self._mhz_to_hz(cpu_info['cpu_hz']) if cpu_info['cpu_hz'] is not None else None + + # Get the CPU percent value (global and per core) + # Stats is shared across all plugins stats['cpu'] = cpu_percent.get() stats['percpu'] = cpu_percent.get(percpu=True) - # Use the psutil lib for the memory (virtual and swap) + # Get the virtual and swap memory stats['mem'] = psutil.virtual_memory().percent try: stats['swap'] = psutil.swap_memory().percent @@ -96,13 +106,14 @@ class PluginModel(GlancesPluginModel): # Correct issue in Illumos OS (see #1767) stats['swap'] = None - # Get additional information - cpu_info = cpu_percent.get_info() - stats['cpu_name'] = cpu_info['cpu_name'] - stats['cpu_hz_current'] = ( - self._mhz_to_hz(cpu_info['cpu_hz_current']) if cpu_info['cpu_hz_current'] is not None else None - ) - stats['cpu_hz'] = self._mhz_to_hz(cpu_info['cpu_hz']) if cpu_info['cpu_hz'] is not None else None + # Get load + stats['cpucore'] = get_nb_log_core() + try: + # Load average is a tuple (1 min, 5 min, 15 min) + # Process only the 15 min value + stats['load'] = get_load_average(percent=True)[2] + except (TypeError, IndexError): + stats['load'] = None elif self.input_method == 'snmp': # Not available @@ -118,12 +129,16 @@ class PluginModel(GlancesPluginModel): # Call the father's method super(PluginModel, self).update_views() - # Add specifics information - # Alert only + # Alert for CPU, MEM and SWAP for key in ['cpu', 'mem', 'swap']: if key in self.stats: self.views[key]['decoration'] = self.get_alert(self.stats[key], header=key) + # Alert for LOAD + self.views['load']['decoration'] = self.get_alert( + self.stats['load'], header='load' + ) + def msg_curse(self, args=None, max_width=10): """Return the list to display in the UI.""" # Init the return message @@ -145,9 +160,13 @@ class PluginModel(GlancesPluginModel): sparkline_tag = data.available if not sparkline_tag: # Fallback to bar if Sparkline module is not installed - data = Bar(max_width, percentage_char=self.get_conf_value('percentage_char', default=['|'])[0]) + data = Bar(max_width, + percentage_char=self.get_conf_value('percentage_char', default=['|'])[0]) # Build the string message + ########################## + + # System information if 'cpu_name' in self.stats and 'cpu_hz_current' in self.stats and 'cpu_hz' in self.stats: msg_name = self.stats['cpu_name'] if self.stats['cpu_hz_current'] and self.stats['cpu_hz']: @@ -160,7 +179,9 @@ class PluginModel(GlancesPluginModel): ret.append(self.curse_add_line(msg_name)) ret.append(self.curse_add_line(msg_freq)) ret.append(self.curse_new_line()) - for key in ['cpu', 'mem', 'swap']: + + # Loop over CPU, MEM and LOAD + for key in ['cpu', 'mem', 'load']: if key == 'cpu' and args.percpu: if sparkline_tag: raw_cpu = self.get_raw_history(item='percpu', nb=data.size) From 2d997ac36fcfe876949d7d266fecbd15171a8fe4 Mon Sep 17 00:00:00 2001 From: nicolargo Date: Sat, 20 Jan 2024 17:19:41 +0100 Subject: [PATCH 2/7] Add swap information - Todo: WebUI --- glances/outputs/glances_bars.py | 16 ++++++---------- glances/plugins/quicklook/__init__.py | 6 +++++- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/glances/outputs/glances_bars.py b/glances/outputs/glances_bars.py index 8e803fd6..f6466a9b 100644 --- a/glances/outputs/glances_bars.py +++ b/glances/outputs/glances_bars.py @@ -15,7 +15,6 @@ from math import modf class Bar(object): - """Manage bar (progression or status). import sys @@ -29,11 +28,8 @@ class Bar(object): """ def __init__(self, size, - percentage_char='|', - empty_char=' ', - pre_char='[', post_char=']', - display_value=True, - min_value=0, max_value=100): + percentage_char='|', empty_char=' ', pre_char='[', post_char=']', + display_value=True, min_value=0, max_value=100): # Build curses_bars self.__curses_bars = [empty_char] * 5 + [percentage_char] * 5 # Bar size @@ -75,11 +71,9 @@ class Bar(object): def post_char(self): return self.__post_char - def get(self): + def get(self, overwrite=''): """Return the bars.""" - value = self.percent - if value > self.max_value: - value = self.max_value + value = self.max_value if self.percent > self.max_value else self.percent frac, whole = modf(self.size * value / 100.0) ret = self.__curses_bars[8] * int(whole) if frac > 0: @@ -91,6 +85,8 @@ class Bar(object): ret = '{}>{:4.0f}%'.format(ret, self.max_value) else: ret = '{}{:5.1f}%'.format(ret, self.percent) + if overwrite and len(overwrite) < len(ret) - 6: + ret = overwrite + ret[len(overwrite):] return ret def __str__(self): diff --git a/glances/plugins/quicklook/__init__.py b/glances/plugins/quicklook/__init__.py index 083a5939..e9570678 100644 --- a/glances/plugins/quicklook/__init__.py +++ b/glances/plugins/quicklook/__init__.py @@ -221,10 +221,14 @@ class PluginModel(GlancesPluginModel): def _msg_create_line(self, msg, data, key): """Create a new line to the Quick view.""" + if key == 'mem' and self.get_alert(self.stats['swap'], header='swap') != 'DEFAULT': + overwrite = 'SWAP' + else: + overwrite = '' return [ self.curse_add_line(msg), self.curse_add_line(data.pre_char, decoration='BOLD'), - self.curse_add_line(data.get(), self.get_views(key=key, option='decoration')), + self.curse_add_line(data.get(overwrite), self.get_views(key=key, option='decoration')), self.curse_add_line(data.post_char, decoration='BOLD'), self.curse_add_line(' '), ] From 92db000a753bf2b5fa66428ab173e8aa00624a72 Mon Sep 17 00:00:00 2001 From: nicolargo Date: Sat, 20 Jan 2024 17:24:04 +0100 Subject: [PATCH 3/7] Sparkline not working - Web UI not done --- glances/outputs/glances_sparklines.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/glances/outputs/glances_sparklines.py b/glances/outputs/glances_sparklines.py index 6d6d2b86..742f9944 100644 --- a/glances/outputs/glances_sparklines.py +++ b/glances/outputs/glances_sparklines.py @@ -75,7 +75,7 @@ class Sparkline(object): def post_char(self): return self.__post_char - def get(self): + def get(self, overwrite=''): """Return the sparkline.""" ret = sparklines(self.percents, minimum=0, maximum=100)[0] if self.__with_text: From 0a555866e371f084103cda1afdb9f3a9ccbd7652 Mon Sep 17 00:00:00 2001 From: nicolargo Date: Sat, 20 Jan 2024 17:40:26 +0100 Subject: [PATCH 4/7] TODO - WebUI --- glances/outputs/glances_sparklines.py | 15 ++++++++++----- glances/plugins/quicklook/__init__.py | 5 +++++ 2 files changed, 15 insertions(+), 5 deletions(-) diff --git a/glances/outputs/glances_sparklines.py b/glances/outputs/glances_sparklines.py index 742f9944..29c0fbf0 100644 --- a/glances/outputs/glances_sparklines.py +++ b/glances/outputs/glances_sparklines.py @@ -34,7 +34,9 @@ class Sparkline(object): """Manage sparklines (see https://pypi.org/project/sparklines/).""" - def __init__(self, size, pre_char='[', post_char=']', empty_char=' ', with_text=True): + def __init__(self, size, + pre_char='[', post_char=']', empty_char=' ', + display_value=True): # If the sparklines python module available ? self.__available = sparklines_module # Sparkline size @@ -45,7 +47,7 @@ class Sparkline(object): self.__pre_char = pre_char self.__post_char = post_char self.__empty_char = empty_char - self.__with_text = with_text + self.__display_value = display_value @property def available(self): @@ -56,7 +58,7 @@ class Sparkline(object): # Return the sparkline size, with or without decoration if with_decoration: return self.__size - if self.__with_text: + if self.__display_value: return self.__size - 6 @property @@ -78,11 +80,14 @@ class Sparkline(object): def get(self, overwrite=''): """Return the sparkline.""" ret = sparklines(self.percents, minimum=0, maximum=100)[0] - if self.__with_text: + if self.__display_value: percents_without_none = [x for x in self.percents if x is not None] if len(percents_without_none) > 0: ret = '{}{:5.1f}%'.format(ret, percents_without_none[-1]) - return nativestr(ret) + ret = nativestr(ret) + if overwrite and len(overwrite) < len(ret) - 6: + ret = overwrite + ret[len(overwrite):] + return ret def __str__(self): """Return the sparkline.""" diff --git a/glances/plugins/quicklook/__init__.py b/glances/plugins/quicklook/__init__.py index e9570678..1cfd5682 100644 --- a/glances/plugins/quicklook/__init__.py +++ b/glances/plugins/quicklook/__init__.py @@ -37,6 +37,10 @@ fields_description = { 'description': 'SWAP percent usage', 'unit': 'percent', }, + 'load': { + 'description': 'LOAD percent usage', + 'unit': 'percent', + }, 'cpu_name': { 'description': 'CPU name', }, @@ -57,6 +61,7 @@ items_history_list = [ {'name': 'percpu', 'description': 'PERCPU percent usage', 'y_unit': '%'}, {'name': 'mem', 'description': 'MEM percent usage', 'y_unit': '%'}, {'name': 'swap', 'description': 'SWAP percent usage', 'y_unit': '%'}, + {'name': 'load', 'description': 'LOAD percent usage', 'y_unit': '%'}, ] From e564c21b8977f249dd2fbce7522d2be16f513720 Mon Sep 17 00:00:00 2001 From: nicolargo Date: Sat, 20 Jan 2024 17:53:39 +0100 Subject: [PATCH 5/7] WebUI done - To be tested with no LOAD (is it a usecase ?) --- .../static/js/components/plugin-quicklook.vue | 13 ++++++++----- glances/outputs/static/public/glances.js | Bin 448518 -> 448549 bytes glances/plugins/load/__init__.py | 2 +- 3 files changed, 9 insertions(+), 6 deletions(-) diff --git a/glances/outputs/static/js/components/plugin-quicklook.vue b/glances/outputs/static/js/components/plugin-quicklook.vue index 1b806275..fd607de0 100644 --- a/glances/outputs/static/js/components/plugin-quicklook.vue +++ b/glances/outputs/static/js/components/plugin-quicklook.vue @@ -61,22 +61,22 @@
{{ mem }}%
-
SWAP
+
LOAD
 
-
{{ swap }}%
+
{{ load }}%
@@ -109,6 +109,9 @@ export default { mem() { return this.stats.mem; }, + load() { + return this.stats.load; + }, cpu() { return this.stats.cpu; }, diff --git a/glances/outputs/static/public/glances.js b/glances/outputs/static/public/glances.js index 9b4636a252a6caa8dcadb4a144c922a0a7013136..5bfc2ce1c8d63814a313c8af123cda9523e07443 100644 GIT binary patch delta 102 zcmZqMAiZ>hbVCbc3sVbo3rh>@7PeJ0S$zB*UAC{A$!5vOl#@UGVkMh6XHI@%O07@7PeJ0S%SkI1GcZ5$!5vOoLo>k{o^J!(d}}x*=*QY iipvuVrpGO0(}u8m7qU4(SQi(vX@ObW|1V@yGXnsR?jUyn diff --git a/glances/plugins/load/__init__.py b/glances/plugins/load/__init__.py index cc936078..0191321f 100644 --- a/glances/plugins/load/__init__.py +++ b/glances/plugins/load/__init__.py @@ -198,6 +198,6 @@ def get_load_average(percent: bool = False): pass if load_average and percent: - return tuple([i / get_nb_log_core() * 100 for i in load_average]) + return tuple([round(i / get_nb_log_core() * 100, 1) for i in load_average]) else: return load_average From 5092475d7f0414726abae26cfafff0d55d61d230 Mon Sep 17 00:00:00 2001 From: nicolargo Date: Sat, 27 Jan 2024 11:20:44 +0100 Subject: [PATCH 6/7] Make the Quicklook stats list configurable (TODO on the WebUI) --- conf/glances.conf | 8 +++- glances/outputs/glances_bars.py | 20 ++++++--- glances/outputs/glances_sparklines.py | 10 +++-- glances/plugins/quicklook/__init__.py | 63 +++++++++++++++------------ 4 files changed, 64 insertions(+), 37 deletions(-) diff --git a/conf/glances.conf b/conf/glances.conf index 75512743..1a489815 100644 --- a/conf/glances.conf +++ b/conf/glances.conf @@ -45,8 +45,11 @@ max_processes_display=25 # Set to true to disable a plugin # Note: you can also disable it from the command line (see --disable-plugin ) disable=False -# Graphical percentage char used in the terminal user interface (default is |) -percentage_char=| +# Stats list (default is cpu,mem,load) +# Available stats are: cpu,mem,load,swap +list=cpu,mem,load +# Graphical bar char used in the terminal user interface (default is |) +bar_char=| # Define CPU, MEM and SWAP thresholds in % cpu_careful=50 cpu_warning=70 @@ -58,6 +61,7 @@ swap_careful=50 swap_warning=70 swap_critical=90 # Source: http://blog.scoutapp.com/articles/2009/07/31/understanding-load-averages +# With 1 CPU core, the load should be lower than 1.00 (100%) load_careful=70 load_warning=100 load_critical=500 diff --git a/glances/outputs/glances_bars.py b/glances/outputs/glances_bars.py index f6466a9b..171099bf 100644 --- a/glances/outputs/glances_bars.py +++ b/glances/outputs/glances_bars.py @@ -28,10 +28,14 @@ class Bar(object): """ def __init__(self, size, - percentage_char='|', empty_char=' ', pre_char='[', post_char=']', - display_value=True, min_value=0, max_value=100): + bar_char='|', + empty_char=' ', + pre_char='[', post_char=']', + unit_char='%', + display_value=True, + min_value=0, max_value=100): # Build curses_bars - self.__curses_bars = [empty_char] * 5 + [percentage_char] * 5 + self.__curses_bars = [empty_char] * 5 + [bar_char] * 5 # Bar size self.__size = size # Bar current percent @@ -43,6 +47,8 @@ class Bar(object): self.__pre_char = pre_char self.__post_char = post_char self.__empty_char = empty_char + self.__unit_char = unit_char + # Value should be displayed ? self.__display_value = display_value @property @@ -82,9 +88,13 @@ class Bar(object): ret += self.__empty_char * int(self.size - whole) if self.__display_value: if self.percent > self.max_value: - ret = '{}>{:4.0f}%'.format(ret, self.max_value) + ret = '{}>{:4.0f}{}'.format(ret, + self.max_value, + self.__unit_char) else: - ret = '{}{:5.1f}%'.format(ret, self.percent) + ret = '{}{:5.1f}{}'.format(ret, + self.percent, + self.__unit_char) if overwrite and len(overwrite) < len(ret) - 6: ret = overwrite + ret[len(overwrite):] return ret diff --git a/glances/outputs/glances_sparklines.py b/glances/outputs/glances_sparklines.py index 29c0fbf0..3a5dabf8 100644 --- a/glances/outputs/glances_sparklines.py +++ b/glances/outputs/glances_sparklines.py @@ -35,7 +35,8 @@ class Sparkline(object): """Manage sparklines (see https://pypi.org/project/sparklines/).""" def __init__(self, size, - pre_char='[', post_char=']', empty_char=' ', + pre_char='[', post_char=']', + unit_char='%', display_value=True): # If the sparklines python module available ? self.__available = sparklines_module @@ -46,7 +47,8 @@ class Sparkline(object): # Char used for the decoration self.__pre_char = pre_char self.__post_char = post_char - self.__empty_char = empty_char + self.__unit_char = unit_char + # Value should be displayed ? self.__display_value = display_value @property @@ -83,7 +85,9 @@ class Sparkline(object): if self.__display_value: percents_without_none = [x for x in self.percents if x is not None] if len(percents_without_none) > 0: - ret = '{}{:5.1f}%'.format(ret, percents_without_none[-1]) + ret = '{}{:5.1f}{}'.format(ret, + percents_without_none[-1], + self.__unit_char) ret = nativestr(ret) if overwrite and len(overwrite) < len(ret) - 6: ret = overwrite + ret[len(overwrite):] diff --git a/glances/plugins/quicklook/__init__.py b/glances/plugins/quicklook/__init__.py index 1cfd5682..b1e53bda 100644 --- a/glances/plugins/quicklook/__init__.py +++ b/glances/plugins/quicklook/__init__.py @@ -71,6 +71,9 @@ class PluginModel(GlancesPluginModel): 'stats' is a dictionary. """ + AVAILABLE_STATS_LIST = ['cpu', 'mem', 'swap', 'load'] + DEFAULT_STATS_LIST = ['cpu', 'mem', 'load'] + def __init__(self, args=None, config=None): """Init the quicklook plugin.""" super(PluginModel, self).__init__( @@ -81,6 +84,12 @@ class PluginModel(GlancesPluginModel): # We want to display the stat in the curse interface self.display_curse = True + # Define the stats list + self.stats_list = self.get_conf_value('list', default=self.DEFAULT_STATS_LIST) + if not set(self.stats_list).issubset(self.AVAILABLE_STATS_LIST): + logger.warning('Quicklook plugin: Invalid stats list: {}'.format(self.stats_list)) + self.stats_list = self.AVAILABLE_STATS_LIST + @GlancesPluginModel._check_decorator @GlancesPluginModel._log_result_decorator def update(self): @@ -115,7 +124,7 @@ class PluginModel(GlancesPluginModel): stats['cpucore'] = get_nb_log_core() try: # Load average is a tuple (1 min, 5 min, 15 min) - # Process only the 15 min value + # Process only the 15 min value (index 2) stats['load'] = get_load_average(percent=True)[2] except (TypeError, IndexError): stats['load'] = None @@ -135,7 +144,7 @@ class PluginModel(GlancesPluginModel): super(PluginModel, self).update_views() # Alert for CPU, MEM and SWAP - for key in ['cpu', 'mem', 'swap']: + for key in self.stats_list: if key in self.stats: self.views[key]['decoration'] = self.get_alert(self.stats[key], header=key) @@ -159,14 +168,14 @@ class PluginModel(GlancesPluginModel): return ret # Define the data: Bar (default behavior) or Sparkline - sparkline_tag = False - if self.args.sparkline and self.history_enable() and not self.args.client: - data = Sparkline(max_width) - sparkline_tag = data.available - if not sparkline_tag: - # Fallback to bar if Sparkline module is not installed - data = Bar(max_width, - percentage_char=self.get_conf_value('percentage_char', default=['|'])[0]) + data = dict() + for key in self.stats_list: + if self.args.sparkline and self.history_enable() and not self.args.client: + data[key] = Sparkline(max_width) + else: + # Fallback to bar if Sparkline module is not installed + data[key] = Bar(max_width, + bar_char=self.get_conf_value('bar_char', default=['|'])[0]) # Build the string message ########################## @@ -186,36 +195,36 @@ class PluginModel(GlancesPluginModel): ret.append(self.curse_new_line()) # Loop over CPU, MEM and LOAD - for key in ['cpu', 'mem', 'load']: + for key in self.stats_list: if key == 'cpu' and args.percpu: - if sparkline_tag: - raw_cpu = self.get_raw_history(item='percpu', nb=data.size) + if type(data[key]).__name__ == 'Sparkline': + raw_cpu = self.get_raw_history(item='percpu', nb=data[key].size) for cpu_index, cpu in enumerate(self.stats['percpu']): - if sparkline_tag: + if type(data[key]).__name__ == 'Sparkline': # Sparkline display an history - data.percents = [i[1][cpu_index]['total'] for i in raw_cpu] + data[key].percents = [i[1][cpu_index]['total'] for i in raw_cpu] # A simple padding in order to align metrics to the right - data.percents += [None] * (data.size - len(data.percents)) + data[key].percents += [None] * (data[key].size - len(data[key].percents)) else: # Bar only the last value - data.percent = cpu['total'] + data[key].percent = cpu['total'] if cpu[cpu['key']] < 10: msg = '{:3}{} '.format(key.upper(), cpu['cpu_number']) else: msg = '{:4} '.format(cpu['cpu_number']) - ret.extend(self._msg_create_line(msg, data, key)) + ret.extend(self._msg_create_line(msg, data[key], key)) ret.append(self.curse_new_line()) else: - if sparkline_tag: + if type(data[key]).__name__ == 'Sparkline': # Sparkline display an history - data.percents = [i[1] for i in self.get_raw_history(item=key, nb=data.size)] + data[key].percents = [i[1] for i in self.get_raw_history(item=key, nb=data[key].size)] # A simple padding in order to align metrics to the right - data.percents += [None] * (data.size - len(data.percents)) + data[key].percents += [None] * (data[key].size - len(data[key].percents)) else: # Bar only the last value - data.percent = self.stats[key] + data[key].percent = self.stats[key] msg = '{:4} '.format(key.upper()) - ret.extend(self._msg_create_line(msg, data, key)) + ret.extend(self._msg_create_line(msg, data[key], key)) ret.append(self.curse_new_line()) # Remove the last new line @@ -226,10 +235,10 @@ class PluginModel(GlancesPluginModel): def _msg_create_line(self, msg, data, key): """Create a new line to the Quick view.""" - if key == 'mem' and self.get_alert(self.stats['swap'], header='swap') != 'DEFAULT': - overwrite = 'SWAP' - else: - overwrite = '' + # if key == 'mem' and self.get_alert(self.stats['swap'], header='swap') != 'DEFAULT': + # overwrite = 'SWAP' + # else: + overwrite = '' return [ self.curse_add_line(msg), self.curse_add_line(data.pre_char, decoration='BOLD'), From 1623c27f4e8e460d99c8d64aa2cef39a1c51a2dd Mon Sep 17 00:00:00 2001 From: nicolargo Date: Sun, 28 Jan 2024 10:42:20 +0100 Subject: [PATCH 7/7] Quicklook plugin lst is also configurable and taken into account in the WebUI --- conf/glances.conf | 2 +- docs/aoa/quicklook.rst | 10 +- docs/api.rst | 418 +++++++++--------- docs/man/glances.1 | 2 +- .../static/js/components/plugin-quicklook.vue | 44 +- glances/outputs/static/package-lock.json | 12 +- glances/outputs/static/public/glances.js | Bin 448549 -> 448173 bytes glances/plugins/quicklook/__init__.py | 3 + 8 files changed, 228 insertions(+), 263 deletions(-) diff --git a/conf/glances.conf b/conf/glances.conf index 1a489815..35122262 100644 --- a/conf/glances.conf +++ b/conf/glances.conf @@ -61,7 +61,7 @@ swap_careful=50 swap_warning=70 swap_critical=90 # Source: http://blog.scoutapp.com/articles/2009/07/31/understanding-load-averages -# With 1 CPU core, the load should be lower than 1.00 (100%) +# With 1 CPU core, the load should be lower than 1.00 ~ 100% load_careful=70 load_warning=100 load_critical=500 diff --git a/docs/aoa/quicklook.rst b/docs/aoa/quicklook.rst index 093a7814..82fac3aa 100644 --- a/docs/aoa/quicklook.rst +++ b/docs/aoa/quicklook.rst @@ -4,7 +4,7 @@ Quick Look ========== The ``quicklook`` plugin is only displayed on wide screen and proposes a -bar view for CPU and memory (virtual and swap). +bar view for cpu, memory, swap and load (this list is configurable). In the terminal interface, click on ``3`` to enable/disable it. @@ -27,10 +27,14 @@ client/server mode (see issue ). Limit values can be overwritten in the configuration file under the ``[quicklook]`` section. -You can also configure the percentage char used in the terminal user interface. +You can also configure the stats list and the bat character used in the +user interface. .. code-block:: ini [quicklook] + # Stats list (default is cpu,mem,load) + # Available stats are: cpu,mem,load,swap + list=cpu,mem,load # Graphical percentage char used in the terminal user interface (default is |) - percentage_char=@ + bar_char=| diff --git a/docs/api.rst b/docs/api.rst index 62509320..a892492a 100644 --- a/docs/api.rst +++ b/docs/api.rst @@ -109,16 +109,16 @@ GET alert Get plugin stats:: # curl http://localhost:61208/api/4/alert - [{"avg": 75.58190732727591, - "begin": 1705242982.0, + [{"avg": 81.2863503930515, + "begin": 1706434886.0, "count": 1, "desc": "", "end": -1, - "max": 75.58190732727591, - "min": 75.58190732727591, + "max": 81.2863503930515, + "min": 81.2863503930515, "sort": "memory_percent", "state": "WARNING", - "sum": 75.58190732727591, + "sum": 81.2863503930515, "top": [], "type": "MEM"}] @@ -140,21 +140,21 @@ Fields descriptions: Get a specific field:: # curl http://localhost:61208/api/4/alert/begin - {"begin": [1705242982.0]} + {"begin": [1706434886.0]} Get a specific item when field matches the given value:: - # curl http://localhost:61208/api/4/alert/begin/1705242982.0 - {"1705242982.0": [{"avg": 75.58190732727591, - "begin": 1705242982.0, + # curl http://localhost:61208/api/4/alert/begin/1706434886.0 + {"1706434886.0": [{"avg": 81.2863503930515, + "begin": 1706434886.0, "count": 1, "desc": "", "end": -1, - "max": 75.58190732727591, - "min": 75.58190732727591, + "max": 81.2863503930515, + "min": 81.2863503930515, "sort": "memory_percent", "state": "WARNING", - "sum": 75.58190732727591, + "sum": 81.2863503930515, "top": [], "type": "MEM"}]} @@ -172,7 +172,7 @@ Get plugin stats:: "refresh": 3.0, "regex": True, "result": None, - "timer": 0.19934892654418945}, + "timer": 0.36128687858581543}, {"count": 0, "countmax": 20.0, "countmin": None, @@ -181,7 +181,7 @@ Get plugin stats:: "refresh": 3.0, "regex": True, "result": None, - "timer": 0.19925165176391602}] + "timer": 0.36110568046569824}] Fields descriptions: @@ -209,7 +209,7 @@ Get a specific item when field matches the given value:: "refresh": 3.0, "regex": True, "result": None, - "timer": 0.19934892654418945}]} + "timer": 0.36128687858581543}]} GET connections --------------- @@ -243,8 +243,8 @@ Get plugin stats:: # curl http://localhost:61208/api/4/containers [{"command": "top", - "cpu": {"total": 1.8635523677666806e-06}, - "cpu_percent": 1.8635523677666806e-06, + "cpu": {"total": 2.4258436881746593e-06}, + "cpu_percent": 2.4258436881746593e-06, "created": "2023-12-09T10:45:34.339489876+01:00", "engine": "podman", "id": "481d6ffb7eef284d062628cf350bdd9ce0a803db8a2a505d75565ed24322b714", @@ -253,8 +253,8 @@ Get plugin stats:: "io_rx": 0.0, "io_wx": 0.0, "key": "name", - "memory": {"limit": 7823585280.0, "usage": 1306624.0}, - "memory_usage": 1306624.0, + "memory": {"limit": 7823585280.0, "usage": 1212416.0}, + "memory_usage": 1212416.0, "name": "sad_darwin", "network": {"rx": 0.0, "time_since_update": 1, "tx": 0.0}, "network_rx": 0.0, @@ -264,8 +264,8 @@ Get plugin stats:: "status": "running", "uptime": "1 months"}, {"command": "", - "cpu": {"total": 3.4505346487574547e-10}, - "cpu_percent": 3.4505346487574547e-10, + "cpu": {"total": 3.5348550629383954e-10}, + "cpu_percent": 3.5348550629383954e-10, "created": "2022-10-22T14:23:03.120912374+02:00", "engine": "podman", "id": "9491515251edcd5bb5dc17205d7ee573c0be96fe0b08b0a12a7e2cea874565ea", @@ -274,8 +274,8 @@ Get plugin stats:: "io_rx": 0.0, "io_wx": 0.0, "key": "name", - "memory": {"limit": 7823585280.0, "usage": 290816.0}, - "memory_usage": 290816.0, + "memory": {"limit": 7823585280.0, "usage": 237568.0}, + "memory_usage": 237568.0, "name": "8d0f1c783def-infra", "network": {"rx": 0.0, "time_since_update": 1, "tx": 0.0}, "network_rx": 0.0, @@ -313,8 +313,8 @@ Get a specific item when field matches the given value:: # curl http://localhost:61208/api/4/containers/name/sad_darwin {"sad_darwin": [{"command": "top", - "cpu": {"total": 1.8635523677666806e-06}, - "cpu_percent": 1.8635523677666806e-06, + "cpu": {"total": 2.4258436881746593e-06}, + "cpu_percent": 2.4258436881746593e-06, "created": "2023-12-09T10:45:34.339489876+01:00", "engine": "podman", "id": "481d6ffb7eef284d062628cf350bdd9ce0a803db8a2a505d75565ed24322b714", @@ -323,8 +323,8 @@ Get a specific item when field matches the given value:: "io_rx": 0.0, "io_wx": 0.0, "key": "name", - "memory": {"limit": 7823585280.0, "usage": 1306624.0}, - "memory_usage": 1306624.0, + "memory": {"limit": 7823585280.0, "usage": 1212416.0}, + "memory_usage": 1212416.0, "name": "sad_darwin", "network": {"rx": 0.0, "time_since_update": 1, "tx": 0.0}, "network_rx": 0.0, @@ -362,7 +362,7 @@ Get plugin stats:: "ctx_switches": 0, "guest": 0.0, "guest_nice": 0.0, - "idle": 74.6, + "idle": 43.4, "interrupts": 0, "iowait": 0.0, "irq": 0.0, @@ -371,10 +371,10 @@ Get plugin stats:: "softirq": 0.0, "steal": 0.0, "syscalls": 0, - "system": 3.3, + "system": 7.8, "time_since_update": 1, - "total": 25.4, - "user": 22.1} + "total": 56.6, + "user": 48.8} Fields descriptions: @@ -397,7 +397,7 @@ Fields descriptions: Get a specific field:: # curl http://localhost:61208/api/4/cpu/total - {"total": 25.4} + {"total": 56.6} GET diskio ---------- @@ -454,13 +454,13 @@ Get plugin stats:: # curl http://localhost:61208/api/4/fs [{"alias": "Root", "device_name": "/dev/mapper/ubuntu--gnome--vg-root", - "free": 19083309056, + "free": 17195761664, "fs_type": "ext4", "key": "mnt_point", "mnt_point": "/", - "percent": 91.7, + "percent": 92.6, "size": 243334156288, - "used": 211863392256}, + "used": 213750939648}, {"device_name": "zsfpool", "free": 31195136, "fs_type": "zfs", @@ -490,13 +490,13 @@ Get a specific item when field matches the given value:: # curl http://localhost:61208/api/4/fs/mnt_point// {"/": [{"alias": "Root", "device_name": "/dev/mapper/ubuntu--gnome--vg-root", - "free": 19083309056, + "free": 17195761664, "fs_type": "ext4", "key": "mnt_point", "mnt_point": "/", - "percent": 91.7, + "percent": 92.6, "size": 243334156288, - "used": 211863392256}]} + "used": 213750939648}]} GET ip ------ @@ -504,11 +504,11 @@ GET ip Get plugin stats:: # curl http://localhost:61208/api/4/ip - {"address": "192.168.0.32", - "gateway": "192.168.0.254", + {"address": "192.168.1.14", + "gateway": "192.168.1.1", "mask": "255.255.255.0", "mask_cidr": 24, - "public_address": "91.166.228.228", + "public_address": "92.151.148.66", "public_info_human": ""} Fields descriptions: @@ -523,7 +523,7 @@ Fields descriptions: Get a specific field:: # curl http://localhost:61208/api/4/ip/gateway - {"gateway": "192.168.0.254"} + {"gateway": "192.168.1.1"} GET load -------- @@ -531,10 +531,7 @@ GET load Get plugin stats:: # curl http://localhost:61208/api/4/load - {"cpucore": 4, - "min1": 1.00927734375, - "min15": 0.66259765625, - "min5": 0.7548828125} + {"cpucore": 4, "min1": 2.142578125, "min15": 2.2412109375, "min5": 2.296875} Fields descriptions: @@ -546,7 +543,7 @@ Fields descriptions: Get a specific field:: # curl http://localhost:61208/api/4/load/min1 - {"min1": 1.00927734375} + {"min1": 2.142578125} GET mem ------- @@ -554,16 +551,16 @@ GET mem Get plugin stats:: # curl http://localhost:61208/api/4/mem - {"active": 2827825152, - "available": 1910370304, - "buffers": 442753024, - "cached": 1887649792, - "free": 1910370304, - "inactive": 3567714304, - "percent": 75.6, - "shared": 457003008, + {"active": 2943950848, + "available": 1464078336, + "buffers": 63561728, + "cached": 1855676416, + "free": 1464078336, + "inactive": 3364462592, + "percent": 81.3, + "shared": 513527808, "total": 7823585280, - "used": 5913214976} + "used": 6359506944} Fields descriptions: @@ -590,13 +587,13 @@ GET memswap Get plugin stats:: # curl http://localhost:61208/api/4/memswap - {"free": 3856048128, - "percent": 52.3, - "sin": 14772441088, - "sout": 22269526016, + {"free": 3434184704, + "percent": 57.5, + "sin": 21763555328, + "sout": 30277906432, "time_since_update": 1, "total": 8082419712, - "used": 4226371584} + "used": 4648235008} Fields descriptions: @@ -620,26 +617,26 @@ Get plugin stats:: # curl http://localhost:61208/api/4/network [{"alias": None, - "cumulative_cx": 2537577204, - "cumulative_rx": 1268788602, - "cumulative_tx": 1268788602, - "cx": 0, + "cumulative_cx": 2734623262, + "cumulative_rx": 1367311631, + "cumulative_tx": 1367311631, + "cx": 576, "interface_name": "lo", "is_up": True, "key": "interface_name", - "rx": 0, + "rx": 288, "speed": 0, "time_since_update": 1, - "tx": 0}, + "tx": 288}, {"alias": "WIFI", - "cumulative_cx": 14514673497, - "cumulative_rx": 11339647204, - "cumulative_tx": 3175026293, - "cx": 224, + "cumulative_cx": 16571979029, + "cumulative_rx": 13260033314, + "cumulative_tx": 3311945715, + "cx": 186, "interface_name": "wlp2s0", "is_up": True, "key": "interface_name", - "rx": 98, + "rx": 60, "speed": 0, "time_since_update": 1, "tx": 126}] @@ -666,24 +663,24 @@ Get a specific field:: "br-40875d2e2716", "docker0", "br_grafana", - "veth55598fc", - "mpqemubr0"]} + "mpqemubr0", + "vethbeef843"]} Get a specific item when field matches the given value:: # curl http://localhost:61208/api/4/network/interface_name/lo {"lo": [{"alias": None, - "cumulative_cx": 2537577204, - "cumulative_rx": 1268788602, - "cumulative_tx": 1268788602, - "cx": 0, + "cumulative_cx": 2734623262, + "cumulative_rx": 1367311631, + "cumulative_tx": 1367311631, + "cx": 576, "interface_name": "lo", "is_up": True, "key": "interface_name", - "rx": 0, + "rx": 288, "speed": 0, "time_since_update": 1, - "tx": 0}]} + "tx": 288}]} GET now ------- @@ -691,7 +688,7 @@ GET now Get plugin stats:: # curl http://localhost:61208/api/4/now - "2024-01-14 15:36:22 CET" + "2024-01-28 10:41:26 CET" GET percpu ---------- @@ -700,19 +697,6 @@ Get plugin stats:: # curl http://localhost:61208/api/4/percpu [{"cpu_number": 0, - "guest": 0.0, - "guest_nice": 0.0, - "idle": 20.0, - "iowait": 0.0, - "irq": 0.0, - "key": "cpu_number", - "nice": 0.0, - "softirq": 0.0, - "steal": 0.0, - "system": 2.0, - "total": 80.0, - "user": 9.0}, - {"cpu_number": 1, "guest": 0.0, "guest_nice": 0.0, "idle": 23.0, @@ -722,9 +706,22 @@ Get plugin stats:: "nice": 0.0, "softirq": 0.0, "steal": 0.0, - "system": 2.0, + "system": 5.0, "total": 77.0, - "user": 7.0}] + "user": 22.0}, + {"cpu_number": 1, + "guest": 0.0, + "guest_nice": 0.0, + "idle": 16.0, + "iowait": 0.0, + "irq": 0.0, + "key": "cpu_number", + "nice": 0.0, + "softirq": 0.0, + "steal": 0.0, + "system": 4.0, + "total": 84.0, + "user": 31.0}] Fields descriptions: @@ -753,12 +750,12 @@ Get plugin stats:: # curl http://localhost:61208/api/4/ports [{"description": "DefaultGateway", - "host": "192.168.0.254", + "host": "192.168.1.1", "indice": "port_0", "port": 0, "refresh": 30, "rtt_warning": None, - "status": 0.005277, + "status": 0.007028, "timeout": 3}] Fields descriptions: @@ -775,19 +772,19 @@ Fields descriptions: Get a specific field:: # curl http://localhost:61208/api/4/ports/host - {"host": ["192.168.0.254"]} + {"host": ["192.168.1.1"]} Get a specific item when field matches the given value:: - # curl http://localhost:61208/api/4/ports/host/192.168.0.254 - {"192.168.0.254": [{"description": "DefaultGateway", - "host": "192.168.0.254", - "indice": "port_0", - "port": 0, - "refresh": 30, - "rtt_warning": None, - "status": 0.005277, - "timeout": 3}]} + # curl http://localhost:61208/api/4/ports/host/192.168.1.1 + {"192.168.1.1": [{"description": "DefaultGateway", + "host": "192.168.1.1", + "indice": "port_0", + "port": 0, + "refresh": 30, + "rtt_warning": None, + "status": 0.007028, + "timeout": 3}]} GET processcount ---------------- @@ -795,7 +792,7 @@ GET processcount Get plugin stats:: # curl http://localhost:61208/api/4/processcount - {"pid_max": 0, "running": 1, "sleeping": 326, "thread": 1611, "total": 392} + {"pid_max": 0, "running": 1, "sleeping": 336, "thread": 1717, "total": 412} Fields descriptions: @@ -808,7 +805,7 @@ Fields descriptions: Get a specific field:: # curl http://localhost:61208/api/4/processcount/total - {"total": 392} + {"total": 412} GET psutilversion ----------------- @@ -824,25 +821,14 @@ GET quicklook Get plugin stats:: # curl http://localhost:61208/api/4/quicklook - {"cpu": 25.4, - "cpu_hz": 3000000000.0, - "cpu_hz_current": 2723398750.0000005, + {"cpu": 56.6, + "cpu_hz": 2025000000.0, + "cpu_hz_current": 1723932000.0, "cpu_name": "Intel(R) Core(TM) i7-4500U CPU @ 1.80GHz", - "mem": 75.6, + "cpucore": 4, + "load": 56.0, + "mem": 81.3, "percpu": [{"cpu_number": 0, - "guest": 0.0, - "guest_nice": 0.0, - "idle": 20.0, - "iowait": 0.0, - "irq": 0.0, - "key": "cpu_number", - "nice": 0.0, - "softirq": 0.0, - "steal": 0.0, - "system": 2.0, - "total": 80.0, - "user": 9.0}, - {"cpu_number": 1, "guest": 0.0, "guest_nice": 0.0, "idle": 23.0, @@ -852,50 +838,64 @@ Get plugin stats:: "nice": 0.0, "softirq": 0.0, "steal": 0.0, - "system": 2.0, + "system": 5.0, "total": 77.0, - "user": 7.0}, + "user": 22.0}, + {"cpu_number": 1, + "guest": 0.0, + "guest_nice": 0.0, + "idle": 16.0, + "iowait": 0.0, + "irq": 0.0, + "key": "cpu_number", + "nice": 0.0, + "softirq": 0.0, + "steal": 0.0, + "system": 4.0, + "total": 84.0, + "user": 31.0}, {"cpu_number": 2, "guest": 0.0, "guest_nice": 0.0, - "idle": 21.0, + "idle": 27.0, "iowait": 0.0, "irq": 0.0, "key": "cpu_number", "nice": 0.0, "softirq": 0.0, "steal": 0.0, - "system": 1.0, - "total": 79.0, - "user": 9.0}, + "system": 4.0, + "total": 73.0, + "user": 21.0}, {"cpu_number": 3, "guest": 0.0, "guest_nice": 0.0, - "idle": 28.0, + "idle": 24.0, "iowait": 0.0, "irq": 0.0, "key": "cpu_number", "nice": 0.0, "softirq": 0.0, "steal": 0.0, - "system": 1.0, - "total": 72.0, - "user": 3.0}], - "swap": 52.3} + "system": 3.0, + "total": 76.0, + "user": 25.0}], + "swap": 57.5} Fields descriptions: * **cpu**: CPU percent usage (unit is *percent*) * **mem**: MEM percent usage (unit is *percent*) * **swap**: SWAP percent usage (unit is *percent*) +* **load**: LOAD percent usage (unit is *percent*) * **cpu_name**: CPU name (unit is *None*) * **cpu_hz_current**: CPU current frequency (unit is *hertz*) * **cpu_hz**: CPU max frequency (unit is *hertz*) Get a specific field:: - # curl http://localhost:61208/api/4/quicklook/cpu - {"cpu": 25.4} + # curl http://localhost:61208/api/4/quicklook/cpu_name + {"cpu_name": "Intel(R) Core(TM) i7-4500U CPU @ 1.80GHz"} GET sensors ----------- @@ -984,7 +984,7 @@ GET uptime Get plugin stats:: # curl http://localhost:61208/api/4/uptime - "50 days, 6:38:24" + "64 days, 1:43:26" GET version ----------- @@ -1009,85 +1009,63 @@ Get top 2 processes of the processlist plugin:: # curl http://localhost:61208/api/4/processlist/top/2 [{"cmdline": ["/usr/share/code/code", + "--ms-enable-electron-run-as-node", + "/home/nicolargo/.vscode/extensions/vue.volar-1.8.25/server.js", + "--node-ipc", + "--clientProcessId=391253"], + "cpu_percent": 0.0, + "cpu_times": {"children_system": 0.0, + "children_user": 0.0, + "iowait": 0.0, + "system": 182.3, + "user": 3586.33}, + "gids": {"effective": 1000, "real": 1000, "saved": 1000}, + "io_counters": [1702031360, 0, 0, 0, 0], + "key": "pid", + "memory_info": {"data": 792121344, + "dirty": 0, + "lib": 0, + "rss": 578248704, + "shared": 17330176, + "text": 120565760, + "vms": 1205534920704}, + "memory_percent": 7.391096067914275, + "name": "code", + "nice": 0, + "num_threads": 8, + "pid": 391764, + "status": "S", + "time_since_update": 1, + "username": "nicolargo"}, + {"cmdline": ["/usr/share/code/code", "--ms-enable-electron-run-as-node", "/home/nicolargo/.vscode/extensions/ms-python.vscode-pylance-2023.12.1/dist/server.bundle.js", "--cancellationReceive=file:810abd06604ca203178b3fa9390087012fbf550dba", "--node-ipc", "--clientProcessId=391253"], "cpu_percent": 0.0, - "cpu_times": {"children_system": 0.78, - "children_user": 6.15, + "cpu_times": {"children_system": 0.85, + "children_user": 6.34, "iowait": 0.0, - "system": 360.08, - "user": 6010.89}, + "system": 466.27, + "user": 7859.93}, "gids": {"effective": 1000, "real": 1000, "saved": 1000}, - "io_counters": [1231159296, 2641920, 0, 0, 0], + "io_counters": [2126852096, 2703360, 0, 0, 0], "key": "pid", - "memory_info": {"data": 899014656, + "memory_info": {"data": 944828416, "dirty": 0, "lib": 0, - "rss": 511119360, - "shared": 26382336, + "rss": 531513344, + "shared": 17362944, "text": 120565760, "vms": 1207768694784}, - "memory_percent": 6.533057948593103, + "memory_percent": 6.793731070571267, "name": "code", "nice": 0, "num_threads": 13, "pid": 391817, "status": "S", "time_since_update": 1, - "username": "nicolargo"}, - {"cmdline": ["/usr/share/code/code", - "--type=renderer", - "--crashpad-handler-pid=391157", - "--enable-crash-reporter=721e05a9-6035-4dcb-bd58-68097aa48dd0,no_channel", - "--user-data-dir=/home/nicolargo/.config/Code", - "--standard-schemes=vscode-webview,vscode-file", - "--enable-sandbox", - "--secure-schemes=vscode-webview,vscode-file", - "--bypasscsp-schemes", - "--cors-schemes=vscode-webview,vscode-file", - "--fetch-schemes=vscode-webview,vscode-file", - "--service-worker-schemes=vscode-webview", - "--streaming-schemes", - "--app-path=/usr/share/code/resources/app", - "--enable-sandbox", - "--enable-blink-features=HighlightAPI", - "--first-renderer-process", - "--lang=en-US", - "--num-raster-threads=2", - "--enable-main-frame-before-activation", - "--renderer-client-id=4", - "--time-ticks-at-unix-epoch=-1702561657662203", - "--launch-time-ticks=95866298101", - "--shared-files=v8_context_snapshot_data:100", - "--field-trial-handle=0,i,2865222574050452096,10380804405300286374,262144", - "--disable-features=CalculateNativeWinOcclusion,SpareRendererForSitePerProcess", - "--vscode-window-config=vscode:a08b576a-4b00-4480-bfc3-390d8aea727c"], - "cpu_percent": 0.0, - "cpu_times": {"children_system": 0.0, - "children_user": 0.0, - "iowait": 0.0, - "system": 872.37, - "user": 12288.82}, - "gids": {"effective": 1000, "real": 1000, "saved": 1000}, - "io_counters": [1207435264, 3117056, 0, 0, 0], - "key": "pid", - "memory_info": {"data": 1501626368, - "dirty": 0, - "lib": 0, - "rss": 484990976, - "shared": 76034048, - "text": 120565760, - "vms": 1220702756864}, - "memory_percent": 6.199088507922547, - "name": "code", - "nice": 0, - "num_threads": 15, - "pid": 391192, - "status": "S", - "time_since_update": 1, "username": "nicolargo"}] Note: Only work for plugin with a list of items @@ -1116,34 +1094,34 @@ GET stats history History of a plugin:: # curl http://localhost:61208/api/4/cpu/history - {"system": [["2024-01-14T15:36:24.814316", 3.3], - ["2024-01-14T15:36:25.828843", 1.8], - ["2024-01-14T15:36:26.982020", 1.8]], - "user": [["2024-01-14T15:36:24.814299", 22.1], - ["2024-01-14T15:36:25.828836", 9.7], - ["2024-01-14T15:36:26.982006", 9.7]]} + {"system": [["2024-01-28T10:41:28.116797", 7.8], + ["2024-01-28T10:41:29.140407", 3.1], + ["2024-01-28T10:41:30.368579", 3.1]], + "user": [["2024-01-28T10:41:28.116785", 48.8], + ["2024-01-28T10:41:29.140398", 17.3], + ["2024-01-28T10:41:30.368565", 17.3]]} Limit history to last 2 values:: # curl http://localhost:61208/api/4/cpu/history/2 - {"system": [["2024-01-14T15:36:25.828843", 1.8], - ["2024-01-14T15:36:26.982020", 1.8]], - "user": [["2024-01-14T15:36:25.828836", 9.7], - ["2024-01-14T15:36:26.982006", 9.7]]} + {"system": [["2024-01-28T10:41:29.140407", 3.1], + ["2024-01-28T10:41:30.368579", 3.1]], + "user": [["2024-01-28T10:41:29.140398", 17.3], + ["2024-01-28T10:41:30.368565", 17.3]]} History for a specific field:: # curl http://localhost:61208/api/4/cpu/system/history - {"system": [["2024-01-14T15:36:22.968267", 3.3], - ["2024-01-14T15:36:24.814316", 3.3], - ["2024-01-14T15:36:25.828843", 1.8], - ["2024-01-14T15:36:26.982020", 1.8]]} + {"system": [["2024-01-28T10:41:26.512718", 7.8], + ["2024-01-28T10:41:28.116797", 7.8], + ["2024-01-28T10:41:29.140407", 3.1], + ["2024-01-28T10:41:30.368579", 3.1]]} Limit history for a specific field to last 2 values:: # curl http://localhost:61208/api/4/cpu/system/history - {"system": [["2024-01-14T15:36:25.828843", 1.8], - ["2024-01-14T15:36:26.982020", 1.8]]} + {"system": [["2024-01-28T10:41:29.140407", 3.1], + ["2024-01-28T10:41:30.368579", 3.1]]} GET limits (used for thresholds) -------------------------------- @@ -1301,14 +1279,18 @@ All limits/thresholds:: "19"]}, "psutilversion": {"history_size": 1200.0}, "quicklook": {"history_size": 1200.0, + "quicklook_bar_char": ["|"], "quicklook_cpu_careful": 50.0, "quicklook_cpu_critical": 90.0, "quicklook_cpu_warning": 70.0, "quicklook_disable": ["False"], + "quicklook_list": ["cpu", "mem", "load"], + "quicklook_load_careful": 70.0, + "quicklook_load_critical": 500.0, + "quicklook_load_warning": 100.0, "quicklook_mem_careful": 50.0, "quicklook_mem_critical": 90.0, "quicklook_mem_warning": 70.0, - "quicklook_percentage_char": ["|"], "quicklook_swap_careful": 50.0, "quicklook_swap_critical": 90.0, "quicklook_swap_warning": 70.0}, diff --git a/docs/man/glances.1 b/docs/man/glances.1 index 0e7ba5cf..aa91312b 100644 --- a/docs/man/glances.1 +++ b/docs/man/glances.1 @@ -27,7 +27,7 @@ level margin: \\n[rst2man-indent\\n[rst2man-indent-level]] .\" new: \\n[rst2man-indent\\n[rst2man-indent-level]] .in \\n[rst2man-indent\\n[rst2man-indent-level]]u .. -.TH "GLANCES" "1" "Jan 14, 2024" "4.0.0_beta01" "Glances" +.TH "GLANCES" "1" "Jan 28, 2024" "4.0.0_beta01" "Glances" .SH NAME glances \- An eye on your system .SH SYNOPSIS diff --git a/glances/outputs/static/js/components/plugin-quicklook.vue b/glances/outputs/static/js/components/plugin-quicklook.vue index fd607de0..637b91d8 100644 --- a/glances/outputs/static/js/components/plugin-quicklook.vue +++ b/glances/outputs/static/js/components/plugin-quicklook.vue @@ -42,41 +42,23 @@
{{ percpu.total }}%
-
-
MEM
+
+
{{ key.toUpperCase() }}
 
-
{{ mem }}%
-
-
-
LOAD
-
-
-
-   -
-
-
-
{{ load }}%
+
{{ stats[key] }}%
@@ -106,12 +88,6 @@ export default { view() { return this.data.views['quicklook']; }, - mem() { - return this.stats.mem; - }, - load() { - return this.stats.load; - }, cpu() { return this.stats.cpu; }, @@ -124,15 +100,15 @@ export default { cpu_hz() { return this.stats.cpu_hz; }, - swap() { - return this.stats.swap; - }, percpus() { return this.stats.percpu.map(({ cpu_number: number, total }) => ({ number, total })); - } + }, + stats_list_after_cpu() { + return this.view.list.filter((key) => !key.includes('cpu')); + }, }, methods: { getDecoration(value) { diff --git a/glances/outputs/static/package-lock.json b/glances/outputs/static/package-lock.json index 00e73156..85e76ff0 100644 --- a/glances/outputs/static/package-lock.json +++ b/glances/outputs/static/package-lock.json @@ -2336,9 +2336,9 @@ "dev": true }, "node_modules/follow-redirects": { - "version": "1.15.2", - "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.2.tgz", - "integrity": "sha512-VQLG33o04KaQ8uYi2tVNbdrWp1QWxNNea+nmIB4EVM28v0hmP17z7aG1+wAkNzVq4KeXTq3221ye5qTJP91JwA==", + "version": "1.15.5", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.5.tgz", + "integrity": "sha512-vSFWUON1B+yAw1VN4xMfxgn5fTUiaOzAJCKBwIIgT/+7CuGy9+r+5gITvP62j3RmaD5Ph65UaERdOSRGUzZtgw==", "dev": true, "funding": [ { @@ -7584,9 +7584,9 @@ "dev": true }, "follow-redirects": { - "version": "1.15.2", - "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.2.tgz", - "integrity": "sha512-VQLG33o04KaQ8uYi2tVNbdrWp1QWxNNea+nmIB4EVM28v0hmP17z7aG1+wAkNzVq4KeXTq3221ye5qTJP91JwA==", + "version": "1.15.5", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.5.tgz", + "integrity": "sha512-vSFWUON1B+yAw1VN4xMfxgn5fTUiaOzAJCKBwIIgT/+7CuGy9+r+5gITvP62j3RmaD5Ph65UaERdOSRGUzZtgw==", "dev": true }, "forwarded": { diff --git a/glances/outputs/static/public/glances.js b/glances/outputs/static/public/glances.js index 5bfc2ce1c8d63814a313c8af123cda9523e07443..c888455866e98aa1bf9ddcceac8187cab6677914 100644 GIT binary patch delta 1422 zcmZuwT}&KR7|k8nuSm+KG`50eWf}RIX@_NLY7@6&_$jm$N+}c&aD&rjxD1_{U1nxM zTB)s)XiWRihw`CqqSTZGWg8$1BQ+KKpouXiYD_eJ>Witb#u(JZ=-nU6N}QLO``zz; z=gc|h-d@}ni|xBKMW(o^tf}lNR~#P9;P)OV=Ef;5{ps3^rSC#LUhIb*Tqm7w1P`vi z3TJWpJvfvVibV0(W!Qty+<-T5{RZ^5N|r6#)_|s3_JBNOE9L-e62uFpVnEC zG8h!4GZY^huqVfq)j@tzs>AAAP?Xh3YcPMq<;P36V30dS@jDNAJE5MJ- zrlA^?pF9!@8DPiWuds2{>!&fS)wMte#Pat6P;4IWn=l^Q9!D?!B13LyuJ=HPj9 z3cKf^jx;+nbI`|?v@#fVFu+^7Y}&k(MvQ1tsv3;qQHmvhxC(IB70AY_d3ckY#QQT0 zcO*&EgTKr}KG(sz!XR*?>34nVA25F&p2mk8u3cPHvQmigk68QpB!A5N82)ybX3#&M zq7SXi83z1MITWI~0G0g7OshuHRvEIcBpi}Ds5FZA7hr(YV@V92%Il)iV`H1JF$T5V z@s#p-GX}Y&JEi+ErhD}~RO3br^0=N9XReRpwQeZlTDAi2d~pX%;y#^0wI!|ealE_; zWv*^29ZM_y!y+_zdeR&<`K+QPNj@gT<{w%DnR_YCXkiJS@Sk8VoKq$O{!IfyrfRDp zSz{LTZUwS-@J-mJeLi{&h#>r5x1#tT@ypc%Omgtp$Kt! zmODZ5Kpd*LUWzZrp_0Y>ojAM&wl48r0b_9}$C?!=Au0~6KpAHx04gxH0-`&dG1bzO zmyfl1SK%Nh>#1~)t3xUysp04uYe7MDf8IbR=fYUI8z9b742Wau@t$7_Z%h*9djo zpTcjXs)4zq$wo-A+LO8NVAn6uwyoHy7*^P{0;ehZ@4=IerQ7!>EL+h7rvBeqT@hQ= zl|Xn~xrb>Gi0CNafyU|Ap~Ct79=uJ+uyb)84(}wov+^}`5svCe>VbEB-@qriM8`)z MGUs&6`w0sE1tekHd;kCd delta 1456 zcmZ8gT}&KR7|k7azVcJIg$M|An{_C42L?(>t8ppH-$E%+{tC1ZLWkXDx@7O}va{?$ z>l$N7e5o}i+K(a;NZPcu5LQ5k#)>I#)fiJBd{Cn`(M02uF{ag|>YbUjU3r+yy>rh! z-}%mWW_h{jN}}kMX)?`Cr%hX?`E~eu289Q_nAPrT7o_roq7+l`{Xh9U%)SKmoYaH2 zXCRMjQ1IyoeCf`%j=Dw@cEW^_IwUiYo9|L;1_e3nlgp#Bf5ICG#)KiML%}!uU=P=# zTy%jAKbeFP{N@rIN~2zi@+{=;V2ilq58~Y^$hY`|vIn1-g*l5FlS2j|Q(wiUkT>kc z?B^gKYx{x6JG1aSepv~H_<9SpT04~*N2L^SR}6@b76r$Lpj!L;9mq+;;V&QqqKY&) zrC@X(1}%bK`Qte#GbH>v2erncZ2?LTvm>!gC=sNC;t;dJ=MX%;s37&Q>kZ1|{Ry^z zbXbQM=AnTX4Cy+r*@RBqtbdD_RG${(l3?FjuruOAl1pLasq`HR>&~H8=;+7gbxeGS z;f^bKF95meVcF*q;!+zPSb{xijY-{&haeGxodyMlLZU?*ev#v&AQ-MZUN+HZ?& zZr1S>Z@Nuy$Z_nt3^u+^ks1~J=UotSvjEcZr!f%lbQ9#0cKq%#)R8gGegy_NQjh1Z z!d|Y|$iP#$`#e~1*L}VUf4K@>q{&RkSwn;kL)Rdi+sB|maBxSH?>P(B)wo26rlSC zxJvpIN!VK0S`f;Z!zsAtlxgoRT5QoR8+7*?6nCrzi1{pa+{OJL&j1?&1Pb$(e!|zfYT7i0U3Kv$`xER;1 z6_B|wH71>J%crh~LYOf=CmvpUC)D0wm(sn2J}4 z)tyq?Z`RgXFRVf_$H>-J;Q*&n{Bae^Nf2|^;5EiDy9RCCgjpLOuE8$i(VN+dlU*8=Oj4k<_za?AsqK>DuOJ gkjNy%82k!K3WjL~4Ne3i4xv~Mg#