def update(self): """Update the command result attributed.""" # Search application monitored processes by a regular expression processlist = gl_processes.getalllist() # Iter upon the AMPs dict for k, v in iteritems(self.get()): try: amps_list = [p for p in processlist for c in p['cmdline'] if re.search(v.regex(), c) is not None] except TypeError: continue if len(amps_list) > 0: # At least one process is matching the regex logger.debug("AMPS: {} process detected (PID={})".format(k, amps_list[0]['pid'])) # Call the AMP update method thread = threading.Thread(target=v.update_wrapper, args=[amps_list]) thread.start() else: # Set the process number to 0 v.set_count(0) if v.count_min() is not None and v.count_min() > 0: # Only display the "No running process message" is countmin is defined v.set_result("No running process") return self.__amps_dict
def build_tree(process_dict, sort_key, sort_reverse, hide_kernel_threads, excluded_processes): """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 iteritems(process_dict): new_node = ProcessTreeNode(process, stats, sort_key, sort_reverse) try: parent_process = process.parent() except psutil.NoSuchProcess: # parent is dead, consider no parent parent_process = None if (parent_process is None) or (parent_process in excluded_processes): # no parent, or excluded parent, add this node at the top level tree_root.children.append(new_node) else: parent_node = tree_root.find_process(parent_process) if parent_node is not None: # parent is already in the tree, add a new child parent_node.children.append(new_node) else: # 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 while nodes_to_add_last: # 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 tree_root.children.append(node_to_add) else: if (parent_process is None) or (parent_process in excluded_processes): # no parent, or excluded parent, add this node at the top level tree_root.children.append(node_to_add) else: parent_node = tree_root.find_process(parent_process) if parent_node is not None: # parent is already in the tree, add a new child parent_node.children.append(node_to_add) else: # parent is not in tree, add this node later nodes_to_add_last.append(node_to_add) return tree_root
def update(self): """Update the AMP list.""" # Reset stats self.reset() if self.input_method == 'local': for k, v in iteritems(self.glances_amps.update()): # self.stats.append({k: v.result()}) self.stats.append({ 'key': k, 'name': v.NAME, 'result': v.result(), 'refresh': v.refresh(), 'timer': v.time_until_refresh(), 'count': v.count(), 'countmin': v.count_min(), 'countmax': v.count_max(), }) else: # Not available in SNMP mode pass return self.stats
def __build_export(self, stats): """Build the export lists.""" export_names = [] export_values = [] if isinstance(stats, dict): # Stats is a dict # Is there a key ? if 'key' in iterkeys(stats): pre_key = '{}.'.format(stats[stats['key']]) else: pre_key = '' # Walk through the dict for key, value in iteritems(stats): if isinstance(value, list): try: value = value[0] except IndexError: value = '' if isinstance(value, dict): item_names, item_values = self.__build_export(value) item_names = [ pre_key + key.lower() + str(i) for i in item_names ] export_names += item_names export_values += item_values else: export_names.append(pre_key + key.lower()) export_values.append(value) elif isinstance(stats, list): # Stats is a list (of dict) # Recursive loop through the list for item in stats: item_names, item_values = self.__build_export(item) export_names += item_names export_values += item_values return export_names, export_values
def update(self): """Update the processes stats.""" # Reset the stats self.processlist = [] self.processcount = {'total': 0, 'running': 0, 'sleeping': 0, 'thread': 0} # Do not process if disable tag is set if self.disable_tag: return # Get the time since last update time_since_update = getTimeSinceLastUpdate('process_disk') # Build an internal dict with only mandatories stats (sort keys) processdict = {} excluded_processes = set() for proc in psutil.process_iter(): # Ignore kernel threads if needed if self.no_kernel_threads and is_kernel_thread(proc): continue # If self.max_processes is None: Only retrieve mandatory stats # Else: retrieve mandatory and standard stats s = self.__get_process_stats(proc, mandatory_stats=True, standard_stats=self.max_processes is None) # Check if s is note None (issue #879) # waiting for upstream patch from psutil if s is None: continue # Continue to the next process if it has to be filtered if self._filter.is_filtered(s): excluded_processes.add(proc) continue # Ok add the process to the list processdict[proc] = s # Update processcount (global statistics) try: self.processcount[str(proc.status())] += 1 except KeyError: # Key did not exist, create it try: self.processcount[str(proc.status())] = 1 except psutil.NoSuchProcess: pass except psutil.NoSuchProcess: pass else: self.processcount['total'] += 1 # Update thread number (global statistics) try: self.processcount['thread'] += proc.num_threads() except Exception: pass if self._enable_tree: self.process_tree = ProcessTreeNode.build_tree(processdict, self.sort_key, self.sort_reverse, self.no_kernel_threads, excluded_processes) for i, node in enumerate(self.process_tree): # Only retreive stats for visible processes (max_processes) if self.max_processes is not None and i >= self.max_processes: break # add standard stats new_stats = self.__get_process_stats(node.process, mandatory_stats=False, standard_stats=True, extended_stats=False) if new_stats is not None: node.stats.update(new_stats) # Add a specific time_since_update stats for bitrate node.stats['time_since_update'] = time_since_update else: # Process optimization # 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(iteritems(processdict), key=lambda x: x[1][self.sort_key], reverse=self.sort_reverse) except (KeyError, TypeError) as e: logger.error("Cannot sort process list by {}: {}".format(self.sort_key, e)) logger.error('{}'.format(listitems(processdict)[0])) # Fallback to all process (issue #423) processloop = iteritems(processdict) first = False else: processloop = processiter[0:self.max_processes] first = True else: # Get all processes stats processloop = iteritems(processdict) first = False for i in processloop: # Already existing mandatory stats procstat = i[1] 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], mandatory_stats=False, standard_stats=True, extended_stats=first) if s is None: continue procstat.update(s) # Add a specific time_since_update stats for bitrate procstat['time_since_update'] = time_since_update # Update process list self.processlist.append(procstat) # Next... first = False # Build the all processes list used by the AMPs self.allprocesslist = [p for p in itervalues(processdict)] # Clean internals caches if timeout is reached if self.cache_timer.finished(): self.username_cache = {} self.cmdline_cache = {} # Restart the timer self.cache_timer.reset()
def get_process_curses_data(self, p, first, args): """Get curses data to display for a process.""" ret = [self.curse_new_line()] # CPU if 'cpu_percent' in p and p[ 'cpu_percent'] is not None and p['cpu_percent'] != '': if args.disable_irix and self.nb_log_core != 0: msg = '{:>6.1f}'.format(p['cpu_percent'] / float(self.nb_log_core)) else: msg = '{:>6.1f}'.format(p['cpu_percent']) ret.append( self.curse_add_line( msg, self.get_alert(p['cpu_percent'], header="cpu"))) else: msg = '{:>6}'.format('?') ret.append(self.curse_add_line(msg)) # MEM if 'memory_percent' in p and p[ 'memory_percent'] is not None and p['memory_percent'] != '': msg = '{:>6.1f}'.format(p['memory_percent']) ret.append( self.curse_add_line( msg, self.get_alert(p['memory_percent'], header="mem"))) else: msg = '{:>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 = '{:>6}'.format( self.auto_unit(p['memory_info'][1], low_precision=False)) ret.append(self.curse_add_line(msg, optional=True)) # RSS msg = '{:>6}'.format( self.auto_unit(p['memory_info'][0], low_precision=False)) ret.append(self.curse_add_line(msg, optional=True)) else: msg = '{:>6}'.format('?') ret.append(self.curse_add_line(msg)) ret.append(self.curse_add_line(msg)) # PID msg = '{:>6}'.format(p['pid']) ret.append(self.curse_add_line(msg)) # USER if 'username' in p: # docker internal users are displayed as ints only, therefore str() # Correct issue #886 on Windows OS msg = ' {:9}'.format(str(p['username'])[:9]) ret.append(self.curse_add_line(msg)) else: msg = ' {:9}'.format('?') ret.append(self.curse_add_line(msg)) # NICE if 'nice' in p: nice = p['nice'] if nice is None: nice = '?' msg = '{:>5}'.format(nice) if isinstance(nice, int) and (nice != 0): ret.append(self.curse_add_line(msg, decoration='NICE')) else: ret.append(self.curse_add_line(msg)) else: msg = '{:>5}'.format('?') ret.append(self.curse_add_line(msg)) # STATUS if 'status' in p: status = p['status'] msg = '{:>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 = '{:>2}'.format('?') ret.append(self.curse_add_line(msg)) # TIME+ if self.tag_proc_time: try: delta = timedelta(seconds=sum(p['cpu_times'])) except (OverflowError, TypeError) as e: # Catch OverflowError on some Amazon EC2 server # See https://github.com/nicolargo/glances/issues/87 # Also catch TypeError on Mac OS X # See: https://github.com/nicolargo/glances/issues/622 logger.debug("Cannot get TIME+ ({})".format(e)) self.tag_proc_time = False else: hours, minutes, seconds, microseconds = convert_timedelta( delta) if hours: msg = '{:>4}h'.format(hours) ret.append( self.curse_add_line(msg, decoration='CPU_TIME', optional=True)) msg = '{}:{}'.format(str(minutes).zfill(2), seconds) else: msg = '{:>4}:{}.{}'.format(minutes, seconds, microseconds) else: msg = '{:>10}'.format('?') ret.append(self.curse_add_line(msg, optional=True)) # IO read/write if 'io_counters' in p: # IO read io_rs = int((p['io_counters'][0] - p['io_counters'][2]) / p['time_since_update']) if io_rs == 0: msg = '{:>6}'.format("0") else: msg = '{:>6}'.format(self.auto_unit(io_rs, low_precision=True)) ret.append(self.curse_add_line(msg, optional=True, additional=True)) # IO write io_ws = int((p['io_counters'][1] - p['io_counters'][3]) / p['time_since_update']) if io_ws == 0: msg = '{:>6}'.format("0") else: msg = '{:>6}'.format(self.auto_unit(io_ws, low_precision=True)) ret.append(self.curse_add_line(msg, optional=True, additional=True)) else: msg = '{:>6}'.format("?") 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'] try: # XXX: remove `cmdline != ['']` when we'll drop support for psutil<4.0.0 if cmdline and cmdline != ['']: path, cmd, arguments = split_cmdline(cmdline) if os.path.isdir(path) and not args.process_short_name: msg = ' {}'.format(path) + os.sep ret.append(self.curse_add_line(msg, splittable=True)) if gl_processes.is_tree_enabled(): # mark position to add tree decoration ret[-1]["_tree_decoration"] = True ret.append( self.curse_add_line(cmd, decoration='PROCESS', splittable=True)) else: msg = ' {}'.format(cmd) ret.append( self.curse_add_line(msg, decoration='PROCESS', splittable=True)) if gl_processes.is_tree_enabled(): # mark position to add tree decoration ret[-1]["_tree_decoration"] = True if arguments: msg = ' {}'.format(arguments) ret.append(self.curse_add_line(msg, splittable=True)) else: msg = ' {}'.format(p['name']) 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' in p and p['memory_info'] is not None: ret.append(self.curse_new_line()) msg = xpad + 'Memory info: ' for k, v in iteritems(p['memory_info']._asdict()): # 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 open files/network sessions msg = '' 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']) + ' ' if msg != '': ret.append(self.curse_new_line()) msg = xpad + 'Open: ' + msg 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. 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)) return ret