# -*- coding: utf-8 -*- # # This file is part of Glances. # # Copyright (C) 2018 Nicolargo # # 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 . """Manage logs.""" import time from datetime import datetime from glances.compat import range from glances.processes import glances_processes, sort_stats class GlancesLogs(object): """This class manages logs inside the Glances software. Logs is a list of list (stored in the self.logs_list var) item_state = "OK|CAREFUL|WARNING|CRITICAL" item_type = "CPU*|LOAD|MEM|MON" item_value = value Item 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 logs class.""" # Maximum size of the logs list self.logs_max = 10 # Init the logs list self.logs_list = [] def get(self): """Return the raw logs list.""" return self.logs_list def len(self): """Return the number of item in the logs list.""" return self.logs_list.__len__() def __itemexist__(self, item_type): """Return the item position, if it exists. An item exist in the list if: * end is < 0 * item_type is matching Return -1 if the item is not found. """ for i in range(self.len()): if self.logs_list[i][1] < 0 and self.logs_list[i][3] == item_type: return i return -1 def get_process_sort_key(self, item_type): """Return the process sort key""" # Process sort depending on alert type if item_type.startswith("MEM"): # Sort TOP process by memory_percent ret = 'memory_percent' elif item_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, item_type): """Define the process auto sort key from the alert type.""" glances_processes.auto_sort = True glances_processes.sort_key = self.get_process_sort_key(item_type) def reset_process_sort(self): """Reset the process auto sort key.""" # Default sort is... glances_processes.auto_sort = True glances_processes.sort_key = 'cpu_percent' def add(self, item_state, item_type, item_value, proc_list=None, proc_desc="", peak_time=6): """Add a new item to the logs list. If 'item' is a 'new one', add the new item at the beginning of the logs list. If 'item' is not a 'new one', update the existing item. If event < peak_time the the alert is not setoff. """ proc_list = proc_list or glances_processes.getlist() # Add or update the log item_index = self.__itemexist__(item_type) if item_index < 0: # Item did not exist, add if WARNING or CRITICAL self._create_item(item_state, item_type, item_value, proc_list, proc_desc, peak_time) else: # Item exist, update self._update_item(item_index, item_state, item_type, item_value, proc_list, proc_desc, peak_time) return self.len() def _create_item(self, item_state, item_type, item_value, proc_list, proc_desc, peak_time): """Create a new item in the log list""" if item_state == "WARNING" or item_state == "CRITICAL": # Define the automatic process sort key self.set_process_sort(item_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 item_state, # STATE: WARNING|CRITICAL item_type, # TYPE: CPU, LOAD, MEM... item_value, # MAX item_value, # AVG item_value, # MIN item_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.logs_list.insert(0, item) if self.len() > self.logs_max: self.logs_list.pop() return True else: return False def _update_item(self, item_index, item_state, item_type, item_value, proc_list, proc_desc, peak_time): """Update a item in the log list""" if item_state == "OK" or item_state == "CAREFUL": # Reset the automatic process sort key self.reset_process_sort() endtime = time.mktime(datetime.now().timetuple()) if endtime - self.logs_list[item_index][0] > peak_time: # If event is > peak_time seconds self.logs_list[item_index][1] = endtime else: # If event <= peak_time seconds, ignore self.logs_list.remove(self.logs_list[item_index]) else: # Update the item # State if item_state == "CRITICAL": self.logs_list[item_index][2] = item_state # Value if item_value > self.logs_list[item_index][4]: # MAX self.logs_list[item_index][4] = item_value elif item_value < self.logs_list[item_index][6]: # MIN self.logs_list[item_index][6] = item_value # AVG (compute average value) self.logs_list[item_index][7] += item_value self.logs_list[item_index][8] += 1 self.logs_list[item_index][5] = (self.logs_list[item_index][7] / self.logs_list[item_index][8]) # TOP PROCESS LIST (only for CRITICAL ALERT) if item_state == "CRITICAL": # Sort the current process list to retreive the TOP 3 processes self.logs_list[item_index][9] = sort_stats(proc_list, glances_processes.sort_key)[0:3] self.logs_list[item_index][11] = glances_processes.sort_key # MONITORED PROCESSES DESC self.logs_list[item_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_logs_list = [] while self.len() > 0: item = self.logs_list.pop() if item[1] < 0 or (not critical and item[2].startswith("CRITICAL")): clean_logs_list.insert(0, item) # The list is now the clean one self.logs_list = clean_logs_list return self.len() glances_logs = GlancesLogs()