Test Failed
Push — develop ( abf64f...1d1151 )
by Nicolas
02:59
created

glances.events.GlancesEvents._update_event()   B

Complexity

Conditions 6

Size

Total Lines 46
Code Lines 26

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 6
eloc 26
nop 8
dl 0
loc 46
rs 8.3226
c 0
b 0
f 0

How to fix   Many Parameters   

Many Parameters

Methods with many parameters are not only hard to understand, but their parameters also often become inconsistent when you need more, or different data.

There are several approaches to avoid long parameter lists:

1
# -*- coding: utf-8 -*-
2
#
3
# This file is part of Glances.
4
#
5
# Copyright (C) 2019 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
"""Manage Glances events (previously Glances logs in Glances < 3.1)."""
21
22
import time
0 ignored issues
show
introduced by
import missing from __future__ import absolute_import
Loading history...
23
from datetime import datetime
0 ignored issues
show
introduced by
import missing from __future__ import absolute_import
Loading history...
24
25
from glances.compat import range
0 ignored issues
show
Bug Best Practice introduced by
This seems to re-define the built-in range.

It is generally discouraged to redefine built-ins as this makes code very hard to read.

Loading history...
introduced by
import missing from __future__ import absolute_import
Loading history...
26
from glances.processes import glances_processes, sort_stats
0 ignored issues
show
introduced by
import missing from __future__ import absolute_import
Loading history...
27
28
29
class GlancesEvents(object):
30
31
    """This class manages events inside the Glances software.
32
33
    Events is a list of event (stored in the self.events_list var)
34
    event_state = "OK|CAREFUL|WARNING|CRITICAL"
35
    event_type = "CPU*|LOAD|MEM|MON"
36
    event_value = value
37
38
    Item (or event) is defined by:
39
      ["begin",
40
       "end",
41
       "WARNING|CRITICAL",
42
       "CPU|LOAD|MEM",
43
       MAX, AVG, MIN, SUM, COUNT,
44
       [top3 process list],
45
       "Processes description",
46
       "top sort key"]
47
    """
48
49
    def __init__(self):
50
        """Init the events class."""
51
        # Maximum size of the events list
52
        self.events_max = 10
53
54
        # Init the logs list
55
        self.events_list = []
56
57
    def get(self):
58
        """Return the raw events list."""
59
        return self.events_list
60
61
    def len(self):
62
        """Return the number of events in the logs list."""
63
        return self.events_list.__len__()
64
65
    def __event_exist(self, event_type):
66
        """Return the event position, if it exists.
67
68
        An event exist if:
69
        * end is < 0
70
        * event_type is matching
71
        Return -1 if the item is not found.
72
        """
73
        for i in range(self.len()):
74
            if self.events_list[i][1] < 0 and self.events_list[i][3] == event_type:
0 ignored issues
show
Coding Style introduced by
This line is too long as per the coding-style (83/80).

This check looks for lines that are too long. You can specify the maximum line length.

Loading history...
75
                return i
76
        return -1
77
78
    def get_event_sort_key(self, event_type):
0 ignored issues
show
Coding Style introduced by
This method could be written as a function/class method.

If a method does not access any attributes of the class, it could also be implemented as a function or static method. This can help improve readability. For example

class Foo:
    def some_method(self, x, y):
        return x + y;

could be written as

class Foo:
    @classmethod
    def some_method(cls, x, y):
        return x + y;
Loading history...
79
        """Return the process sort key"""
80
        # Process sort depending on alert type
81
        if event_type.startswith("MEM"):
82
            # Sort TOP process by memory_percent
83
            ret = 'memory_percent'
84
        elif event_type.startswith("CPU_IOWAIT"):
85
            # Sort TOP process by io_counters (only for Linux OS)
86
            ret = 'io_counters'
87
        else:
88
            # Default sort is...
89
            ret = 'cpu_percent'
90
        return ret
91
92
    def set_process_sort(self, event_type):
93
        """Define the process auto sort key from the alert type."""
94
        if glances_processes.auto_sort:
95
            glances_processes.sort_key = self.get_event_sort_key(event_type)
96
97
    def reset_process_sort(self):
0 ignored issues
show
Coding Style introduced by
This method could be written as a function/class method.

If a method does not access any attributes of the class, it could also be implemented as a function or static method. This can help improve readability. For example

class Foo:
    def some_method(self, x, y):
        return x + y;

could be written as

class Foo:
    @classmethod
    def some_method(cls, x, y):
        return x + y;
Loading history...
98
        """Reset the process auto sort key."""
99
        if glances_processes.auto_sort:
100
            glances_processes.sort_key = 'cpu_percent'
101
102
    def add(self, event_state, event_type, event_value,
0 ignored issues
show
best-practice introduced by
Too many arguments (7/5)
Loading history...
103
            proc_list=None, proc_desc="", peak_time=6):
104
        """Add a new item to the logs list.
105
106
        If 'event' is a 'new one', add it at the beginning of the list.
107
        If 'event' is not a 'new one', update the list .
108
        If event < peak_time then the alert is not set.
109
        """
110
        proc_list = proc_list or glances_processes.getlist()
111
112
        # Add or update the log
113
        event_index = self.__event_exist(event_type)
114
        if event_index < 0:
115
            # Event did not exist, add it
116
            self._create_event(event_state, event_type, event_value,
117
                               proc_list, proc_desc, peak_time)
118
        else:
119
            # Event exist, update it
120
            self._update_event(event_index, event_state, event_type, event_value,
0 ignored issues
show
Coding Style introduced by
This line is too long as per the coding-style (81/80).

This check looks for lines that are too long. You can specify the maximum line length.

Loading history...
121
                               proc_list, proc_desc, peak_time)
122
123
        return self.len()
124
125
    def _create_event(self, event_state, event_type, event_value,
0 ignored issues
show
best-practice introduced by
Too many arguments (7/5)
Loading history...
126
                      proc_list, proc_desc, peak_time):
0 ignored issues
show
Unused Code introduced by
The argument proc_list seems to be unused.
Loading history...
Unused Code introduced by
The argument peak_time seems to be unused.
Loading history...
127
        """Add a new item in the log list.
128
129
        Item is added only if the criticity (event_state) is WARNING or CRITICAL.
0 ignored issues
show
Coding Style introduced by
This line is too long as per the coding-style (81/80).

This check looks for lines that are too long. You can specify the maximum line length.

Loading history...
130
        """
131
        if event_state == "WARNING" or event_state == "CRITICAL":
132
            # Define the automatic process sort key
133
            self.set_process_sort(event_type)
134
135
            # Create the new log item
136
            # Time is stored in Epoch format
137
            # Epoch -> DMYHMS = datetime.fromtimestamp(epoch)
138
            item = [
139
                time.mktime(datetime.now().timetuple()),  # START DATE
140
                -1,  # END DATE
141
                event_state,  # STATE: WARNING|CRITICAL
142
                event_type,  # TYPE: CPU, LOAD, MEM...
143
                event_value,  # MAX
144
                event_value,  # AVG
145
                event_value,  # MIN
146
                event_value,  # SUM
147
                1,  # COUNT
148
                [],  # TOP 3 PROCESS LIST
149
                proc_desc,  # MONITORED PROCESSES DESC
150
                glances_processes.sort_key]  # TOP PROCESS SORTKEY
151
152
            # Add the item to the list
153
            self.events_list.insert(0, item)
154
155
            # Limit the list to 'events_max' items
156
            if self.len() > self.events_max:
157
                self.events_list.pop()
158
159
            return True
160
        else:
161
            return False
162
163
    def _update_event(self, event_index, event_state, event_type, event_value,
0 ignored issues
show
best-practice introduced by
Too many arguments (8/5)
Loading history...
164
                      proc_list, proc_desc, peak_time):
165
        """Update an event in the list"""
166
        if event_state == "OK" or event_state == "CAREFUL":
167
            # Reset the automatic process sort key
168
            self.reset_process_sort()
169
170
            # Set the end of the events
171
            endtime = time.mktime(datetime.now().timetuple())
172
            if endtime - self.events_list[event_index][0] > peak_time:
173
                # If event is > peak_time seconds
174
                self.events_list[event_index][1] = endtime
175
            else:
176
                # If event <= peak_time seconds, ignore
177
                self.events_list.remove(self.events_list[event_index])
178
        else:
179
            # Update the item
180
            self.set_process_sort(event_type)
181
182
            # State
183
            if event_state == "CRITICAL":
184
                self.events_list[event_index][2] = event_state
185
            # Min value
186
            self.events_list[event_index][6] = min(self.events_list[event_index][6],
0 ignored issues
show
Coding Style introduced by
This line is too long as per the coding-style (84/80).

This check looks for lines that are too long. You can specify the maximum line length.

Loading history...
187
                                                   event_value)
188
            # Max value
189
            self.events_list[event_index][4] = max(self.events_list[event_index][4],
0 ignored issues
show
Coding Style introduced by
This line is too long as per the coding-style (84/80).

This check looks for lines that are too long. You can specify the maximum line length.

Loading history...
190
                                                   event_value)
191
            # Average value
192
            self.events_list[event_index][7] += event_value
193
            self.events_list[event_index][8] += 1
194
            self.events_list[event_index][5] = (self.events_list[event_index][7] /
0 ignored issues
show
Coding Style introduced by
This line is too long as per the coding-style (82/80).

This check looks for lines that are too long. You can specify the maximum line length.

Loading history...
introduced by
division w/o __future__ statement
Loading history...
195
                                                self.events_list[event_index][8])
0 ignored issues
show
Coding Style introduced by
This line is too long as per the coding-style (81/80).

This check looks for lines that are too long. You can specify the maximum line length.

Loading history...
196
197
            # TOP PROCESS LIST (only for CRITICAL ALERT)
198
            if event_state == "CRITICAL":
199
                events_sort_key = self.get_event_sort_key(event_type)
200
                # Sort the current process list to retreive the TOP 3 processes
201
                self.events_list[event_index][9] = sort_stats(proc_list,
202
                                                              events_sort_key)[0:3]
0 ignored issues
show
Coding Style introduced by
This line is too long as per the coding-style (83/80).

This check looks for lines that are too long. You can specify the maximum line length.

Loading history...
203
                self.events_list[event_index][11] = events_sort_key
204
205
            # MONITORED PROCESSES DESC
206
            self.events_list[event_index][10] = proc_desc
207
208
        return True
209
210
    def clean(self, critical=False):
211
        """Clean the logs list by deleting finished items.
212
213
        By default, only delete WARNING message.
214
        If critical = True, also delete CRITICAL message.
215
        """
216
        # Create a new clean list
217
        clean_events_list = []
218
        while self.len() > 0:
219
            item = self.events_list.pop()
220
            if item[1] < 0 or (not critical and item[2].startswith("CRITICAL")):
221
                clean_events_list.insert(0, item)
222
        # The list is now the clean one
223
        self.events_list = clean_events_list
224
        return self.len()
225
226
227
glances_events = GlancesEvents()
0 ignored issues
show
Coding Style Naming introduced by
The name glances_events does not conform to the constant naming conventions ((([A-Z_][A-Z0-9_]*)|(__.*__))$).

This check looks for invalid names for a range of different identifiers.

You can set regular expressions to which the identifiers must conform if the defaults do not match your requirements.

If your project includes a Pylint configuration file, the settings contained in that file take precedence.

To find out more about Pylint, please refer to their site.

Loading history...
228