summaryrefslogtreecommitdiffstats
path: root/glances/events.py
diff options
context:
space:
mode:
Diffstat (limited to 'glances/events.py')
-rw-r--r--glances/events.py227
1 files changed, 227 insertions, 0 deletions
diff --git a/glances/events.py b/glances/events.py
new file mode 100644
index 00000000..50356255
--- /dev/null
+++ b/glances/events.py
@@ -0,0 +1,227 @@
+# -*- coding: utf-8 -*-
+#
+# This file is part of Glances.
+#
+# Copyright (C) 2019 Nicolargo <nicolas@nicolargo.com>
+#
+# Glances is free software; you can redistribute it and/or modify
+# it under the terms of the GNU Lesser General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# Glances is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+"""Manage Glances events (previously Glances logs in Glances < 3.1)."""
+
+import time
+from datetime import datetime
+
+from glances.compat import range
+from glances.processes import glances_processes, sort_stats
+
+
+class GlancesEvents(object):
+
+ """This class manages events inside the Glances software.
+
+ Events is a list of event (stored in the self.events_list var)
+ event_state = "OK|CAREFUL|WARNING|CRITICAL"
+ event_type = "CPU*|LOAD|MEM|MON"
+ event_value = value
+
+ Item (or event) is defined by:
+ ["begin",
+ "end",
+ "WARNING|CRITICAL",
+ "CPU|LOAD|MEM",
+ MAX, AVG, MIN, SUM, COUNT,
+ [top3 process list],
+ "Processes description",
+ "top sort key"]
+ """
+
+ def __init__(self):
+ """Init the events class."""
+ # Maximum size of the events list
+ self.events_max = 10
+
+ # Init the logs list
+ self.events_list = []
+
+ def get(self):
+ """Return the raw events list."""
+ return self.events_list
+
+ def len(self):
+ """Return the number of events in the logs list."""
+ return self.events_list.__len__()
+
+ def __event_exist(self, event_type):
+ """Return the event position, if it exists.
+
+ An event exist if:
+ * end is < 0
+ * event_type is matching
+ Return -1 if the item is not found.
+ """
+ for i in range(self.len()):
+ if self.events_list[i][1] < 0 and self.events_list[i][3] == event_type:
+ return i
+ return -1
+
+ def get_event_sort_key(self, event_type):
+ """Return the process sort key"""
+ # Process sort depending on alert type
+ if event_type.startswith("MEM"):
+ # Sort TOP process by memory_percent
+ ret = 'memory_percent'
+ elif event_type.startswith("CPU_IOWAIT"):
+ # Sort TOP process by io_counters (only for Linux OS)
+ ret = 'io_counters'
+ else:
+ # Default sort is...
+ ret = 'cpu_percent'
+ return ret
+
+ def set_process_sort(self, event_type):
+ """Define the process auto sort key from the alert type."""
+ if glances_processes.auto_sort:
+ glances_processes.sort_key = self.get_event_sort_key(event_type)
+
+ def reset_process_sort(self):
+ """Reset the process auto sort key."""
+ if glances_processes.auto_sort:
+ glances_processes.sort_key = 'cpu_percent'
+
+ def add(self, event_state, event_type, event_value,
+ proc_list=None, proc_desc="", peak_time=6):
+ """Add a new item to the logs list.
+
+ If 'event' is a 'new one', add it at the beginning of the list.
+ If 'event' is not a 'new one', update the list .
+ If event < peak_time then the alert is not set.
+ """
+ proc_list = proc_list or glances_processes.getlist()
+
+ # Add or update the log
+ event_index = self.__event_exist(event_type)
+ if event_index < 0:
+ # Event did not exist, add it
+ self._create_event(event_state, event_type, event_value,
+ proc_list, proc_desc, peak_time)
+ else:
+ # Event exist, update it
+ self._update_event(event_index, event_state, event_type, event_value,
+ proc_list, proc_desc, peak_time)
+
+ return self.len()
+
+ def _create_event(self, event_state, event_type, event_value,
+ proc_list, proc_desc, peak_time):
+ """Add a new item in the log list.
+
+ Item is added only if the criticity (event_state) is WARNING or CRITICAL.
+ """
+ if event_state == "WARNING" or event_state == "CRITICAL":
+ # Define the automatic process sort key
+ self.set_process_sort(event_type)
+
+ # Create the new log item
+ # Time is stored in Epoch format
+ # Epoch -> DMYHMS = datetime.fromtimestamp(epoch)
+ item = [
+ time.mktime(datetime.now().timetuple()), # START DATE
+ -1, # END DATE
+ event_state, # STATE: WARNING|CRITICAL
+ event_type, # TYPE: CPU, LOAD, MEM...
+ event_value, # MAX
+ event_value, # AVG
+ event_value, # MIN
+ event_value, # SUM
+ 1, # COUNT
+ [], # TOP 3 PROCESS LIST
+ proc_desc, # MONITORED PROCESSES DESC
+ glances_processes.sort_key] # TOP PROCESS SORTKEY
+
+ # Add the item to the list
+ self.events_list.insert(0, item)
+
+ # Limit the list to 'events_max' items
+ if self.len() > self.events_max:
+ self.events_list.pop()
+
+ return True
+ else:
+ return False
+
+ def _update_event(self, event_index, event_state, event_type, event_value,
+ proc_list, proc_desc, peak_time):
+ """Update an event in the list"""
+ if event_state == "OK" or event_state == "CAREFUL":
+ # Reset the automatic process sort key
+ self.reset_process_sort()
+
+ # Set the end of the events
+ endtime = time.mktime(datetime.now().timetuple())
+ if endtime - self.events_list[event_index][0] > peak_time:
+ # If event is > peak_time seconds
+ self.events_list[event_index][1] = endtime
+ else:
+ # If event <= peak_time seconds, ignore
+ self.events_list.remove(self.events_list[event_index])
+ else:
+ # Update the item
+ self.set_process_sort(event_type)
+
+ # State
+ if event_state == "CRITICAL":
+ self.events_list[event_index][2] = event_state
+ # Min value
+ self.events_list[event_index][6] = min(self.events_list[event_index][6],
+ event_value)
+ # Max value
+ self.events_list[event_index][4] = max(self.events_list[event_index][4],
+ event_value)
+ # Average value
+ self.events_list[event_index][7] += event_value
+ self.events_list[event_index][8] += 1
+ self.events_list[event_index][5] = (self.events_list[event_index][7] /
+ self.events_list[event_index][8])
+
+ # TOP PROCESS LIST (only for CRITICAL ALERT)
+ if event_state == "CRITICAL":
+ events_sort_key = self.get_event_sort_key(event_type)
+ # Sort the current process list to retreive the TOP 3 processes
+ self.events_list[event_index][9] = sort_stats(proc_list,
+ events_sort_key)[0:3]
+ self.events_list[event_index][11] = events_sort_key
+
+ # MONITORED PROCESSES DESC
+ self.events_list[event_index][10] = proc_desc
+
+ return True
+
+ def clean(self, critical=False):
+ """Clean the logs list by deleting finished items.
+
+ By default, only delete WARNING message.
+ If critical = True, also delete CRITICAL message.
+ """
+ # Create a new clean list
+ clean_events_list = []
+ while self.len() > 0:
+ item = self.events_list.pop()
+ if item[1] < 0 or (not critical and item[2].startswith("CRITICAL")):
+ clean_events_list.insert(0, item)
+ # The list is now the clean one
+ self.events_list = clean_events_list
+ return self.len()
+
+
+glances_events = GlancesEvents()