Completed
Push — master ( 3dcd25...20576f )
by Nicolas
01:26
created

GlancesFilter   A

Complexity

Total Complexity 18

Size/Duplication

Total Lines 121
Duplicated Lines 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
c 1
b 0
f 0
dl 0
loc 121
rs 10
wmc 18

7 Methods

Rating   Name   Duplication   Size   Complexity  
A is_filtered() 0 14 3
A filter_re() 0 4 1
A __init__() 0 10 1
B filter() 0 4 5
A filter_key() 0 4 1
B _is_process_filtered() 0 19 5
A filter_input() 0 4 1
1
# -*- coding: utf-8 -*-
2
#
3
# This file is part of Glances.
4
#
5
# Copyright (C) 2016 Nicolargo <[email protected]>
6
#
7
# Glances is free software; you can redistribute it and/or modify
8
# it under the terms of the GNU Lesser General Public License as published by
9
# the Free Software Foundation, either version 3 of the License, or
10
# (at your option) any later version.
11
#
12
# Glances is distributed in the hope that it will be useful,
13
# but WITHOUT ANY WARRANTY; without even the implied warranty of
14
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15
# GNU Lesser General Public License for more details.
16
#
17
# You should have received a copy of the GNU Lesser General Public License
18
# along with this program. If not, see <http://www.gnu.org/licenses/>.
19
20
import re
21
22
from glances.logger import logger
23
24
25
class GlancesFilter(object):
26
27
    """Allow Glances to filter processes
28
29
    >>> f = GlancesFilter()
30
    >>> f.filter = '.*python.*'
31
    >>> f.filter
32
    '.*python.*'
33
    >>> f.key
34
    None
35
    >>> f.filter = 'user:nicolargo'
36
    >>> f.filter
37
    'nicolargo'
38
    >>> f.key
39
    'user'
40
    >>> f.filter = 'username:.*nico.*'
41
    >>> f.filter
42
    '.*nico.*'
43
    >>> f.key
44
    'username'
45
    """
46
47
    def __init__(self):
48
        # Filter entered by the user (string)
49
        self._filter_input = None
50
        # Filter to apply
51
        self._filter = None
52
        # Filter regular expression
53
        self._filter_re = None
54
        # Dict key where the filter should be applied
55
        # Default is None: search on command line and process name
56
        self._filter_key = None
57
58
    @property
59
    def filter_input(self):
60
        """Return the filter given by the user (as a sting)"""
61
        return self._filter_input
62
63
    @property
64
    def filter(self):
65
        """Return the current filter to be applied"""
66
        return self._filter
67
68
    @filter.setter
69
    def filter(self, value):
70
        """Set the filter (as a sting) and compute the regular expression
71
        A filter could be one of the following:
72
        - python > Process name of cmd start with python
73
        - .*python.* > Process name of cmd contain python
74
        - username:nicolargo > Process of nicolargo user
75
        """
76
        self._filter_input = value
77
        if value is None:
78
            self._filter = None
79
            self._filter_key = None
80
        else:
81
            new_filter = value.split(':')
82
            if len(new_filter) == 1:
83
                self._filter = new_filter[0]
84
                self._filter_key = None
85
            else:
86
                self._filter = new_filter[1]
87
                self._filter_key = new_filter[0]
88
89
        self._filter_re = None
90
        if self.filter is not None:
91
            logger.info("Set filter to {} on key {}".format(self.filter, self.filter_key))
92
            # Compute the regular expression
93
            try:
94
                self._filter_re = re.compile(self.filter)
95
                logger.debug("Filter regex compilation OK: {}".format(self.filter))
96
            except Exception as e:
97
                logger.error("Cannot compile filter regex: {} ({})".format(self.filter, e))
98
                self._filter = None
99
                self._filter_re = None
100
                self._filter_key = None
101
102
    @property
103
    def filter_re(self):
104
        """Return the filter regular expression"""
105
        return self._filter_re
106
107
    @property
108
    def filter_key(self):
109
        """key where the filter should be applied"""
110
        return self._filter_key
111
112
    def is_filtered(self, process):
113
        """Return True if the process item match the current filter
114
        The proces item is a dict.
115
        """
116
        if self.filter is None:
117
            # No filter => Not filtered
118
            return False
119
120
        if self.filter_key is None:
121
            # Apply filter on command line and process name
122
            return self._is_process_filtered(process, key='cmdline') and self._is_process_filtered(process, key='name')
123
        else:
124
            # Apply filter on <key>
125
            return self._is_process_filtered(process)
126
127
    def _is_process_filtered(self, process, key=None):
128
        """Return True if the process[key] should be filtered according to the current filter"""
129
        if key is None:
130
            key = self.filter_key
131
        try:
132
            # If the item process[key] is a list, convert it to a string
133
            # in order to match it with the current regular expression
134
            if isinstance(process[key], list):
135
                value = ' '.join(process[key])
136
            else:
137
                value = process[key]
138
        except KeyError:
139
            # If the key did not exist
140
            return False
141
        try:
142
            return self._filter_re.match(value) is None
143
        except AttributeError:
144
            #  Filter processes crashs with a bad regular expression pattern (issue #665)
145
            return False
146