Test Failed
Pull Request — develop (#3190)
by
unknown
02:44
created

glances.amps_list.AmpsList._build_amps_list()   B

Complexity

Conditions 7

Size

Total Lines 22
Code Lines 13

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 7
eloc 13
nop 3
dl 0
loc 22
rs 8
c 0
b 0
f 0
1
#
2
# This file is part of Glances.
3
#
4
# SPDX-FileCopyrightText: 2022 Nicolas Hennion <[email protected]>
5
#
6
# SPDX-License-Identifier: LGPL-3.0-only
7
#
8
9
"""Manage the AMPs list."""
10
11
import os
12
import re
13
import threading
14
15
from glances.globals import amps_path, listkeys
16
from glances.logger import logger
17
from glances.processes import glances_processes
18
19
20
class AmpsList:
21
    """This class describes the optional application monitoring process list.
22
23
    The AMP list is a list of processes with a specific monitoring action.
24
25
    The list (Python list) is composed of items (Python dict).
26
    An item is defined (dict keys):
27
    *...
28
    """
29
30
    # The dict
31
    __amps_dict = {}
32
33
    def __init__(self, args, config):
34
        """Init the AMPs list."""
35
        self.args = args
36
        self.config = config
37
38
        # Load the AMP configurations / scripts
39
        self.load_configs()
40
41
    def load_configs(self):
42
        """Load the AMP configuration files."""
43
        if self.config is None:
44
            return False
45
46
        # For each AMP script, call the load_config method
47
        for s in self.config.sections():
48
            if s.startswith("amp_"):
49
                # An AMP section exists in the configuration file
50
                # If an AMP module exist in amps_path (glances/amps) folder then use it
51
                amp_name = s[4:]
52
                amp_module = os.path.join(amps_path, amp_name)
53
                if not os.path.exists(amp_module):
54
                    # If not, use the default script
55
                    amp_module = os.path.join(amps_path, "default")
56
                try:
57
                    amp = __import__(os.path.basename(amp_module))
58
                except ImportError as e:
59
                    logger.warning(f"Missing Python Lib ({e}), cannot load AMP {amp_name}")
60
                except Exception as e:
61
                    logger.warning(f"Cannot load AMP {amp_name} ({e})")
62
                else:
63
                    # Add the AMP to the dictionary
64
                    # The key is the AMP name
65
                    # for example, the file glances_xxx.py
66
                    # generate self._amps_list["xxx"] = ...
67
                    self.__amps_dict[amp_name] = amp.Amp(name=amp_name, args=self.args)
68
                    # Load the AMP configuration
69
                    self.__amps_dict[amp_name].load_config(self.config)
70
        # Log AMPs list
71
        logger.debug(f"AMPs list: {self.getList()}")
72
73
        return True
74
75
    def __str__(self):
76
        return str(self.__amps_dict)
77
78
    def __repr__(self):
79
        return self.__amps_dict
80
81
    def __getitem__(self, item):
82
        return self.__amps_dict[item]
83
84
    def __len__(self):
85
        return len(self.__amps_dict)
86
87
    def update(self):
88
        """Update the command result attributed."""
89
        # Get the current processes list (once)
90
        processlist = glances_processes.get_list()
91
92
        # Iter upon the AMPs dict
93
        for k, v in self.get().items():
94
            if not v.enable():
95
                # Do not update if the enable tag is set
96
                continue
97
98
            if v.regex() is None:
99
                # If there is no regex, execute anyway (see issue #1690)
100
                v.set_count(0)
101
                # Call the AMP update method
102
                thread = threading.Thread(target=v.update_wrapper, args=[[]])
103
                thread.start()
104
                continue
105
106
            amps_list = self._build_amps_list(v, processlist)
107
108
            if amps_list:
109
                # At least one process is matching the regex
110
                logger.debug(f"AMPS: {len(amps_list)} processes {k} detected ({amps_list})")
111
                # Call the AMP update method
112
                thread = threading.Thread(target=v.update_wrapper, args=[amps_list])
113
                thread.start()
114
            else:
115
                # Set the process number to 0
116
                v.set_count(0)
117
                if v.count_min() is not None and v.count_min() > 0:
118
                    # Only display the "No running process message" if count_min is defined
119
                    v.set_result("No running process")
120
121
        return self.__amps_dict
122
123
    def _build_amps_list(self, amp_value, processlist):
124
        """Return the AMPS process list according to the amp_value
125
126
        Search application monitored processes by a regular expression
127
        """
128
        try:
129
            # Search in both cmdline and name (for kernel thread, see #1261)
130
            ret = [
131
                {'pid': p['pid'], 'cpu_percent': p['cpu_percent'], 'memory_percent': p['memory_percent']}
132
                for p in processlist
133
                if re.search(amp_value.regex(), p['name'])
134
                or ((cmdline := p.get('cmdline')) and re.search(amp_value.regex(), ' '.join(cmdline)))
135
            ]
136
137
        except (TypeError, KeyError) as e:
138
            logger.debug(f"Can not build AMPS list ({e})")
139
140
        return ret
141
142
    def getList(self):
143
        """Return the AMPs list."""
144
        return listkeys(self.__amps_dict)
145
146
    def get(self):
147
        """Return the AMPs dict."""
148
        return self.__amps_dict
149
150
    def set(self, new_dict):
151
        """Set the AMPs dict."""
152
        self.__amps_dict = new_dict
153