summaryrefslogtreecommitdiffstats
path: root/glances/plugins/glances_processlist.py
diff options
context:
space:
mode:
Diffstat (limited to 'glances/plugins/glances_processlist.py')
-rw-r--r--glances/plugins/glances_processlist.py204
1 files changed, 149 insertions, 55 deletions
diff --git a/glances/plugins/glances_processlist.py b/glances/plugins/glances_processlist.py
index 348ea4a6..269a7e4f 100644
--- a/glances/plugins/glances_processlist.py
+++ b/glances/plugins/glances_processlist.py
@@ -24,7 +24,7 @@ import os
from datetime import timedelta
# Import Glances libs
-from glances.core.glances_globals import glances_processes, is_windows
+from glances.core.glances_globals import glances_processes, is_linux, is_bsd, is_mac, is_windows, logger
from glances.plugins.glances_plugin import GlancesPlugin
@@ -41,12 +41,6 @@ class Plugin(GlancesPlugin):
# We want to display the stat in the curse interface
self.display_curse = True
- # Set the message position
- # It is NOT the curse position but the Glances column/line
- # Enter -1 to right align
- self.column_curse = 1
- # Enter -1 to diplay bottom
- self.line_curse = 4
# Note: 'glances_processes' is already init in the glances_processes.py script
@@ -63,10 +57,9 @@ class Plugin(GlancesPlugin):
# Update stats using the standard system lib
# Note: Update is done in the processcount plugin
# Just return the processes list
- self.stats = glances_processes.getlist()
+ self.stats = glances_processes.getlist()
elif self.get_input() == 'snmp':
- # Update stats using SNMP
- # !!! TODO
+ # No SNMP grab for processes
pass
return self.stats
@@ -81,14 +74,10 @@ class Plugin(GlancesPlugin):
return ret
# Compute the sort key
- try:
- args.process_sorted_by
- except AttributeError:
- args.process_sorted_by = glances_processes.getsortkey()
- if args.process_sorted_by == 'auto':
- process_sort_key = glances_processes.getsortkey()
+ if glances_processes.getmanualsortkey() is None:
+ process_sort_key = glances_processes.getautosortkey()
else:
- process_sort_key = args.process_sorted_by
+ process_sort_key = glances_processes.getmanualsortkey()
sort_style = 'SORT'
# Header
@@ -111,9 +100,9 @@ class Plugin(GlancesPlugin):
msg = '{0:>9}'.format(_("TIME+"))
ret.append(self.curse_add_line(msg, optional=True))
msg = '{0:>6}'.format(_("IOR/s"))
- ret.append(self.curse_add_line(msg, sort_style if process_sort_key == 'io_counters' else 'DEFAULT', optional=True))
+ ret.append(self.curse_add_line(msg, sort_style if process_sort_key == 'io_counters' else 'DEFAULT', optional=True, additional=True))
msg = '{0:>6}'.format(_("IOW/s"))
- ret.append(self.curse_add_line(msg, sort_style if process_sort_key == 'io_counters' else 'DEFAULT', optional=True))
+ ret.append(self.curse_add_line(msg, sort_style if process_sort_key == 'io_counters' else 'DEFAULT', optional=True, additional=True))
msg = ' {0:8}'.format(_("Command"))
ret.append(self.curse_add_line(msg))
@@ -121,45 +110,72 @@ class Plugin(GlancesPlugin):
tag_proc_time = True
# Loop over processes (sorted by the sort key previously compute)
+ first = True
for p in self.sortlist(process_sort_key):
ret.append(self.curse_new_line())
# CPU
- msg = '{0:>6.1f}'.format(p['cpu_percent'])
- ret.append(self.curse_add_line(msg,
- self.get_alert(p['cpu_percent'], header="cpu")))
+ if 'cpu_percent' in p and p['cpu_percent'] is not None and p['cpu_percent'] != '':
+ msg = '{0:>6.1f}'.format(p['cpu_percent'])
+ ret.append(self.curse_add_line(msg,
+ self.get_alert(p['cpu_percent'], header="cpu")))
+ else:
+ msg = '{0:>6}'.format('?')
+ ret.append(self.curse_add_line(msg))
# MEM
- msg = '{0:>6.1f}'.format(p['memory_percent'])
- ret.append(self.curse_add_line(msg,
- self.get_alert(p['memory_percent'], header="mem")))
- # VMS
- msg = '{0:>6}'.format(self.auto_unit(p['memory_info'][1], low_precision=False))
- ret.append(self.curse_add_line(msg, optional=True))
- # RSS
- msg = '{0:>6}'.format(self.auto_unit(p['memory_info'][0], low_precision=False))
- ret.append(self.curse_add_line(msg, optional=True))
+ if 'memory_percent' in p and p['memory_percent'] is not None and p['memory_percent'] != '':
+ msg = '{0:>6.1f}'.format(p['memory_percent'])
+ ret.append(self.curse_add_line(msg,
+ self.get_alert(p['memory_percent'], header="mem")))
+ else:
+ msg = '{0:>6}'.format('?')
+ ret.append(self.curse_add_line(msg))
+ # VMS/RSS
+ if 'memory_info' in p and p['memory_info'] is not None and p['memory_info'] != '':
+ # VMS
+ msg = '{0:>6}'.format(self.auto_unit(p['memory_info'][1], low_precision=False))
+ ret.append(self.curse_add_line(msg, optional=True))
+ # RSS
+ msg = '{0:>6}'.format(self.auto_unit(p['memory_info'][0], low_precision=False))
+ ret.append(self.curse_add_line(msg, optional=True))
+ else:
+ msg = '{0:>6}'.format('?')
+ ret.append(self.curse_add_line(msg))
+ ret.append(self.curse_add_line(msg))
# PID
msg = '{0:>6}'.format(p['pid'])
ret.append(self.curse_add_line(msg))
# USER
- # docker internal users are displayed as ints only, therefore str()
- msg = ' {0:9}'.format(str(p['username'])[:9])
- ret.append(self.curse_add_line(msg))
+ if 'username' in p:
+ # docker internal users are displayed as ints only, therefore str()
+ msg = ' {0:9}'.format(str(p['username'])[:9])
+ ret.append(self.curse_add_line(msg))
+ else:
+ msg = ' {0:9}'.format('?')
+ ret.append(self.curse_add_line(msg))
# NICE
- nice = p['nice']
- if nice is None:
- nice = '?'
- msg = '{0:>5}'.format(nice)
- if isinstance(nice, int) and ((is_windows and nice != 32) or
- (not is_windows and nice != 0)):
- ret.append(self.curse_add_line(msg, decoration='NICE'))
+ if 'nice' in p:
+ nice = p['nice']
+ if nice is None:
+ nice = '?'
+ msg = '{0:>5}'.format(nice)
+ if isinstance(nice, int) and ((is_windows and nice != 32) or
+ (not is_windows and nice != 0)):
+ ret.append(self.curse_add_line(msg, decoration='NICE'))
+ else:
+ ret.append(self.curse_add_line(msg))
else:
+ msg = '{0:>5}'.format('?')
ret.append(self.curse_add_line(msg))
# STATUS
- status = p['status']
- msg = '{0:>2}'.format(status)
- if status == 'R':
- ret.append(self.curse_add_line(msg, decoration='STATUS'))
+ if 'status' in p:
+ status = p['status']
+ msg = '{0:>2}'.format(status)
+ if status == 'R':
+ ret.append(self.curse_add_line(msg, decoration='STATUS'))
+ else:
+ ret.append(self.curse_add_line(msg))
else:
+ msg = '{0:>2}'.format('?')
ret.append(self.curse_add_line(msg))
# TIME+
if tag_proc_time:
@@ -185,29 +201,30 @@ class Plugin(GlancesPlugin):
msg = '{0:>6}'.format("0")
else:
msg = '{0:>6}'.format(self.auto_unit(io_rs, low_precision=False))
- ret.append(self.curse_add_line(msg, optional=True))
+ ret.append(self.curse_add_line(msg, optional=True, additional=True))
# IO write
io_ws = (p['io_counters'][1] - p['io_counters'][3]) / p['time_since_update']
if io_ws == 0:
msg = '{0:>6}'.format("0")
else:
msg = '{0:>6}'.format(self.auto_unit(io_ws, low_precision=False))
- ret.append(self.curse_add_line(msg, optional=True))
+ ret.append(self.curse_add_line(msg, optional=True, additional=True))
else:
msg = '{0:>6}'.format("?")
- ret.append(self.curse_add_line(msg, optional=True))
- ret.append(self.curse_add_line(msg, optional=True))
+ ret.append(self.curse_add_line(msg, optional=True, additional=True))
+ ret.append(self.curse_add_line(msg, optional=True, additional=True))
+
# Command line
# If no command line for the process is available, fallback to
# the bare process name instead
cmdline = p['cmdline']
- if cmdline == "":
+ if cmdline == "" or args.process_short_name:
msg = ' {0}'.format(p['name'])
ret.append(self.curse_add_line(msg, splittable=True))
else:
try:
cmd = cmdline.split()[0]
- args = ' '.join(cmdline.split()[1:])
+ argument = ' '.join(cmdline.split()[1:])
path, basename = os.path.split(cmd)
if os.path.isdir(path):
msg = ' {0}'.format(path) + os.sep
@@ -216,11 +233,83 @@ class Plugin(GlancesPlugin):
else:
msg = ' {0}'.format(basename)
ret.append(self.curse_add_line(msg, decoration='PROCESS', splittable=True))
- msg = " {0}".format(args)
+ msg = " {0}".format(argument)
ret.append(self.curse_add_line(msg, splittable=True))
except UnicodeEncodeError:
ret.append(self.curse_add_line("", splittable=True))
+ # Add extended stats but only for the top processes
+ # !!! CPU consumption ???
+ # TODO: extended stats into the web interface
+ if first and 'extended_stats' in p:
+ # Left padding
+ xpad = ' ' * 13
+ # First line is CPU affinity
+ if 'cpu_affinity' in p and p['cpu_affinity'] is not None:
+ ret.append(self.curse_new_line())
+ msg = xpad + _('CPU affinity: ') + str(len(p['cpu_affinity'])) + _(' cores')
+ ret.append(self.curse_add_line(msg, splittable=True))
+ # Second line is memory info
+ if 'memory_info_ex' in p and p['memory_info_ex'] is not None:
+ ret.append(self.curse_new_line())
+ msg = xpad + _('Memory info: ')
+ for k, v in p['memory_info_ex']._asdict().items():
+ # Ignore rss and vms (already displayed)
+ if k not in ['rss', 'vms'] and v is not None:
+ msg += k + ' ' + self.auto_unit(v, low_precision=False) + ' '
+ if 'memory_swap' in p and p['memory_swap'] is not None:
+ msg += _('swap ') + self.auto_unit(p['memory_swap'], low_precision=False)
+ ret.append(self.curse_add_line(msg, splittable=True))
+ # Third line is for openned files/network sessions
+ ret.append(self.curse_new_line())
+ msg = xpad + _('Openned: ')
+ if 'num_threads' in p and p['num_threads'] is not None:
+ msg += _('threads ') + str(p['num_threads']) + ' '
+ if 'num_fds' in p and p['num_fds'] is not None:
+ msg += _('files ') + str(p['num_fds']) + ' '
+ if 'num_handles' in p and p['num_handles'] is not None:
+ msg += _('handles ') + str(p['num_handles']) + ' '
+ if 'tcp' in p and p['tcp'] is not None:
+ msg += _('TCP ') + str(p['tcp']) + ' '
+ if 'udp' in p and p['udp'] is not None:
+ msg += _('UDP ') + str(p['udp']) + ' '
+ ret.append(self.curse_add_line(msg, splittable=True))
+ # Fouth line is IO nice level (only Linux and Windows OS)
+ if 'ionice' in p and p['ionice'] is not None:
+ ret.append(self.curse_new_line())
+ msg = xpad + _('IO nice: ')
+ k = _('Class is ')
+ v = p['ionice'].ioclass
+ # Linux: The scheduling class. 0 for none, 1 for real time, 2 for best-effort, 3 for idle.
+ # Windows: On Windows only ioclass is used and it can be set to 2 (normal), 1 (low) or 0 (very low).
+ if is_windows:
+ if v == 0:
+ msg += k + 'Very Low'
+ elif v == 1:
+ msg += k + 'Low'
+ elif v == 2:
+ msg += _('No specific I/O priority')
+ else:
+ msg += k + str(v)
+ else:
+ if v == 0:
+ msg += _('No specific I/O priority')
+ elif v == 1:
+ msg += k + 'Real Time'
+ elif v == 2:
+ msg += k + 'Best Effort'
+ elif v == 3:
+ msg += k + 'IDLE'
+ else:
+ msg += k + str(v)
+ # value is a number which goes from 0 to 7.
+ # The higher the value, the lower the I/O priority of the process.
+ if hasattr(p['ionice'], 'value') and p['ionice'].value != 0:
+ msg += _(' (value %s/7)') % str(p['ionice'].value)
+ ret.append(self.curse_add_line(msg, splittable=True))
+ # End of extended stats
+ first = False
+
# Return the message with decoration
return ret
@@ -250,9 +339,14 @@ class Plugin(GlancesPlugin):
reverse=sortedreverse)
else:
# Others sorts
- listsorted = sorted(self.stats,
- key=lambda process: process[sortedby],
- reverse=sortedreverse)
+ try:
+ listsorted = sorted(self.stats,
+ key=lambda process: process[sortedby],
+ reverse=sortedreverse)
+ except KeyError:
+ listsorted = sorted(self.stats,
+ key=lambda process: process['name'],
+ reverse=False)
self.stats = listsorted