summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authornicolargo <nicolas@nicolargo.com>2024-04-06 17:46:42 +0200
committernicolargo <nicolas@nicolargo.com>2024-04-06 17:46:42 +0200
commitf87e7d7fe69599de434cfacb0ab65cc9810f7f99 (patch)
treeab16866df32d23d991d3e983e62183e8deb11107
parent71a77bc8ca86bb8a55c6116eb3073a570f56fdb8 (diff)
Export individual processes stats #794
-rw-r--r--conf/glances.conf6
-rw-r--r--docs/aoa/ps.rst8
-rw-r--r--docs/api.rst223
-rw-r--r--docs/man/glances.12
-rw-r--r--glances/filter.py63
-rw-r--r--glances/plugins/processlist/__init__.py2
-rw-r--r--glances/processes.py31
-rwxr-xr-xunitest.py25
8 files changed, 214 insertions, 146 deletions
diff --git a/conf/glances.conf b/conf/glances.conf
index a1435372..5f993981 100644
--- a/conf/glances.conf
+++ b/conf/glances.conf
@@ -359,10 +359,8 @@ nice_warning=-20,-19,-18,-17,-16,-15,-14,-13,-12,-11,-10,-9,-8,-7,-6,-5,-4,-3,-2
#nice_critical=15,16,17,18,19
#
# Define the list of processes to export using:
-# a comma-separated list of regular expression (apply on name and cmdline)
-#export=.*firefox.*
-# or an uniq key:value filter
-#export=pid:1234
+# a comma-separated list of Glances filter
+#export=.*firefox.*,pid:1234
[ports]
disable=False
diff --git a/docs/aoa/ps.rst b/docs/aoa/ps.rst
index fe788cf3..e0a57eec 100644
--- a/docs/aoa/ps.rst
+++ b/docs/aoa/ps.rst
@@ -208,11 +208,9 @@ Glances version 4 introduces a new feature to export specifics processes. In ord
feature, you need to use the export option in the processlist section of the Glances configuration
file or the --export-process-filter option in the command line.
-The export option is one of the following:
-- a comma separated list of process names or regular expressions
-- a single Glances filter (see above)
+The export option is a list of Glances filters.
-Example number one, export all processes with the name 'python':
+Example number one, export all processes named 'python' (or with a command line containing 'python'):
.. code-block:: ini
@@ -230,7 +228,7 @@ Example number two, export all processes with the name 'python' or 'bash':
Note: or the --export-process-filter ".*python.*,.*bash.*" option in the command line.
-Example number three, export all processes belong to the user 'nicolargo':
+Example number three, export all processes belong to 'nicolargo' user:
.. code-block:: ini
diff --git a/docs/api.rst b/docs/api.rst
index 0965f802..50ac6908 100644
--- a/docs/api.rst
+++ b/docs/api.rst
@@ -141,7 +141,7 @@ Get plugin stats::
"refresh": 3.0,
"regex": True,
"result": None,
- "timer": 0.4065737724304199},
+ "timer": 0.3346278667449951},
{"count": 0,
"countmax": 20.0,
"countmin": None,
@@ -150,7 +150,7 @@ Get plugin stats::
"refresh": 3.0,
"regex": True,
"result": None,
- "timer": 0.4064033031463623}]
+ "timer": 0.3344759941101074}]
Fields descriptions:
@@ -178,7 +178,7 @@ Get a specific item when field matches the given value::
"refresh": 3.0,
"regex": True,
"result": None,
- "timer": 0.4065737724304199}]}
+ "timer": 0.3346278667449951}]}
GET cloud
---------
@@ -226,18 +226,18 @@ Get plugin stats::
"engine": "docker",
"id": "3abd51c615968482d9ccff5afc629f267f6dda113ed68b75b432615fae3b49fb",
"image": ["portainer/portainer-ce:2.9.3"],
- "io": {"cumulative_ior": 40960, "cumulative_iow": 741376},
+ "io": {"cumulative_ior": 110592, "cumulative_iow": 962560},
"key": "name",
"memory": {"cache": None,
"limit": 7823568896,
"max_usage": None,
"rss": None,
- "usage": 14016512},
- "memory_usage": 14016512,
+ "usage": 15851520},
+ "memory_usage": 15851520,
"name": "portainer",
- "network": {"cumulative_rx": 1280393, "cumulative_tx": 1496},
+ "network": {"cumulative_rx": 1803247, "cumulative_tx": 1636},
"status": "running",
- "uptime": "5 days"}]
+ "uptime": "6 days"}]
Fields descriptions:
@@ -273,18 +273,18 @@ Get a specific item when field matches the given value::
"engine": "docker",
"id": "3abd51c615968482d9ccff5afc629f267f6dda113ed68b75b432615fae3b49fb",
"image": ["portainer/portainer-ce:2.9.3"],
- "io": {"cumulative_ior": 40960, "cumulative_iow": 741376},
+ "io": {"cumulative_ior": 110592, "cumulative_iow": 962560},
"key": "name",
"memory": {"cache": None,
"limit": 7823568896,
"max_usage": None,
"rss": None,
- "usage": 14016512},
- "memory_usage": 14016512,
+ "usage": 15851520},
+ "memory_usage": 15851520,
"name": "portainer",
- "network": {"cumulative_rx": 1280393, "cumulative_tx": 1496},
+ "network": {"cumulative_rx": 1803247, "cumulative_tx": 1636},
"status": "running",
- "uptime": "5 days"}]}
+ "uptime": "6 days"}]}
GET core
--------
@@ -311,19 +311,19 @@ Get plugin stats::
# curl http://localhost:61208/api/4/cpu
{"cpucore": 4,
- "ctx_switches": 1046087238,
+ "ctx_switches": 1083773007,
"guest": 0.0,
- "idle": 71.1,
- "interrupts": 480749229,
+ "idle": 71.2,
+ "interrupts": 497643356,
"iowait": 0.0,
"irq": 0.0,
"nice": 0.0,
- "soft_interrupts": 213157924,
+ "soft_interrupts": 222951171,
"steal": 0.0,
"syscalls": 0,
- "system": 4.8,
- "total": 28.9,
- "user": 24.1}
+ "system": 3.1,
+ "total": 28.8,
+ "user": 25.8}
Fields descriptions:
@@ -356,7 +356,7 @@ Fields descriptions:
Get a specific field::
# curl http://localhost:61208/api/4/cpu/total
- {"total": 28.9}
+ {"total": 28.8}
GET diskio
----------
@@ -366,10 +366,10 @@ Get plugin stats::
# curl http://localhost:61208/api/4/diskio
[{"disk_name": "sda",
"key": "disk_name",
- "read_bytes": 103830181888,
- "read_count": 5595135,
- "write_bytes": 205683687424,
- "write_count": 2538561},
+ "read_bytes": 106861217280,
+ "read_count": 5848339,
+ "write_bytes": 209200316416,
+ "write_count": 2631934},
{"disk_name": "sda1",
"key": "disk_name",
"read_bytes": 24269824,
@@ -404,10 +404,10 @@ Get a specific item when field matches the given value::
# curl http://localhost:61208/api/4/diskio/disk_name/sda
{"sda": [{"disk_name": "sda",
"key": "disk_name",
- "read_bytes": 103830181888,
- "read_count": 5595135,
- "write_bytes": 205683687424,
- "write_count": 2538561}]}
+ "read_bytes": 106861217280,
+ "read_count": 5848339,
+ "write_bytes": 209200316416,
+ "write_count": 2631934}]}
GET folders
-----------
@@ -434,13 +434,13 @@ Get plugin stats::
# curl http://localhost:61208/api/4/fs
[{"device_name": "/dev/mapper/ubuntu--gnome--vg-root",
- "free": 36362539008,
+ "free": 35840458752,
"fs_type": "ext4",
"key": "mnt_point",
"mnt_point": "/",
- "percent": 84.3,
+ "percent": 84.5,
"size": 243334156288,
- "used": 194584162304},
+ "used": 195106242560},
{"device_name": "zsfpool",
"free": 31195136,
"fs_type": "zfs",
@@ -469,13 +469,13 @@ Get a specific item when field matches the given value::
# curl http://localhost:61208/api/4/fs/mnt_point//
{"/": [{"device_name": "/dev/mapper/ubuntu--gnome--vg-root",
- "free": 36362539008,
+ "free": 35840458752,
"fs_type": "ext4",
"key": "mnt_point",
"mnt_point": "/",
- "percent": 84.3,
+ "percent": 84.5,
"size": 243334156288,
- "used": 194584162304}]}
+ "used": 195106242560}]}
GET gpu
-------
@@ -548,10 +548,7 @@ GET load
Get plugin stats::
# curl http://localhost:61208/api/4/load
- {"cpucore": 4,
- "min1": 1.11474609375,
- "min15": 1.30419921875,
- "min5": 1.060546875}
+ {"cpucore": 4, "min1": 0.1416015625, "min15": 0.970703125, "min5": 0.765625}
Fields descriptions:
@@ -563,7 +560,7 @@ Fields descriptions:
Get a specific field::
# curl http://localhost:61208/api/4/load/min1
- {"min1": 1.11474609375}
+ {"min1": 0.1416015625}
GET mem
-------
@@ -571,16 +568,16 @@ GET mem
Get plugin stats::
# curl http://localhost:61208/api/4/mem
- {"active": 2653958144,
- "available": 2423255040,
- "buffers": 676577280,
- "cached": 2417643520,
- "free": 2423255040,
- "inactive": 3602350080,
- "percent": 69.0,
- "shared": 699977728,
+ {"active": 2535997440,
+ "available": 2432135168,
+ "buffers": 501940224,
+ "cached": 2622812160,
+ "free": 2432135168,
+ "inactive": 3695976448,
+ "percent": 68.9,
+ "shared": 652316672,
"total": 7823568896,
- "used": 5400313856}
+ "used": 5391433728}
Fields descriptions:
@@ -607,13 +604,13 @@ GET memswap
Get plugin stats::
# curl http://localhost:61208/api/4/memswap
- {"free": 6406701056,
- "percent": 20.7,
- "sin": 8078508032,
- "sout": 16575467520,
+ {"free": 6828023808,
+ "percent": 15.5,
+ "sin": 8335540224,
+ "sout": 16940646400,
"time_since_update": 1,
"total": 8082419712,
- "used": 1675718656}
+ "used": 1254395904}
Fields descriptions:
@@ -638,15 +635,15 @@ Get plugin stats::
# curl http://localhost:61208/api/4/network
[{"alias": None,
"bytes_all": 0,
- "bytes_all_gauge": 9306142258,
+ "bytes_all_gauge": 9770615278,
"bytes_recv": 0,
- "bytes_recv_gauge": 8752265243,
+ "bytes_recv_gauge": 9183565245,
"bytes_sent": 0,
- "bytes_sent_gauge": 553877015,
+ "bytes_sent_gauge": 587050033,
"interface_name": "wlp2s0",
"key": "interface_name",
"speed": 0,
- "time_since_update": 0.30997323989868164},
+ "time_since_update": 0.22126293182373047},
{"alias": None,
"bytes_all": 0,
"bytes_all_gauge": 0,
@@ -657,7 +654,7 @@ Get plugin stats::
"interface_name": "br-40875d2e2716",
"key": "interface_name",
"speed": 0,
- "time_since_update": 0.30997323989868164}]
+ "time_since_update": 0.22126293182373047}]
Fields descriptions:
@@ -693,15 +690,15 @@ Get a specific item when field matches the given value::
# curl http://localhost:61208/api/4/network/interface_name/wlp2s0
{"wlp2s0": [{"alias": None,
"bytes_all": 0,
- "bytes_all_gauge": 9306142258,
+ "bytes_all_gauge": 9770615278,
"bytes_recv": 0,
- "bytes_recv_gauge": 8752265243,
+ "bytes_recv_gauge": 9183565245,
"bytes_sent": 0,
- "bytes_sent_gauge": 553877015,
+ "bytes_sent_gauge": 587050033,
"interface_name": "wlp2s0",
"key": "interface_name",
"speed": 0,
- "time_since_update": 0.30997323989868164}]}
+ "time_since_update": 0.22126293182373047}]}
GET now
-------
@@ -709,7 +706,7 @@ GET now
Get plugin stats::
# curl http://localhost:61208/api/4/now
- "2024-04-05 19:39:57 CEST"
+ "2024-04-06 17:45:25 CEST"
GET percpu
----------
@@ -720,29 +717,29 @@ Get plugin stats::
[{"cpu_number": 0,
"guest": 0.0,
"guest_nice": 0.0,
- "idle": 42.0,
+ "idle": 10.0,
"iowait": 0.0,
"irq": 0.0,
"key": "cpu_number",
"nice": 0.0,
"softirq": 0.0,
"steal": 0.0,
- "system": 6.0,
- "total": 58.0,
- "user": 27.0},
+ "system": 4.0,
+ "total": 90.0,
+ "user": 52.0},
{"cpu_number": 1,
"guest": 0.0,
"guest_nice": 0.0,
- "idle": 67.0,
+ "idle": 53.0,
"iowait": 0.0,
"irq": 0.0,
"key": "cpu_number",
"nice": 0.0,
"softirq": 0.0,
"steal": 0.0,
- "system": 3.0,
- "total": 33.0,
- "user": 6.0}]
+ "system": 2.0,
+ "total": 47.0,
+ "user": 11.0}]
Fields descriptions:
@@ -776,7 +773,7 @@ Get plugin stats::
"port": 0,
"refresh": 30,
"rtt_warning": None,
- "status": 0.005854,
+ "status": 0.007423,
"timeout": 3}]
Fields descriptions:
@@ -804,7 +801,7 @@ Get a specific item when field matches the given value::
"port": 0,
"refresh": 30,
"rtt_warning": None,
- "status": 0.005854,
+ "status": 0.007423,
"timeout": 3}]}
GET processcount
@@ -813,7 +810,7 @@ GET processcount
Get plugin stats::
# curl http://localhost:61208/api/4/processcount
- {"pid_max": 0, "running": 2, "sleeping": 336, "thread": 1575, "total": 404}
+ {"pid_max": 0, "running": 1, "sleeping": 333, "thread": 1520, "total": 403}
Fields descriptions:
@@ -826,7 +823,7 @@ Fields descriptions:
Get a specific field::
# curl http://localhost:61208/api/4/processcount/total
- {"total": 404}
+ {"total": 403}
GET processlist
---------------
@@ -866,43 +863,43 @@ GET quicklook
Get plugin stats::
# curl http://localhost:61208/api/4/quicklook
- {"cpu": 28.9,
+ {"cpu": 28.8,
"cpu_hz": 2025000000.0,
- "cpu_hz_current": 1723951750.0,
+ "cpu_hz_current": 1723628500.0,
"cpu_name": "Intel(R) Core(TM) i7-4500U CPU @ 1.80GHz",
"cpucore": 4,
- "load": 32.6,
- "mem": 69.0,
+ "load": 24.3,
+ "mem": 68.9,
"percpu": [{"cpu_number": 0,
"guest": 0.0,
"guest_nice": 0.0,
- "idle": 42.0,
+ "idle": 10.0,
"iowait": 0.0,
"irq": 0.0,
"key": "cpu_number",
"nice": 0.0,
"softirq": 0.0,
"steal": 0.0,
- "system": 6.0,
- "total": 58.0,
- "user": 27.0},
+ "system": 4.0,
+ "total": 90.0,
+ "user": 52.0},
{"cpu_number": 1,
"guest": 0.0,
"guest_nice": 0.0,
- "idle": 67.0,
+ "idle": 53.0,
"iowait": 0.0,
"irq": 0.0,
"key": "cpu_number",
"nice": 0.0,
"softirq": 0.0,
"steal": 0.0,
- "system": 3.0,
- "total": 33.0,
- "user": 6.0},
+ "system": 2.0,
+ "total": 47.0,
+ "user": 11.0},
{"cpu_number": 2,
"guest": 0.0,
"guest_nice": 0.0,
- "idle": 66.0,
+ "idle": 62.0,
"iowait": 0.0,
"irq": 0.0,
"key": "cpu_number",
@@ -910,22 +907,22 @@ Get plugin stats::
"softirq": 0.0,
"steal": 0.0,
"system": 1.0,
- "total": 34.0,
- "user": 8.0},
+ "total": 38.0,
+ "user": 2.0},
{"cpu_number": 3,
"guest": 0.0,
"guest_nice": 0.0,
- "idle": 40.0,
+ "idle": 62.0,
"iowait": 0.0,
"irq": 0.0,
"key": "cpu_number",
"nice": 0.0,
"softirq": 0.0,
"steal": 0.0,
- "system": 4.0,
- "total": 60.0,
- "user": 30.0}],
- "swap": 20.7}
+ "system": 1.0,
+ "total": 38.0,
+ "user": 2.0}],
+ "swap": 15.5}
Fields descriptions:
@@ -1045,7 +1042,7 @@ GET uptime
Get plugin stats::
# curl http://localhost:61208/api/4/uptime
- "32 days, 10:39:09"
+ "33 days, 8:44:36"
GET version
-----------
@@ -1105,34 +1102,34 @@ GET stats history
History of a plugin::
# curl http://localhost:61208/api/4/cpu/history
- {"system": [["2024-04-05T19:39:59.495699", 4.8],
- ["2024-04-05T19:40:00.515910", 1.8],
- ["2024-04-05T19:40:01.696855", 1.8]],
- "user": [["2024-04-05T19:39:59.495685", 24.1],
- ["2024-04-05T19:40:00.515902", 7.0],
- ["2024-04-05T19:40:01.696838", 7.0]]}
+ {"system": [["2024-04-06T17:45:26.720681", 3.1],
+ ["2024-04-06T17:45:27.742109", 2.2],
+ ["2024-04-06T17:45:28.929983", 2.2]],
+ "user": [["2024-04-06T17:45:26.720667", 25.8],
+ ["2024-04-06T17:45:27.742099", 7.5],
+ ["2024-04-06T17:45:28.929968", 7.5]]}
Limit history to last 2 values::
# curl http://localhost:61208/api/4/cpu/history/2
- {"system": [["2024-04-05T19:40:00.515910", 1.8],
- ["2024-04-05T19:40:01.696855", 1.8]],
- "user": [["2024-04-05T19:40:00.515902", 7.0],
- ["2024-04-05T19:40:01.696838", 7.0]]}
+ {"system": [["2024-04-06T17:45:27.742109", 2.2],
+ ["2024-04-06T17:45:28.929983", 2.2]],
+ "user": [["2024-04-06T17:45:27.742099", 7.5],
+ ["2024-04-06T17:45:28.929968", 7.5]]}
History for a specific field::
# curl http://localhost:61208/api/4/cpu/system/history
- {"system": [["2024-04-05T19:39:57.916788", 4.8],
- ["2024-04-05T19:39:59.495699", 4.8],
- ["2024-04-05T19:40:00.515910", 1.8],
- ["2024-04-05T19:40:01.696855", 1.8]]}
+ {"system": [["2024-04-06T17:45:25.061145", 3.1],
+ ["2024-04-06T17:45:26.720681", 3.1],
+ ["2024-04-06T17:45:27.742109", 2.2],
+ ["2024-04-06T17:45:28.929983", 2.2]]}
Limit history for a specific field to last 2 values::
# curl http://localhost:61208/api/4/cpu/system/history
- {"system": [["2024-04-05T19:40:00.515910", 1.8],
- ["2024-04-05T19:40:01.696855", 1.8]]}
+ {"system": [["2024-04-06T17:45:27.742109", 2.2],
+ ["2024-04-06T17:45:28.929983", 2.2]]}
GET limits (used for thresholds)
--------------------------------
diff --git a/docs/man/glances.1 b/docs/man/glances.1
index 684a5672..d6d56ccb 100644
--- a/docs/man/glances.1
+++ b/docs/man/glances.1
@@ -27,7 +27,7 @@ level margin: \\n[rst2man-indent\\n[rst2man-indent-level]]
.\" new: \\n[rst2man-indent\\n[rst2man-indent-level]]
.in \\n[rst2man-indent\\n[rst2man-indent-level]]u
..
-.TH "GLANCES" "1" "Apr 05, 2024" "4.0.0_beta01" "Glances"
+.TH "GLANCES" "1" "Apr 06, 2024" "4.0.0_beta01" "Glances"
.SH NAME
glances \- An eye on your system
.SH SYNOPSIS
diff --git a/glances/filter.py b/glances/filter.py
index 727bf695..d54e889d 100644
--- a/glances/filter.py
+++ b/glances/filter.py
@@ -12,6 +12,49 @@ import re
from glances.logger import logger
+class GlancesFilterList(object):
+ """Manage a lis of GlancesFilter objects
+
+ >>> fl = GlancesFilterList()
+ >>> fl.filter = '.*python.*,user:nicolargo'
+ >>> fl.is_filtered({'name': 'python is in the place'})
+ True
+ >>> fl.is_filtered({'name': 'snake is in the place'})
+ False
+ >>> fl.is_filtered({'name': 'snake is in the place', 'username': 'nicolargo'})
+ True
+ >>> fl.is_filtered({'name': 'snake is in the place', 'username': 'notme'})
+ False
+ """
+
+ def __init__(self):
+ self._filter = []
+
+ @property
+ def filter(self):
+ """Return the current filter to be applied"""
+ return self._filter
+
+ @filter.setter
+ def filter(self, value):
+ """Add a comma separated list of filters"""
+ for f in value.split(','):
+ self._add_filter(f)
+
+ def _add_filter(self, filter_input):
+ """Add a filter"""
+ f = GlancesFilter()
+ f.filter = filter_input
+ self._filter.append(f)
+
+ def is_filtered(self, process):
+ """Return True if the process is filtered by at least one filter"""
+ for f in self._filter:
+ if f.is_filtered(process):
+ return True
+ return False
+
+
class GlancesFilter(object):
"""Allow Glances to filter processes
@@ -20,13 +63,13 @@ class GlancesFilter(object):
>>> f.filter = '.*python.*'
>>> f.filter
'.*python.*'
- >>> f.key
+ >>> f.filter_key
None
- >>> f.filter = 'user:nicolargo'
+ >>> f.filter = 'username:nicolargo'
>>> f.filter
'nicolargo'
- >>> f.key
- 'user'
+ >>> f.filter_key
+ 'username'
>>> f.filter = 'username:.*nico.*'
>>> f.filter
'.*nico.*'
@@ -60,9 +103,9 @@ class GlancesFilter(object):
"""Set the filter (as a string) 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
+ - python > Process name start with python
+ - .*python.* > Process name contain python
+ - user:nicolargo > Process belong to nicolargo user
"""
self._filter_input = value
if value is None:
@@ -125,7 +168,9 @@ class GlancesFilter(object):
try:
# 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):
+ if isinstance(process[key], list) and key == 'cmdline' and len(process[key]) > 0:
+ value = process[key][0]
+ elif isinstance(process[key], list):
value = ' '.join(process[key])
else:
value = process[key]
@@ -133,7 +178,7 @@ class GlancesFilter(object):
# If the key did not exist
return False
try:
- return self._filter_re.fullmatch(value) is None
+ return self._filter_re.fullmatch(value) is not None
except (AttributeError, TypeError):
# AttributeError - Filter processes crashes with a bad regular expression pattern (issue #665)
# TypeError - Filter processes crashes if value is None (issue #1105)
diff --git a/glances/plugins/processlist/__init__.py b/glances/plugins/processlist/__init__.py
index f3d2c284..e5cdec0f 100644
--- a/glances/plugins/processlist/__init__.py
+++ b/glances/plugins/processlist/__init__.py
@@ -191,7 +191,7 @@ class PluginModel(GlancesPluginModel):
glances_processes.export_process_filter = config.as_dict()['processlist']['export']
if args.export:
logger.info("Export process filter is set to: {}".format(
- glances_processes.export_process_filter))
+ config.as_dict()['processlist']['export']))
# The default sort key could also be overwrite by command line (see #1903)
if args.sort_processes_key is not None:
diff --git a/glances/processes.py b/glances/processes.py
index 1c9d1de5..7ba12eb7 100644
--- a/glances/processes.py
+++ b/glances/processes.py
@@ -12,7 +12,7 @@ import os
from glances.globals import BSD, LINUX, MACOS, WINDOWS, iterkeys
from glances.globals import namedtuple_to_dict, list_of_namedtuple_to_list_of_dict
from glances.timer import Timer, getTimeSinceLastUpdate
-from glances.filter import GlancesFilter
+from glances.filter import GlancesFilterList, GlancesFilter
from glances.programs import processes_to_programs
from glances.logger import logger
@@ -69,8 +69,9 @@ class GlancesProcesses(object):
# Cache is a dict with key=pid and value = dict of cached value
self.processlist_cache = {}
- # List of processes stats to export (filtred by the _filter_export)
- self._filter_export = GlancesFilter()
+ # List of processes stats to export
+ # Only process matching one of the filter will be exported
+ self._filter_export = GlancesFilterList()
self.processlist_export = []
# Tag to enable/disable the processes stats (to reduce the Glances CPU consumption)
@@ -106,7 +107,7 @@ class GlancesProcesses(object):
# Maximum number of processes showed in the UI (None if no limit)
self._max_processes = None
- # Process filter is a regular expression
+ # Process filter
self._filter = GlancesFilter()
# Whether or not to hide kernel threads
@@ -237,13 +238,13 @@ class GlancesProcesses(object):
@property
def export_process_filter(self):
- """Get the export process filter (current export filter)."""
+ """Get the export process filter (current export process filter list)."""
return self._filter_export.filter
@export_process_filter.setter
def export_process_filter(self, value):
- """Set the export process filter."""
- self._filter_export.filter = '|'.join(value.split(','))
+ """Set the export process filter list."""
+ self._filter_export.filter = value
# Kernel threads
@@ -502,12 +503,12 @@ class GlancesProcesses(object):
except KeyError:
pass
- # Filter and transform process list
- processlist = self.update_list(processlist)
-
# Filter and transform process export list
self.processlist_export = self.update_export_list(processlist)
+ # Filter and transform process list
+ processlist = self.update_list(processlist)
+
# 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:
@@ -522,14 +523,18 @@ class GlancesProcesses(object):
def update_list(self, processlist):
"""Return the process list after filtering and transformation (namedtuple to dict)."""
- ret = list(filter(lambda p: not self._filter.is_filtered(p), processlist))
+ if self._filter.filter is None:
+ return list_of_namedtuple_to_list_of_dict(processlist)
+ ret = list(filter(lambda p: self._filter.is_filtered(p),
+ processlist))
return list_of_namedtuple_to_list_of_dict(ret)
def update_export_list(self, processlist):
"""Return the process export list after filtering and transformation (namedtuple to dict)."""
- if self._filter_export.filter is None:
+ if self._filter_export.filter == []:
return []
- ret = list(filter(lambda p: not self._filter_export.is_filtered(p), processlist))
+ ret = list(filter(lambda p: self._filter_export.is_filtered(p),
+ processlist))
return list_of_namedtuple_to_list_of_dict(ret)
def get_count(self):
diff --git a/unitest.py b/unitest.py
index fe6fd5fc..3428dde1 100755
--- a/unitest.py
+++ b/unitest.py
@@ -33,6 +33,7 @@ from glances.plugins.plugin.model import GlancesPluginModel
from glances.programs import processes_to_programs
from glances.secure import secure_popen
from glances.events_list import GlancesEventsList
+from glances.filter import GlancesFilterList, GlancesFilter
# Global variables
# =================
@@ -345,6 +346,30 @@ class TestGlances(unittest.TestCase):
events.clean()
self.assertEqual(len(events.get()), 1)
+ def test_020_filter(self):
+ """Test filter classes"""
+ print('INFO: [TEST_020] Test filter')
+ gf = GlancesFilter()
+ gf.filter = '.*python.*'
+ self.assertEqual(gf.filter, '.*python.*')
+ self.assertEqual(gf.filter_key, None)
+ self.assertTrue(gf.is_filtered({'name': 'python'}))
+ self.assertTrue(gf.is_filtered({'name': '/usr/bin/python -m glances'}))
+ self.assertFalse(gf.is_filtered({'noname': 'python'}))
+ self.assertFalse(gf.is_filtered({'name': 'snake'}))
+ gf.filter = 'username:nicolargo'
+ self.assertEqual(gf.filter, 'nicolargo')
+ self.assertEqual(gf.filter_key, 'username')
+ self.assertTrue(gf.is_filtered({'username': 'nicolargo'}))
+ self.assertFalse(gf.is_filtered({'username': 'notme'}))
+ self.assertFalse(gf.is_filtered({'notuser': 'nicolargo'}))
+ gfl = GlancesFilterList()
+ gfl.filter = '.*python.*,username:nicolargo'
+ self.assertTrue(gfl.is_filtered({'name': 'python is in the place'}))
+ self.assertFalse(gfl.is_filtered({'name': 'snake is in the place'}))
+ self.assertTrue(gfl.is_filtered({'name': 'snake is in the place', 'username': 'nicolargo'}))
+ self.assertFalse(gfl.is_filtered({'name': 'snake is in the place', 'username': 'notme'}))
+
def test_094_thresholds(self):
"""Test thresholds classes"""
print('INFO: [TEST_094] Thresholds')