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 |
||
23 | from datetime import datetime |
||
24 | |||
25 | from glances.compat import range |
||
26 | from glances.processes import glances_processes, sort_stats |
||
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
|
|||
75 | return i |
||
76 | return -1 |
||
77 | |||
78 | def get_event_sort_key(self, event_type): |
||
0 ignored issues
–
show
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
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, |
||
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
|
|||
121 | proc_list, proc_desc, peak_time) |
||
122 | |||
123 | return self.len() |
||
124 | |||
125 | def _create_event(self, event_state, event_type, event_value, |
||
126 | proc_list, proc_desc, peak_time): |
||
0 ignored issues
–
show
|
|||
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
|
|||
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, |
||
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
|
|||
187 | event_value) |
||
188 | # Max value |
||
189 | self.events_list[event_index][4] = max(self.events_list[event_index][4], |
||
0 ignored issues
–
show
|
|||
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
|
|||
195 | self.events_list[event_index][8]) |
||
0 ignored issues
–
show
|
|||
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
|
|||
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
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 |
This check looks for lines that are too long. You can specify the maximum line length.