diff options
Diffstat (limited to 'glances/core/glances_processes.py')
-rw-r--r-- | glances/core/glances_processes.py | 620 |
1 files changed, 310 insertions, 310 deletions
diff --git a/glances/core/glances_processes.py b/glances/core/glances_processes.py index 6584a3d0..34a786ae 100644 --- a/glances/core/glances_processes.py +++ b/glances/core/glances_processes.py @@ -19,47 +19,47 @@ # Import Python lib import collections -import operator import os import re -# Import psutil -import psutil - # Import Glances lib from glances.core.glances_globals import is_bsd, is_linux, is_mac, is_windows from glances.core.glances_logging import logger -from glances.core.glances_timer import getTimeSinceLastUpdate, Timer +from glances.core.glances_timer import Timer, getTimeSinceLastUpdate + +# Import psutil +import psutil def is_kernel_thread(proc): - """ Return True if proc is a kernel thread, False instead. """ + """Return True if proc is a kernel thread, False instead.""" try: return os.getpgid(proc.pid) == 0 - except OSError: # Python >= 3.3 raises ProcessLookupError, which inherits OSError + # Python >= 3.3 raises ProcessLookupError, which inherits OSError + except OSError: # return False is process is dead return False class ProcessTreeNode(object): - """ - Represent a process tree. + """Represent a process tree. - We avoid recursive algorithm to manipulate the tree because function calls are expensive with CPython. + We avoid recursive algorithm to manipulate the tree because function + calls are expensive with CPython. """ - def __init__(self, process=None, stats=None, sort_key=None, root=False): + def __init__(self, process=None, stats=None, sort_key=None, sort_reverse=True, root=False): self.process = process self.stats = stats self.children = [] self.children_sorted = False self.sort_key = sort_key - self.reverse_sorting = (self.sort_key != "name") + self.sort_reverse = sort_reverse self.is_root = root def __str__(self): - """ Return the tree as a string for debugging. """ + """Return the tree as a string for debugging.""" lines = [] nodes_to_print = collections.deque([collections.deque([("#", self)])]) while nodes_to_print: @@ -69,7 +69,8 @@ class ProcessTreeNode(object): if current_node.is_root: lines.append(indent_str) else: - lines.append("%s[%s]" % (indent_str, current_node.process.name())) + lines.append("%s[%s]" % + (indent_str, current_node.process.name())) indent_str = " " * (len(lines[-1]) - 1) children_nodes_to_print = collections.deque() for child in current_node.children: @@ -77,14 +78,18 @@ class ProcessTreeNode(object): tree_char = "└─" else: tree_char = "├─" - children_nodes_to_print.appendleft((indent_str + tree_char, child)) + children_nodes_to_print.appendleft( + (indent_str + tree_char, child)) if children_nodes_to_print: nodes_to_print.append(children_nodes_to_print) return "\n".join(lines) def set_sorting(self, key, reverse): - """ Set sorting key or func for user with __iter__ (affects the whole tree from this node). """ - if (self.sort_key != key) or (self.reverse_sorting != reverse): + """Set sorting key or func for use with __iter__. + + This affects the whole tree from this node. + """ + if self.sort_key != key or self.sort_reverse != reverse: nodes_to_flag_unsorted = collections.deque([self]) while nodes_to_flag_unsorted: current_node = nodes_to_flag_unsorted.pop() @@ -94,8 +99,8 @@ class ProcessTreeNode(object): nodes_to_flag_unsorted.extend(current_node.children) def get_weight(self): - """ Return "weight" of a process and all its children for sorting. """ - if self.sort_key == "name": + """Return 'weight' of a process and all its children for sorting.""" + if self.sort_key == 'name' or self.sort_key == 'username': return self.stats[self.sort_key] # sum ressource usage for self and children @@ -128,53 +133,63 @@ class ProcessTreeNode(object): return total def __iter__(self): - """ Iterator returning ProcessTreeNode in sorted order, recursively. """ + """Iterator returning ProcessTreeNode in sorted order, recursively.""" if not self.is_root: yield self if not self.children_sorted: # optimization to avoid sorting twice (once when limiting the maximum processes to grab stats for, # and once before displaying) - self.children.sort(key=self.__class__.get_weight, reverse=self.reverse_sorting) + self.children.sort( + key=self.__class__.get_weight, reverse=self.sort_reverse) self.children_sorted = True for child in self.children: for n in iter(child): yield n def iter_children(self, exclude_incomplete_stats=True): - """ - Iterator returning ProcessTreeNode in sorted order (only children of this node, non recursive). + """Iterator returning ProcessTreeNode in sorted order. - If exclude_incomplete_stats is True, exclude processes not having full statistics. - It can happen after a resort (change of sort key) because process stats are not grabbed immediately, - but only at next full update. + Return only children of this node, non recursive. + + If exclude_incomplete_stats is True, exclude processes not + having full statistics. It can happen after a resort (change of + sort key) because process stats are not grabbed immediately, but + only at next full update. """ if not self.children_sorted: # optimization to avoid sorting twice (once when limiting the maximum processes to grab stats for, # and once before displaying) - self.children.sort(key=self.__class__.get_weight, reverse=self.reverse_sorting) + self.children.sort( + key=self.__class__.get_weight, reverse=self.sort_reverse) self.children_sorted = True for child in self.children: - if (not exclude_incomplete_stats) or ("time_since_update" in child.stats): + if not exclude_incomplete_stats or "time_since_update" in child.stats: yield child def find_process(self, process): - """ Search in tree for the ProcessTreeNode owning process, return it or None if not found. """ + """Search in tree for the ProcessTreeNode owning process. + + Return it or None if not found. + """ nodes_to_search = collections.deque([self]) while nodes_to_search: current_node = nodes_to_search.pop() - if (not current_node.is_root) and (current_node.process.pid == process.pid): + if not current_node.is_root and current_node.process.pid == process.pid: return current_node nodes_to_search.extend(current_node.children) @staticmethod - def build_tree(process_dict, sort_key, hide_kernel_threads): - """ Build a process tree using using parent/child relationships, and return the tree root node. """ + def build_tree(process_dict, sort_key, sort_reverse, hide_kernel_threads): + """Build a process tree using using parent/child relationships. + + Return the tree root node. + """ tree_root = ProcessTreeNode(root=True) nodes_to_add_last = collections.deque() # first pass: add nodes whose parent are in the tree for process, stats in process_dict.items(): - new_node = ProcessTreeNode(process, stats, sort_key) + new_node = ProcessTreeNode(process, stats, sort_key, sort_reverse) try: parent_process = process.parent() except psutil.NoSuchProcess: @@ -192,13 +207,16 @@ class ProcessTreeNode(object): # parent is not in tree, add this node later nodes_to_add_last.append(new_node) - # next pass(es): add nodes to their parents if it could not be done in previous pass + # next pass(es): add nodes to their parents if it could not be done in + # previous pass while nodes_to_add_last: - node_to_add = nodes_to_add_last.popleft() # pop from left and append to right to avoid infinite loop + # pop from left and append to right to avoid infinite loop + node_to_add = nodes_to_add_last.popleft() try: parent_process = node_to_add.process.parent() except psutil.NoSuchProcess: - # parent is dead, consider no parent, add this node at the top level + # parent is dead, consider no parent, add this node at the top + # level tree_root.children.append(node_to_add) else: if parent_process is None: @@ -242,10 +260,11 @@ class GlancesProcesses(object): self.process_tree = None # Init stats - self.resetsort() + self.auto_sort = True + self._sort_key = 'cpu_percent' + self.allprocesslist = [] self.processlist = [] - self.processcount = { - 'total': 0, 'running': 0, 'sleeping': 0, 'thread': 0} + self.processcount = {'total': 0, 'running': 0, 'sleeping': 0, 'thread': 0} # Tag to enable/disable the processes stats (to reduce the Glances CPU consumption) # Default is to enable the processes stats @@ -254,13 +273,12 @@ class GlancesProcesses(object): # Extended stats for top process is enable by default self.disable_extended_tag = False - # Maximum number of processes showed in the UI interface - # None if no limit - self.max_processes = None + # Maximum number of processes showed in the UI (None if no limit) + self._max_processes = None # Process filter is a regular expression - self.process_filter = None - self.process_filter_re = None + self._process_filter = None + self._process_filter_re = None # Whether or not to hide kernel threads self.no_kernel_threads = False @@ -283,255 +301,279 @@ class GlancesProcesses(object): """Disable extended process stats.""" self.disable_extended_tag = True - def set_max_processes(self, value): - """Set the maximum number of processes showed in the UI interfaces""" - self.max_processes = value - return self.max_processes + @property + def max_processes(self): + """Get the maximum number of processes showed in the UI.""" + return self._max_processes + + @max_processes.setter + def max_processes(self, value): + """Set the maximum number of processes showed in the UI.""" + self._max_processes = value - def get_max_processes(self): - """Get the maximum number of processes showed in the UI interfaces""" - return self.max_processes + @property + def process_filter(self): + """Get the process filter.""" + return self._process_filter - def set_process_filter(self, value): - """Set the process filter""" + @process_filter.setter + def process_filter(self, value): + """Set the process filter.""" logger.info("Set process filter to {0}".format(value)) - self.process_filter = value + self._process_filter = value if value is not None: try: - self.process_filter_re = re.compile(value) - logger.debug("Process filter regex compilation OK: {0}".format(self.get_process_filter())) + self._process_filter_re = re.compile(value) + logger.debug("Process filter regex compilation OK: {0}".format(self.process_filter)) except Exception: logger.error("Cannot compile process filter regex: {0}".format(value)) - self.process_filter_re = None + self._process_filter_re = None else: - self.process_filter_re = None - return self.process_filter + self._process_filter_re = None - def get_process_filter(self): - """Get the process filter""" - return self.process_filter - - def get_process_filter_re(self): - """Get the process regular expression compiled""" - return self.process_filter_re + @property + def process_filter_re(self): + """Get the process regular expression compiled.""" + return self._process_filter_re def is_filtered(self, value): - """Return True if the value should be filtered""" - if self.get_process_filter() is None: + """Return True if the value should be filtered.""" + if self.process_filter is None: # No filter => Not filtered return False else: - # logger.debug(self.get_process_filter() + " <> " + value + " => " + str(self.get_process_filter_re().match(value) is None)) - return self.get_process_filter_re().match(value) is None + # logger.debug(self.process_filter + " <> " + value + " => " + str(self.process_filter_re.match(value) is None)) + return self.process_filter_re.match(value) is None def disable_kernel_threads(self): - """ Ignore kernel threads in process list. """ + """Ignore kernel threads in process list.""" self.no_kernel_threads = True def enable_tree(self): - """ Enable process tree. """ + """Enable process tree.""" self._enable_tree = True def is_tree_enabled(self): - """ Return True if process tree is enabled, False instead. """ + """Return True if process tree is enabled, False instead.""" return self._enable_tree - def __get_process_stats(self, proc, - mandatory_stats=True, - standard_stats=True, - extended_stats=False): + @property + def sort_reverse(self): + """Return True to sort processes in reverse 'key' order, False instead.""" + if self.sort_key == 'name' or self.sort_key == 'username': + return False + + return True + + def __get_mandatory_stats(self, proc, procstat): """ - Get process stats of the proc processes (proc is returned psutil.process_iter()) - mandatory_stats: need for the sorting/filter step + Get mandatory_stats: need for the sorting/filter step. + => cpu_percent, memory_percent, io_counters, name, cmdline - standard_stats: for all the displayed processes - => username, status, memory_info, cpu_times - extended_stats: only for top processes (see issue #403) - => connections (UDP/TCP), memory_swap... """ + procstat['mandatory_stats'] = True + + # Process CPU, MEM percent and name + procstat.update(proc.as_dict( + attrs=['username', 'cpu_percent', 'memory_percent', + 'name', 'cpu_times'], ad_value='')) + if procstat['cpu_percent'] == '' or procstat['memory_percent'] == '': + # Do not display process if we cannot get the basic + # cpu_percent or memory_percent stats + return None + + # Process command line (cached with internal cache) + try: + self.cmdline_cache[procstat['pid']] + except KeyError: + # Patch for issue #391 + try: + self.cmdline_cache[ + procstat['pid']] = ' '.join(proc.cmdline()) + except (AttributeError, UnicodeDecodeError, psutil.AccessDenied, psutil.NoSuchProcess): + self.cmdline_cache[procstat['pid']] = "" + procstat['cmdline'] = self.cmdline_cache[procstat['pid']] + + # Process IO + # procstat['io_counters'] is a list: + # [read_bytes, write_bytes, read_bytes_old, write_bytes_old, io_tag] + # If io_tag = 0 > Access denied (display "?") + # If io_tag = 1 > No access denied (display the IO rate) + # Note Disk IO stat not available on Mac OS + if not is_mac: + try: + # Get the process IO counters + proc_io = proc.io_counters() + io_new = [proc_io.read_bytes, proc_io.write_bytes] + except (psutil.AccessDenied, psutil.NoSuchProcess, NotImplementedError): + # Access denied to process IO (no root account) + # NoSuchProcess (process die between first and second grab) + # Put 0 in all values (for sort) and io_tag = 0 (for + # display) + procstat['io_counters'] = [0, 0] + [0, 0] + io_tag = 0 + else: + # For IO rate computation + # Append saved IO r/w bytes + try: + procstat['io_counters'] = io_new + \ + self.io_old[procstat['pid']] + except KeyError: + procstat['io_counters'] = io_new + [0, 0] + # then save the IO r/w bytes + self.io_old[procstat['pid']] = io_new + io_tag = 1 - # Process ID (always) - procstat = proc.as_dict(attrs=['pid']) + # Append the IO tag (for display) + procstat['io_counters'] += [io_tag] - if mandatory_stats: - procstat['mandatory_stats'] = True + return procstat - # Process CPU, MEM percent and name + def __get_standard_stats(self, proc, procstat): + """ + Get standard_stats: for all the displayed processes. + + => username, status, memory_info, cpu_times + """ + procstat['standard_stats'] = True + + # Process username (cached with internal cache) + try: + self.username_cache[procstat['pid']] + except KeyError: try: - procstat.update( - proc.as_dict(attrs=['cpu_percent', 'memory_percent', 'name', 'cpu_times'], ad_value='')) + self.username_cache[procstat['pid']] = proc.username() except psutil.NoSuchProcess: - # Correct issue #414 - return None - if procstat['cpu_percent'] == '' or procstat['memory_percent'] == '': - # Do not display process if we cannot get the basic - # cpu_percent or memory_percent stats - return None - - # Process command line (cached with internal cache) - try: - self.cmdline_cache[procstat['pid']] - except KeyError: - # Patch for issue #391 - try: - self.cmdline_cache[ - procstat['pid']] = ' '.join(proc.cmdline()) - except (AttributeError, UnicodeDecodeError, psutil.AccessDenied, psutil.NoSuchProcess): - self.cmdline_cache[procstat['pid']] = "" - procstat['cmdline'] = self.cmdline_cache[procstat['pid']] - - # Process IO - # procstat['io_counters'] is a list: - # [read_bytes, write_bytes, read_bytes_old, write_bytes_old, io_tag] - # If io_tag = 0 > Access denied (display "?") - # If io_tag = 1 > No access denied (display the IO rate) - # Note Disk IO stat not available on Mac OS - if not is_mac: - try: - # Get the process IO counters - proc_io = proc.io_counters() - io_new = [proc_io.read_bytes, proc_io.write_bytes] - except (psutil.AccessDenied, psutil.NoSuchProcess): - # Access denied to process IO (no root account) - # NoSuchProcess (process die between first and second grab) - # Put 0 in all values (for sort) and io_tag = 0 (for - # display) - procstat['io_counters'] = [0, 0] + [0, 0] - io_tag = 0 - else: - # For IO rate computation - # Append saved IO r/w bytes - try: - procstat['io_counters'] = io_new + \ - self.io_old[procstat['pid']] - except KeyError: - procstat['io_counters'] = io_new + [0, 0] - # then save the IO r/w bytes - self.io_old[procstat['pid']] = io_new - io_tag = 1 - - # Append the IO tag (for display) - procstat['io_counters'] += [io_tag] - - if standard_stats: - procstat['standard_stats'] = True - - # Process username (cached with internal cache) - try: - self.username_cache[procstat['pid']] - except KeyError: + self.username_cache[procstat['pid']] = "?" + except (KeyError, psutil.AccessDenied): try: - self.username_cache[procstat['pid']] = proc.username() - except psutil.NoSuchProcess: + self.username_cache[procstat['pid']] = proc.uids().real + except (KeyError, AttributeError, psutil.AccessDenied): self.username_cache[procstat['pid']] = "?" - except (KeyError, psutil.AccessDenied): - try: - self.username_cache[procstat['pid']] = proc.uids().real - except (KeyError, AttributeError, psutil.AccessDenied): - self.username_cache[procstat['pid']] = "?" - procstat['username'] = self.username_cache[procstat['pid']] - - # Process status, nice, memory_info and cpu_times - try: - procstat.update( - proc.as_dict(attrs=['status', 'nice', 'memory_info', 'cpu_times'])) - except psutil.NoSuchProcess: - pass - else: - procstat['status'] = str(procstat['status'])[:1].upper() + procstat['username'] = self.username_cache[procstat['pid']] + + # Process status, nice, memory_info and cpu_times + try: + procstat.update( + proc.as_dict(attrs=['status', 'nice', 'memory_info', 'cpu_times'])) + except psutil.NoSuchProcess: + pass + else: + procstat['status'] = str(procstat['status'])[:1].upper() - if extended_stats and not self.disable_extended_tag: - procstat['extended_stats'] = True + return procstat - # CPU affinity (Windows and Linux only) - try: - procstat.update(proc.as_dict(attrs=['cpu_affinity'])) - except psutil.NoSuchProcess: - pass - except AttributeError: - procstat['cpu_affinity'] = None - # Memory extended - try: - procstat.update(proc.as_dict(attrs=['memory_info_ex'])) - except psutil.NoSuchProcess: - pass - except AttributeError: - procstat['memory_info_ex'] = None - # Number of context switch + def __get_extended_stats(self, proc, procstat): + """ + Get extended_stats: only for top processes (see issue #403). + + => connections (UDP/TCP), memory_swap... + """ + procstat['extended_stats'] = True + + # CPU affinity (Windows and Linux only) + try: + procstat.update(proc.as_dict(attrs=['cpu_affinity'])) + except psutil.NoSuchProcess: + pass + except AttributeError: + procstat['cpu_affinity'] = None + # Memory extended + try: + procstat.update(proc.as_dict(attrs=['memory_info_ex'])) + except psutil.NoSuchProcess: + pass + except AttributeError: + procstat['memory_info_ex'] = None + # Number of context switch + try: + procstat.update(proc.as_dict(attrs=['num_ctx_switches'])) + except psutil.NoSuchProcess: + pass + except AttributeError: + procstat['num_ctx_switches'] = None + # Number of file descriptors (Unix only) + try: + procstat.update(proc.as_dict(attrs=['num_fds'])) + except psutil.NoSuchProcess: + pass + except AttributeError: + procstat['num_fds'] = None + # Threads number + try: + procstat.update(proc.as_dict(attrs=['num_threads'])) + except psutil.NoSuchProcess: + pass + except AttributeError: + procstat['num_threads'] = None + + # Number of handles (Windows only) + if is_windows: try: - procstat.update(proc.as_dict(attrs=['num_ctx_switches'])) + procstat.update(proc.as_dict(attrs=['num_handles'])) except psutil.NoSuchProcess: pass - except AttributeError: - procstat['num_ctx_switches'] = None - # Number of file descriptors (Unix only) + else: + procstat['num_handles'] = None + + # SWAP memory (Only on Linux based OS) + # http://www.cyberciti.biz/faq/linux-which-process-is-using-swap/ + if is_linux: try: - procstat.update(proc.as_dict(attrs=['num_fds'])) + procstat['memory_swap'] = sum( + [v.swap for v in proc.memory_maps()]) except psutil.NoSuchProcess: pass - except AttributeError: - procstat['num_fds'] = None - # Threads number + except psutil.AccessDenied: + procstat['memory_swap'] = None + except Exception: + # Add a dirty except to handle the PsUtil issue #413 + procstat['memory_swap'] = None + + # Process network connections (TCP and UDP) + try: + procstat['tcp'] = len(proc.connections(kind="tcp")) + procstat['udp'] = len(proc.connections(kind="udp")) + except Exception: + procstat['tcp'] = None + procstat['udp'] = None + + # IO Nice + # http://pythonhosted.org/psutil/#psutil.Process.ionice + if is_linux or is_windows: try: - procstat.update(proc.as_dict(attrs=['num_threads'])) + procstat.update(proc.as_dict(attrs=['ionice'])) except psutil.NoSuchProcess: pass - except AttributeError: - procstat['num_threads'] = None + else: + procstat['ionice'] = None - # Number of handles (Windows only) - if is_windows: - try: - procstat.update(proc.as_dict(attrs=['num_handles'])) - except psutil.NoSuchProcess: - pass - else: - procstat['num_handles'] = None + return procstat - # SWAP memory (Only on Linux based OS) - # http://www.cyberciti.biz/faq/linux-which-process-is-using-swap/ - if is_linux: - try: - procstat['memory_swap'] = sum( - [v.swap for v in proc.memory_maps()]) - except psutil.NoSuchProcess: - pass - except psutil.AccessDenied: - procstat['memory_swap'] = None - except Exception: - # Add a dirty except to handle the PsUtil issue #413 - procstat['memory_swap'] = None + def __get_process_stats(self, proc, + mandatory_stats=True, + standard_stats=True, + extended_stats=False): + """Get stats of running processes.""" + # Process ID (always) + procstat = proc.as_dict(attrs=['pid']) - # Process network connections (TCP and UDP) - try: - procstat['tcp'] = len(proc.connections(kind="tcp")) - procstat['udp'] = len(proc.connections(kind="udp")) - except Exception: - procstat['tcp'] = None - procstat['udp'] = None + if mandatory_stats: + procstat = self.__get_mandatory_stats(proc, procstat) - # IO Nice - # http://pythonhosted.org/psutil/#psutil.Process.ionice - if is_linux or is_windows: - try: - procstat.update(proc.as_dict(attrs=['ionice'])) - except psutil.NoSuchProcess: - pass - else: - procstat['ionice'] = None + if procstat is not None and standard_stats: + procstat = self.__get_standard_stats(proc, procstat) - # logger.debug(procstat) + if procstat is not None and extended_stats and not self.disable_extended_tag: + procstat = self.__get_extended_stats(proc, procstat) return procstat def update(self): - """ - Update the processes stats - """ + """Update the processes stats.""" # Reset the stats self.processlist = [] - self.processcount = { - 'total': 0, 'running': 0, 'sleeping': 0, 'thread': 0} + self.processcount = {'total': 0, 'running': 0, 'sleeping': 0, 'thread': 0} # Do not process if disable tag is set if self.disable_tag: @@ -544,15 +586,14 @@ class GlancesProcesses(object): processdict = {} for proc in psutil.process_iter(): # Ignore kernel threads if needed - if (self.no_kernel_threads and (not is_windows) - and is_kernel_thread(proc)): + if self.no_kernel_threads and not is_windows and is_kernel_thread(proc): continue - # If self.get_max_processes() is None: Only retreive mandatory stats + # If self.max_processes is None: Only retreive mandatory stats # Else: retreive mandatory and standard stats s = self.__get_process_stats(proc, mandatory_stats=True, - standard_stats=self.get_max_processes() is None) + standard_stats=self.max_processes is None) # Continue to the next process if it has to be filtered if s is None or (self.is_filtered(s['cmdline']) and self.is_filtered(s['name'])): continue @@ -586,12 +627,13 @@ class GlancesProcesses(object): if self._enable_tree: self.process_tree = ProcessTreeNode.build_tree(processdict, - self.getsortkey(), + self.sort_key, + self.sort_reverse, self.no_kernel_threads) for i, node in enumerate(self.process_tree): - # Only retreive stats for visible processes (get_max_processes) - if (self.get_max_processes() is not None) and (i >= self.get_max_processes()): + # Only retreive stats for visible processes (max_processes) + if self.max_processes is not None and i >= self.max_processes: break # add standard stats @@ -607,30 +649,32 @@ class GlancesProcesses(object): else: # Process optimization - # Only retreive stats for visible processes (get_max_processes) - if self.get_max_processes() is not None: + # Only retreive stats for visible processes (max_processes) + if self.max_processes is not None: # Sort the internal dict and cut the top N (Return a list of tuple) # tuple=key (proc), dict (returned by __get_process_stats) try: - processiter = sorted( - processdict.items(), key=lambda x: x[1][self.getsortkey()], reverse=True) + processiter = sorted(processdict.items(), + key=lambda x: x[1][self.sort_key], + reverse=self.sort_reverse) except (KeyError, TypeError) as e: - logger.error("Cannot sort process list by %s (%s)" % (self.getsortkey(), e)) + logger.error("Cannot sort process list by {0}: {1}".format(self.sort_key, e)) logger.error("%s" % str(processdict.items()[0])) # Fallback to all process (issue #423) processloop = processdict.items() first = False else: - processloop = processiter[0:self.get_max_processes()] + processloop = processiter[0:self.max_processes] first = True else: # Get all processes stats processloop = processdict.items() first = False + for i in processloop: # Already existing mandatory stats procstat = i[1] - if self.get_max_processes() is not None: + if self.max_processes is not None: # Update with standard stats # and extended stats but only for TOP (first) process s = self.__get_process_stats(i[0], @@ -647,6 +691,9 @@ class GlancesProcesses(object): # Next... first = False + # Build the all processes list used by the monitored list + self.allprocesslist = processdict.values() + # Clean internals caches if timeout is reached if self.cache_timer.finished(): self.username_cache = {} @@ -658,6 +705,10 @@ class GlancesProcesses(object): """Get the number of processes.""" return self.processcount + def getalllist(self): + """Get the allprocesslist.""" + return self.allprocesslist + def getlist(self, sortedby=None): """Get the processlist.""" return self.processlist @@ -666,65 +717,14 @@ class GlancesProcesses(object): """Get the process tree.""" return self.process_tree - def getsortkey(self): - """Get the current sort key""" - if self.getmanualsortkey() is not None: - return self.getmanualsortkey() - else: - return self.getautosortkey() - - def getmanualsortkey(self): - """Get the current sort key for manual sort.""" - return self.processmanualsort - - def getautosortkey(self): - """Get the current sort key for automatic sort.""" - return self.processautosort - - def setmanualsortkey(self, sortedby): - """Set the current sort key for manual sort.""" - self.processmanualsort = sortedby - if self._enable_tree and (self.process_tree is not None): - self.process_tree.set_sorting(sortedby, sortedby != "name") - return self.processmanualsort - - def setautosortkey(self, sortedby): - """Set the current sort key for automatic sort.""" - self.processautosort = sortedby - return self.processautosort - - def resetsort(self): - """Set the default sort: Auto""" - self.setmanualsortkey(None) - self.setautosortkey('cpu_percent') - - def getsortlist(self, sortedby=None): - """Get the sorted processlist.""" - if sortedby is None: - # No need to sort... - return self.processlist - - sortedreverse = True - if sortedby == 'name': - sortedreverse = False - - if sortedby == 'io_counters': - # Specific case for io_counters - # Sum of io_r + io_w - try: - # Sort process by IO rate (sum IO read + IO write) - self.processlist.sort(key=lambda process: process[sortedby][0] - - process[sortedby][2] + process[sortedby][1] - - process[sortedby][3], - reverse=sortedreverse) - except Exception: - self.processlist.sort(key=operator.itemgetter('cpu_percent'), - |