First version of the #2662 - Need to study how to display the swap

This commit is contained in:
nicolargo 2024-01-20 14:56:57 +01:00
parent 5841d588c8
commit ef9694cd6a
4 changed files with 102 additions and 48 deletions

View File

@ -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:

View File

@ -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):

View File

@ -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

View File

@ -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)