mirror of
https://github.com/nicolargo/glances.git
synced 2024-11-24 05:15:47 +03:00
Filter processes by others stats (username) #748
This commit is contained in:
parent
d0783a21e1
commit
d1f9d30aae
1
NEWS
1
NEWS
@ -10,6 +10,7 @@ Enhancements and new features:
|
||||
* Add Application Monitoring Process plugin (issue #780)
|
||||
* Improve IP plugin to display public IP address (issue #646)
|
||||
* CPU additionnal stats monitoring: Context switch, Interrupts... (issue #810)
|
||||
* Filter processes by others stats (username) (issue #748)
|
||||
* [Folders] Differentiate permission issue and non-existence of a directory (issue #828)
|
||||
* [Web UI] Add cpu name in quicklook plugin (issue #825)
|
||||
* Allow theme to be set in configuration file (issue #862)
|
||||
|
BIN
docs/_static/processlist-filter.png
vendored
BIN
docs/_static/processlist-filter.png
vendored
Binary file not shown.
Before Width: | Height: | Size: 83 KiB After Width: | Height: | Size: 157 KiB |
@ -79,6 +79,18 @@ Columns display
|
||||
pressing on the ``'/'`` key
|
||||
========================= ==============================================
|
||||
|
||||
Process filtering
|
||||
-----------------
|
||||
|
||||
It's possible to filter the processes list using the ``ENTER`` key.
|
||||
|
||||
Filter syntax is the following (examples):
|
||||
|
||||
- python > Filter processes name or command line starting with *python* (regexp)
|
||||
- .*python.* > Filter processes name or command line containing *python* (regexp)
|
||||
- username:nicolargo > Processes of nicolargo user (key:regexp)
|
||||
- cmdline:\/usr\/bin.* > Processes starting by */usr/bin*
|
||||
|
||||
Extended info
|
||||
-------------
|
||||
|
||||
|
@ -30,49 +30,116 @@ class GlancesFilter(object):
|
||||
>>> f.filter = '.*python.*'
|
||||
>>> f.filter
|
||||
'.*python.*'
|
||||
>>> f.key
|
||||
None
|
||||
>>> f.filter = 'user:nicolargo'
|
||||
>>> f.filter
|
||||
'nicolargo'
|
||||
>>> f.key
|
||||
'user'
|
||||
>>> f.filter = 'username:.*nico.*'
|
||||
>>> f.filter
|
||||
'.*nico.*'
|
||||
>>> f.key
|
||||
'username'
|
||||
"""
|
||||
|
||||
def __init__(self):
|
||||
# Filter entered by the user (string)
|
||||
self._filter_input = None
|
||||
# Filter to apply
|
||||
self._filter = None
|
||||
# Filter regular expression
|
||||
self._filter_re = None
|
||||
# Dict key where the filter should be applied
|
||||
# Default is None: search on command line and process name
|
||||
self._filter_key = None
|
||||
|
||||
@property
|
||||
def filter_input(self):
|
||||
"""Return the filter given by the user (as a sting)"""
|
||||
return self._filter_input
|
||||
|
||||
@property
|
||||
def filter(self):
|
||||
"""Return the filter (as a sting)"""
|
||||
"""Return the current filter to be applied"""
|
||||
return self._filter
|
||||
|
||||
@filter.setter
|
||||
def filter(self, value):
|
||||
"""Set the filter (as a sting) and compute the regular expression"""
|
||||
self._filter = value
|
||||
self._filter_re = None
|
||||
"""Set the filter (as a sting) and compute the regular expression
|
||||
A filter could be one of the following:
|
||||
- python > Process name of cmd start with python
|
||||
- .*python.* > Process name of cmd contain python
|
||||
- username:nicolargo > Process of nicolargo user
|
||||
"""
|
||||
self._filter_input = value
|
||||
if value is None:
|
||||
self._filter = None
|
||||
self._filter_key = None
|
||||
else:
|
||||
new_filter = value.split(':')
|
||||
if len(new_filter) == 1:
|
||||
self._filter = new_filter[0]
|
||||
self._filter_key = None
|
||||
else:
|
||||
self._filter = new_filter[1]
|
||||
self._filter_key = new_filter[0]
|
||||
|
||||
self._filter_re = None
|
||||
if self.filter is not None:
|
||||
logger.info("Set filter to {0}".format(self.filter))
|
||||
logger.info("Set filter to {0} on key {1}".format(self.filter, self.filter_key))
|
||||
# Compute the regular expression
|
||||
try:
|
||||
self._filter_re = re.compile(self.filter)
|
||||
logger.debug("Filter regex compilation OK: {0}".format(self.filter))
|
||||
except Exception as e:
|
||||
logger.error("Cannot compile filter regex: {0} ({1})".format(self.filter, e))
|
||||
self._filter = None
|
||||
self._filter_re = None
|
||||
self._filter_key = None
|
||||
|
||||
@property
|
||||
def filter_re(self):
|
||||
"""Return the filter regular expression"""
|
||||
return self._filter_re
|
||||
|
||||
def is_filtered(self, process, key='cmdline'):
|
||||
@property
|
||||
def filter_key(self):
|
||||
"""key where the filter should be applied"""
|
||||
return self._filter_key
|
||||
|
||||
def is_filtered(self, process):
|
||||
"""Return True if the process item match the current filter
|
||||
The proces item is a dict.
|
||||
The filter will be applyed on the process[key] (command line by default)
|
||||
"""
|
||||
if self.filter is None:
|
||||
# No filter => Not filtered
|
||||
return False
|
||||
|
||||
if self.filter_key is None:
|
||||
# Apply filter on command line and process name
|
||||
return self._is_process_filtered(process, key='cmdline') and self._is_process_filtered(process, key='name')
|
||||
else:
|
||||
# Apply filter on <key>
|
||||
return self._is_process_filtered(process)
|
||||
|
||||
def _is_process_filtered(self, process, key=None):
|
||||
"""Return True if the process[key] should be filtered according to the current filter"""
|
||||
if key is None:
|
||||
key = self.filter_key
|
||||
try:
|
||||
return self._filter_re.match(' '.join(process[key])) is None
|
||||
# If the item process[key] is a list, convert it to a string
|
||||
# in order to match it with the current regular expression
|
||||
if isinstance(process[key], list):
|
||||
value = ' '.join(process[key])
|
||||
else:
|
||||
value = process[key]
|
||||
except KeyError:
|
||||
# If the key did not exist
|
||||
return False
|
||||
try:
|
||||
return self._filter_re.match(value) is None
|
||||
except AttributeError:
|
||||
# Filter processes crashs with a bad regular expression pattern (issue #665)
|
||||
return False
|
||||
|
@ -781,8 +781,18 @@ class _GlancesCurses(object):
|
||||
# Only in standalone mode (cs_status is None)
|
||||
if self.edit_filter and cs_status is None:
|
||||
new_filter = self.display_popup(
|
||||
'Process filter pattern: ', is_input=True,
|
||||
input_value=glances_processes.process_filter)
|
||||
'Process filter pattern: \n' +
|
||||
'\n' +
|
||||
'Examples:\n' +
|
||||
'- python\n' +
|
||||
'- .*python.*\n' +
|
||||
'- \/usr\/lib.*' +
|
||||
'- name:.*nautilus.*\n' +
|
||||
'- cmdline:.*glances.*\n' +
|
||||
'- username:nicolargo\n' +
|
||||
'- username:^root ',
|
||||
is_input=True,
|
||||
input_value=glances_processes.process_filter_input)
|
||||
glances_processes.process_filter = new_filter
|
||||
elif self.edit_filter and cs_status != 'None':
|
||||
self.display_popup('Process filter only available in standalone mode')
|
||||
|
@ -84,6 +84,8 @@ class Plugin(GlancesPlugin):
|
||||
msg = 'Processes filter:'
|
||||
ret.append(self.curse_add_line(msg, "TITLE"))
|
||||
msg = ' {0} '.format(glances_processes.process_filter)
|
||||
if glances_processes.process_filter_key is not None:
|
||||
msg += 'on column {0} '.format(glances_processes.process_filter_key)
|
||||
ret.append(self.curse_add_line(msg, "FILTER"))
|
||||
msg = '(\'ENTER\' to edit, \'E\' to reset)'
|
||||
ret.append(self.curse_add_line(msg))
|
||||
|
@ -116,9 +116,14 @@ class GlancesProcesses(object):
|
||||
"""Set the maximum number of processes showed in the UI."""
|
||||
self._max_processes = value
|
||||
|
||||
@property
|
||||
def process_filter_input(self):
|
||||
"""Get the process filter (given by the user)."""
|
||||
return self._filter.filter_input
|
||||
|
||||
@property
|
||||
def process_filter(self):
|
||||
"""Get the process filter."""
|
||||
"""Get the process filter (current apply filter)."""
|
||||
return self._filter.filter
|
||||
|
||||
@process_filter.setter
|
||||
@ -126,6 +131,11 @@ class GlancesProcesses(object):
|
||||
"""Set the process filter."""
|
||||
self._filter.filter = value
|
||||
|
||||
@property
|
||||
def process_filter_key(self):
|
||||
"""Get the process filter key."""
|
||||
return self._filter.filter_key
|
||||
|
||||
@property
|
||||
def process_filter_re(self):
|
||||
"""Get the process regular expression compiled."""
|
||||
@ -398,7 +408,7 @@ class GlancesProcesses(object):
|
||||
OSX and s['name'] == 'kernel_task'):
|
||||
continue
|
||||
# Continue to the next process if it has to be filtered
|
||||
if s is None or (self._filter.is_filtered(s, 'cmdline') and self._filter.is_filtered(s, 'name')):
|
||||
if s is None or self._filter.is_filtered(s):
|
||||
excluded_processes.add(proc)
|
||||
continue
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user