summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authornicolargo <nicolas@nicolargo.com>2024-01-20 14:56:57 +0100
committernicolargo <nicolas@nicolargo.com>2024-01-20 14:56:57 +0100
commitef9694cd6ada357c56b338bb5aa069575a7c397b (patch)
treed4bf802e8ee46a47fa50724f4bd15c6bbb2ab815
parent5841d588c8347f46441d1ad426acce05b8891636 (diff)
First version of the #2662 - Need to study how to display the swap
-rw-r--r--conf/glances.conf4
-rw-r--r--glances/outputs/glances_bars.py31
-rw-r--r--glances/plugins/load/__init__.py66
-rw-r--r--glances/plugins/quicklook/__init__.py49
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 <nicolas@nicolargo.com>
+# SPDX-FileCopyrightText: 2024 Nicolas Hennion <nicolas@nicolargo.com>
#
# 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)