# -*- coding: utf-8 -*-
|
|
#
|
|
# This file is part of Glances.
|
|
#
|
|
# Copyright (C) 2018 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 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()
|