mirror of
https://github.com/nicolargo/glances.git
synced 2024-11-23 20:45:33 +03:00
First version but only for the TUI standalone mode
This commit is contained in:
parent
e1cd3ded23
commit
34520ca45b
@ -410,6 +410,10 @@ disable=False
|
||||
# Should be one of the following:
|
||||
# cpu_percent, memory_percent, io_counters, name, cpu_times, username
|
||||
#sort_key=memory_percent
|
||||
# List of stats to disable (not grabed and not display)
|
||||
# Stats that can be disabled: cpu_percent,memory_info,memory_percent,username,cpu_times,num_threads,nice,status,io_counters,cmdline
|
||||
# Stats that can not be disable: pid,name
|
||||
#disable_stats=cpu_percent,memory_info,memory_percent,username,cpu_times,num_threads,nice,status,io_counters,cmdline
|
||||
# Define CPU/MEM (per process) thresholds in %
|
||||
# Default values if not defined: 50/70/90
|
||||
cpu_careful=50
|
||||
|
@ -18,7 +18,7 @@ from glances import __apiversion__, __version__, psutil_version
|
||||
from glances.config import Config
|
||||
from glances.globals import WINDOWS, disable, enable
|
||||
from glances.logger import LOG_FILENAME, logger
|
||||
from glances.processes import sort_processes_key_list
|
||||
from glances.processes import sort_processes_stats_list
|
||||
|
||||
|
||||
class GlancesMain:
|
||||
@ -269,8 +269,8 @@ Examples of use:
|
||||
parser.add_argument(
|
||||
'--sort-processes',
|
||||
dest='sort_processes_key',
|
||||
choices=sort_processes_key_list,
|
||||
help='Sort processes by: {}'.format(', '.join(sort_processes_key_list)),
|
||||
choices=sort_processes_stats_list,
|
||||
help='Sort processes by: {}'.format(', '.join(sort_processes_stats_list)),
|
||||
)
|
||||
# Display processes list by program name and not by thread
|
||||
parser.add_argument(
|
||||
|
@ -16,7 +16,7 @@ from glances.globals import MACOS, WINDOWS, disable, enable, itervalues, natives
|
||||
from glances.logger import logger
|
||||
from glances.outputs.glances_colors import GlancesColors
|
||||
from glances.outputs.glances_unicode import unicode_message
|
||||
from glances.processes import glances_processes, sort_processes_key_list
|
||||
from glances.processes import glances_processes, sort_processes_stats_list
|
||||
from glances.timer import Timer
|
||||
|
||||
# Import curses library for "normal" operating system
|
||||
@ -97,7 +97,7 @@ class _GlancesCurses:
|
||||
# 'DOWN' > Down in the server list
|
||||
}
|
||||
|
||||
_sort_loop = sort_processes_key_list
|
||||
_sort_loop = sort_processes_stats_list
|
||||
|
||||
# Define top menu
|
||||
_top = ['quicklook', 'cpu', 'percpu', 'gpu', 'mem', 'memswap', 'load']
|
||||
|
@ -117,6 +117,22 @@ class PluginModel(GlancesPluginModel):
|
||||
stats is a list
|
||||
"""
|
||||
|
||||
# Default list of processes stats to be grabbed / displayed
|
||||
# Can be altered by glances_processes.disable_stats
|
||||
enable_stats = [
|
||||
'cpu_percent',
|
||||
'memory_percent',
|
||||
'memory_info', # vms and rss
|
||||
'pid',
|
||||
'username',
|
||||
'cpu_times',
|
||||
'num_threads',
|
||||
'nice',
|
||||
'status',
|
||||
'io_counters', # ior and iow
|
||||
'cmdline',
|
||||
]
|
||||
|
||||
# Define the header layout of the processes list columns
|
||||
layout_header = {
|
||||
'cpu': '{:<6} ',
|
||||
@ -176,19 +192,8 @@ class PluginModel(GlancesPluginModel):
|
||||
# Use to optimize space (see https://github.com/nicolargo/glances/issues/959)
|
||||
self.pid_max = glances_processes.pid_max
|
||||
|
||||
# Set the default sort key if it is defined in the configuration file
|
||||
if config is not None and 'processlist' in config.as_dict():
|
||||
if 'sort_key' in config.as_dict()['processlist']:
|
||||
logger.debug(
|
||||
'Configuration overwrites processes sort key by {}'.format(
|
||||
config.as_dict()['processlist']['sort_key']
|
||||
)
|
||||
)
|
||||
glances_processes.set_sort_key(config.as_dict()['processlist']['sort_key'], False)
|
||||
if 'export' in config.as_dict()['processlist']:
|
||||
glances_processes.export_process_filter = config.as_dict()['processlist']['export']
|
||||
if args.export:
|
||||
logger.info("Export process filter is set to: {}".format(config.as_dict()['processlist']['export']))
|
||||
# Load the config file
|
||||
self.load(args, config)
|
||||
|
||||
# The default sort key could also be overwrite by command line (see #1903)
|
||||
if args and args.sort_processes_key is not None:
|
||||
@ -196,6 +201,27 @@ class PluginModel(GlancesPluginModel):
|
||||
|
||||
# Note: 'glances_processes' is already init in the processes.py script
|
||||
|
||||
def load(self, args, config):
|
||||
# Set the default sort key if it is defined in the configuration file
|
||||
if config is None or 'processlist' not in config.as_dict():
|
||||
return
|
||||
if 'sort_key' in config.as_dict()['processlist']:
|
||||
logger.debug(
|
||||
'Configuration overwrites processes sort key by {}'.format(config.as_dict()['processlist']['sort_key'])
|
||||
)
|
||||
glances_processes.set_sort_key(config.as_dict()['processlist']['sort_key'], False)
|
||||
if 'export' in config.as_dict()['processlist']:
|
||||
glances_processes.export_process_filter = config.as_dict()['processlist']['export']
|
||||
if args.export:
|
||||
logger.info("Export process filter is set to: {}".format(config.as_dict()['processlist']['export']))
|
||||
if 'disable_stats' in config.as_dict()['processlist']:
|
||||
logger.info(
|
||||
'Followings processes stats wil not be displayed: {}'.format(
|
||||
config.as_dict()['processlist']['disable_stats']
|
||||
)
|
||||
)
|
||||
glances_processes.disable_stats = config.as_dict()['processlist']['disable_stats'].split(',')
|
||||
|
||||
def get_key(self):
|
||||
"""Return the key of the list."""
|
||||
return 'pid'
|
||||
@ -255,7 +281,7 @@ class PluginModel(GlancesPluginModel):
|
||||
pass
|
||||
return 'DEFAULT'
|
||||
|
||||
def _get_process_curses_cpu(self, p, selected, args):
|
||||
def _get_process_curses_cpu_percent(self, p, selected, args):
|
||||
"""Return process CPU curses"""
|
||||
if key_exist_value_not_none_not_v('cpu_percent', p, ''):
|
||||
cpu_layout = self.layout_stat['cpu'] if p['cpu_percent'] < 100 else self.layout_stat['cpu_no_digit']
|
||||
@ -275,7 +301,7 @@ class PluginModel(GlancesPluginModel):
|
||||
ret = self.curse_add_line(msg)
|
||||
return ret
|
||||
|
||||
def _get_process_curses_mem(self, p, selected, args):
|
||||
def _get_process_curses_memory_percent(self, p, selected, args):
|
||||
"""Return process MEM curses"""
|
||||
if key_exist_value_not_none_not_v('memory_percent', p, ''):
|
||||
msg = self.layout_stat['mem'].format(p['memory_percent'])
|
||||
@ -311,6 +337,12 @@ class PluginModel(GlancesPluginModel):
|
||||
ret = self.curse_add_line(msg)
|
||||
return ret
|
||||
|
||||
def _get_process_curses_memory_info(self, p, selected, args):
|
||||
return [
|
||||
self._get_process_curses_vms(p, selected, args),
|
||||
self._get_process_curses_rss(p, selected, args),
|
||||
]
|
||||
|
||||
def _get_process_curses_pid(self, p, selected, args):
|
||||
"""Return process PID curses"""
|
||||
if not self.args.programs:
|
||||
@ -334,7 +366,7 @@ class PluginModel(GlancesPluginModel):
|
||||
msg = self.layout_header['user'].format('?')
|
||||
return self.curse_add_line(msg)
|
||||
|
||||
def _get_process_curses_time(self, p, selected, args):
|
||||
def _get_process_curses_cpu_times(self, p, selected, args):
|
||||
"""Return process time curses"""
|
||||
cpu_times = p['cpu_times']
|
||||
try:
|
||||
@ -365,7 +397,7 @@ class PluginModel(GlancesPluginModel):
|
||||
|
||||
return self.curse_add_line(msg, optional=True)
|
||||
|
||||
def _get_process_curses_thread(self, p, selected, args):
|
||||
def _get_process_curses_num_threads(self, p, selected, args):
|
||||
"""Return process thread curses"""
|
||||
if 'num_threads' in p:
|
||||
num_threads = p['num_threads']
|
||||
@ -422,14 +454,14 @@ class PluginModel(GlancesPluginModel):
|
||||
ret = self.curse_add_line(msg, optional=True, additional=True)
|
||||
return ret
|
||||
|
||||
def _get_process_curses_io(self, p, selected, args):
|
||||
def _get_process_curses_io_counters(self, p, selected, args):
|
||||
return [
|
||||
self._get_process_curses_io_read_write(p, selected, args, rorw='ior'),
|
||||
self._get_process_curses_io_read_write(p, selected, args, rorw='iow'),
|
||||
]
|
||||
|
||||
def _get_process_curses_command(self, p, selected, args):
|
||||
"""Return process command curses"""
|
||||
def _get_process_curses_cmdline(self, p, selected, args):
|
||||
"""Return process cmdline curses"""
|
||||
ret = []
|
||||
# If no command line for the process is available, fallback to the bare process name instead
|
||||
bare_process_name = p['name']
|
||||
@ -476,20 +508,7 @@ class PluginModel(GlancesPluginModel):
|
||||
)
|
||||
)
|
||||
|
||||
for stat in [
|
||||
'cpu',
|
||||
'mem',
|
||||
'vms',
|
||||
'rss',
|
||||
'pid',
|
||||
'username',
|
||||
'time',
|
||||
'thread',
|
||||
'nice',
|
||||
'status',
|
||||
'io',
|
||||
'command',
|
||||
]:
|
||||
for stat in [i for i in self.enable_stats if i not in glances_processes.disable_stats]:
|
||||
msg = getattr(self, f'_get_process_curses_{stat}')(p, selected, args)
|
||||
if isinstance(msg, list):
|
||||
# ex: _get_process_curses_command return a list, so extend
|
||||
@ -718,48 +737,61 @@ class PluginModel(GlancesPluginModel):
|
||||
"""Build the header and add it to the ret dict."""
|
||||
sort_style = 'SORT'
|
||||
|
||||
if args.disable_irix and 0 < self.nb_log_core < 10:
|
||||
msg = self.layout_header['cpu'].format('CPU%/' + str(self.nb_log_core))
|
||||
elif args.disable_irix and self.nb_log_core != 0:
|
||||
msg = self.layout_header['cpu'].format('CPU%/C')
|
||||
else:
|
||||
msg = self.layout_header['cpu'].format('CPU%')
|
||||
ret.append(self.curse_add_line(msg, sort_style if process_sort_key == 'cpu_percent' else 'DEFAULT'))
|
||||
msg = self.layout_header['mem'].format('MEM%')
|
||||
ret.append(self.curse_add_line(msg, sort_style if process_sort_key == 'memory_percent' else 'DEFAULT'))
|
||||
msg = self.layout_header['virt'].format('VIRT')
|
||||
ret.append(self.curse_add_line(msg, optional=True))
|
||||
msg = self.layout_header['res'].format('RES')
|
||||
ret.append(self.curse_add_line(msg, optional=True))
|
||||
if not self.args.programs:
|
||||
msg = self.layout_header['pid'].format('PID', width=self.__max_pid_size())
|
||||
else:
|
||||
msg = self.layout_header['pid'].format('NPROCS', width=self.__max_pid_size())
|
||||
ret.append(self.curse_add_line(msg))
|
||||
msg = self.layout_header['user'].format('USER')
|
||||
ret.append(self.curse_add_line(msg, sort_style if process_sort_key == 'username' else 'DEFAULT'))
|
||||
msg = self.layout_header['time'].format('TIME+')
|
||||
ret.append(
|
||||
self.curse_add_line(msg, sort_style if process_sort_key == 'cpu_times' else 'DEFAULT', optional=True)
|
||||
)
|
||||
msg = self.layout_header['thread'].format('THR')
|
||||
ret.append(self.curse_add_line(msg))
|
||||
msg = self.layout_header['nice'].format('NI')
|
||||
ret.append(self.curse_add_line(msg))
|
||||
msg = self.layout_header['status'].format('S')
|
||||
ret.append(self.curse_add_line(msg))
|
||||
msg = self.layout_header['ior'].format('R/s')
|
||||
ret.append(
|
||||
self.curse_add_line(
|
||||
msg, sort_style if process_sort_key == 'io_counters' else 'DEFAULT', optional=True, additional=True
|
||||
display_stats = [i for i in self.enable_stats if i not in glances_processes.disable_stats]
|
||||
|
||||
if 'cpu_percent' in display_stats:
|
||||
if args.disable_irix and 0 < self.nb_log_core < 10:
|
||||
msg = self.layout_header['cpu'].format('CPU%/' + str(self.nb_log_core))
|
||||
elif args.disable_irix and self.nb_log_core != 0:
|
||||
msg = self.layout_header['cpu'].format('CPU%/C')
|
||||
else:
|
||||
msg = self.layout_header['cpu'].format('CPU%')
|
||||
ret.append(self.curse_add_line(msg, sort_style if process_sort_key == 'cpu_percent' else 'DEFAULT'))
|
||||
|
||||
if 'memory_percent' in display_stats:
|
||||
msg = self.layout_header['mem'].format('MEM%')
|
||||
ret.append(self.curse_add_line(msg, sort_style if process_sort_key == 'memory_percent' else 'DEFAULT'))
|
||||
if 'memory_info' in display_stats:
|
||||
msg = self.layout_header['virt'].format('VIRT')
|
||||
ret.append(self.curse_add_line(msg, optional=True))
|
||||
msg = self.layout_header['res'].format('RES')
|
||||
ret.append(self.curse_add_line(msg, optional=True))
|
||||
if 'pid' in display_stats:
|
||||
if not self.args.programs:
|
||||
msg = self.layout_header['pid'].format('PID', width=self.__max_pid_size())
|
||||
else:
|
||||
msg = self.layout_header['pid'].format('NPROCS', width=self.__max_pid_size())
|
||||
ret.append(self.curse_add_line(msg))
|
||||
if 'username' in display_stats:
|
||||
msg = self.layout_header['user'].format('USER')
|
||||
ret.append(self.curse_add_line(msg, sort_style if process_sort_key == 'username' else 'DEFAULT'))
|
||||
if 'cpu_times' in display_stats:
|
||||
msg = self.layout_header['time'].format('TIME+')
|
||||
ret.append(
|
||||
self.curse_add_line(msg, sort_style if process_sort_key == 'cpu_times' else 'DEFAULT', optional=True)
|
||||
)
|
||||
)
|
||||
msg = self.layout_header['iow'].format('W/s')
|
||||
ret.append(
|
||||
self.curse_add_line(
|
||||
msg, sort_style if process_sort_key == 'io_counters' else 'DEFAULT', optional=True, additional=True
|
||||
if 'num_threads' in display_stats:
|
||||
msg = self.layout_header['thread'].format('THR')
|
||||
ret.append(self.curse_add_line(msg))
|
||||
if 'nice' in display_stats:
|
||||
msg = self.layout_header['nice'].format('NI')
|
||||
ret.append(self.curse_add_line(msg))
|
||||
if 'status' in display_stats:
|
||||
msg = self.layout_header['status'].format('S')
|
||||
ret.append(self.curse_add_line(msg))
|
||||
if 'io_counters' in display_stats:
|
||||
msg = self.layout_header['ior'].format('R/s')
|
||||
ret.append(
|
||||
self.curse_add_line(
|
||||
msg, sort_style if process_sort_key == 'io_counters' else 'DEFAULT', optional=True, additional=True
|
||||
)
|
||||
)
|
||||
msg = self.layout_header['iow'].format('W/s')
|
||||
ret.append(
|
||||
self.curse_add_line(
|
||||
msg, sort_style if process_sort_key == 'io_counters' else 'DEFAULT', optional=True, additional=True
|
||||
)
|
||||
)
|
||||
)
|
||||
if args.is_standalone and not args.disable_cursor:
|
||||
if self.args.programs:
|
||||
shortkey = "('k' to kill)"
|
||||
@ -767,8 +799,9 @@ class PluginModel(GlancesPluginModel):
|
||||
shortkey = "('e' to pin | 'k' to kill)"
|
||||
else:
|
||||
shortkey = ""
|
||||
msg = self.layout_header['command'].format("Programs" if self.args.programs else "Command", shortkey)
|
||||
ret.append(self.curse_add_line(msg, sort_style if process_sort_key == 'name' else 'DEFAULT'))
|
||||
if 'cmdline' in display_stats:
|
||||
msg = self.layout_header['command'].format("Programs" if self.args.programs else "Command", shortkey)
|
||||
ret.append(self.curse_add_line(msg, sort_style if process_sort_key == 'name' else 'DEFAULT'))
|
||||
|
||||
def __msg_curse_sum(self, ret, sep_char='_', mmm=None, args=None):
|
||||
"""
|
||||
|
@ -18,8 +18,11 @@ from glances.timer import Timer, getTimeSinceLastUpdate
|
||||
|
||||
psutil_version_info = tuple([int(num) for num in psutil.__version__.split('.')])
|
||||
|
||||
# This constant defines the list of mandatory processes stats. Thoses stats can not be disabled by the user
|
||||
mandatory_processes_stats_list = ['pid', 'name']
|
||||
|
||||
# This constant defines the list of available processes sort key
|
||||
sort_processes_key_list = ['cpu_percent', 'memory_percent', 'username', 'cpu_times', 'io_counters', 'name']
|
||||
sort_processes_stats_list = ['cpu_percent', 'memory_percent', 'username', 'cpu_times', 'io_counters', 'name']
|
||||
|
||||
# Sort dictionary for human
|
||||
sort_for_human = {
|
||||
@ -38,7 +41,7 @@ class GlancesProcesses:
|
||||
|
||||
def __init__(self, cache_timeout=60):
|
||||
"""Init the class to collect stats about processes."""
|
||||
# Init the args, coming from the GlancesStandalone class
|
||||
# Init the args, coming from the classes derived from GlancesMode
|
||||
# Should be set by the set_args method
|
||||
self.args = None
|
||||
|
||||
@ -96,6 +99,9 @@ class GlancesProcesses:
|
||||
self._max_values = {}
|
||||
self.reset_max_values()
|
||||
|
||||
# Set the key's list be disabled in order to only display specific attribte in the process list
|
||||
self.disable_stats = []
|
||||
|
||||
def _test_grab(self):
|
||||
"""Test somes optionals features"""
|
||||
# Test if the system can grab io_counters
|
||||
@ -143,9 +149,12 @@ class GlancesProcesses:
|
||||
# For each key in the processcount dict
|
||||
# count the number of processes with the same status
|
||||
for k in iterkeys(self.processcount):
|
||||
self.processcount[k] = len(list(filter(lambda v: v['status'] is k, plist)))
|
||||
self.processcount[k] = len(list(filter(lambda v: v.get('status', '?') is k, plist)))
|
||||
# Compute thread
|
||||
self.processcount['thread'] = sum(i['num_threads'] for i in plist if i['num_threads'] is not None)
|
||||
try:
|
||||
self.processcount['thread'] = sum(i['num_threads'] for i in plist if i['num_threads'] is not None)
|
||||
except KeyError:
|
||||
self.processcount['thread'] = None
|
||||
# Compute total
|
||||
self.processcount['total'] = len(plist)
|
||||
|
||||
@ -215,7 +224,15 @@ class GlancesProcesses:
|
||||
"""Set the maximum number of processes showed in the UI."""
|
||||
self._max_processes = value
|
||||
|
||||
# Process filter
|
||||
@property
|
||||
def disable_stats(self):
|
||||
"""Set disable_stats list"""
|
||||
return self._disable_stats
|
||||
|
||||
@disable_stats.setter
|
||||
def disable_stats(self, stats_list):
|
||||
"""Set disable_stats list"""
|
||||
self._disable_stats = [i for i in stats_list if i not in mandatory_processes_stats_list]
|
||||
|
||||
@property
|
||||
def process_filter_input(self):
|
||||
@ -445,6 +462,9 @@ class GlancesProcesses:
|
||||
else:
|
||||
is_cached = True
|
||||
|
||||
# Remove attributes set by the user in the config file (see #1524)
|
||||
sorted_attrs = [i for i in sorted_attrs if i not in self.disable_stats]
|
||||
|
||||
# Build the processes stats list (it is why we need psutil>=5.3.0) (see issue #2755)
|
||||
processlist = list(
|
||||
filter(
|
||||
@ -491,7 +511,7 @@ class GlancesProcesses:
|
||||
proc['time_since_update'] = time_since_update
|
||||
|
||||
# Process status (only keep the first char)
|
||||
proc['status'] = str(proc['status'])[:1].upper()
|
||||
proc['status'] = str(proc.get('status', '?'))[:1].upper()
|
||||
|
||||
# Process IO
|
||||
# procstat['io_counters'] is a list:
|
||||
@ -553,7 +573,7 @@ class GlancesProcesses:
|
||||
|
||||
# Compute the maximum value for keys in self._max_values_list: CPU, MEM
|
||||
# Useful to highlight the processes with maximum values
|
||||
for k in self._max_values_list:
|
||||
for k in [i for i in self._max_values_list if i not in self.disable_stats]:
|
||||
values_list = [i[k] for i in processlist if i[k] is not None]
|
||||
if values_list:
|
||||
self.set_max_values(k, max(values_list))
|
||||
|
@ -17,6 +17,7 @@ from defusedxml import xmlrpc
|
||||
|
||||
from glances import __version__
|
||||
from glances.logger import logger
|
||||
from glances.processes import glances_processes
|
||||
from glances.servers_list_dynamic import GlancesAutoDiscoverClient
|
||||
from glances.stats_server import GlancesStatsServer
|
||||
from glances.timer import Timer
|
||||
@ -176,6 +177,9 @@ class GlancesServer:
|
||||
# Args
|
||||
self.args = args
|
||||
|
||||
# Set the args for the glances_processes instance
|
||||
glances_processes.set_args(args)
|
||||
|
||||
# Init the XML RPC server
|
||||
try:
|
||||
self.server = GlancesXMLRPCServer(args.bind_address, args.port, requestHandler, config=config)
|
||||
|
@ -48,7 +48,7 @@ class GlancesStandalone:
|
||||
self.display_modules_list()
|
||||
sys.exit(0)
|
||||
|
||||
# The args is needed to get the selected process in the process list (Curses mode)
|
||||
# Set the args for the glances_processes instance
|
||||
glances_processes.set_args(args)
|
||||
|
||||
# If process extended stats is disabled by user
|
||||
|
@ -25,6 +25,9 @@ class GlancesWebServer:
|
||||
# Ignore kernel threads in process list
|
||||
glances_processes.disable_kernel_threads()
|
||||
|
||||
# Set the args for the glances_processes instance
|
||||
glances_processes.set_args(args)
|
||||
|
||||
# Initial system information update
|
||||
self.stats.update()
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user