diff options
author | Nicolas Hennion <nicolas@nicolargo.com> | 2014-02-23 17:06:03 +0100 |
---|---|---|
committer | Nicolas Hennion <nicolas@nicolargo.com> | 2014-02-23 17:06:03 +0100 |
commit | 471b04fe85fb4f8fa41f21449fe7d503399aba2f (patch) | |
tree | 0ddaab7c9d1adad63b5bddc0e813ec4f2f96a06c | |
parent | 8b93077e1a9c6fd1bcd6abdcd183e59a485bd698 (diff) |
First commit for the Alert module
-rw-r--r-- | glances/README.txt | 36 | ||||
-rw-r--r-- | glances/core/glances_globals.py | 6 | ||||
-rw-r--r-- | glances/core/glances_logs.py | 181 | ||||
-rw-r--r-- | glances/core/glances_standalone.py | 2 | ||||
-rw-r--r-- | glances/plugins/glances_alert.py | 71 | ||||
-rw-r--r-- | glances/plugins/glances_cpu.py | 8 | ||||
-rw-r--r-- | glances/plugins/glances_diskio.py | 2 | ||||
-rw-r--r-- | glances/plugins/glances_plugin.py | 39 |
8 files changed, 310 insertions, 35 deletions
diff --git a/glances/README.txt b/glances/README.txt index a4fac1a0..2cbb4004 100644 --- a/glances/README.txt +++ b/glances/README.txt @@ -5,24 +5,28 @@ If you are lookink for user manual, please follow this link: https://github.com/ === -__init__.py Global module init -__main__.py Entry point for module +__init__.py Global module init +__main__.py Entry point for module core/ - glances_main.py Main script to rule them up... - glances_globals.py Share variables uppon modules - glances_config.py Manage configuration file - glances_timer.py Manage timer - glances_stats.py Inteface to grab stats - glances_client.py Glances client - glances_server.py Glances_server + glances_config.py Manage configuration file + glances_globals.py Share variables uppon modules + glances_limits.py Manage limits + glances_logs.py Manage logs + glances_main.py Main script to rule them up... + glances_stats.py Inteface to grab stats + glances_client.py Glances client + glances_server.py Glances server + glances_standalone.py Glances standalone (with curse interface) + glances_stats.py The stats manager + glances_timer.py Manage timer plugins/ - glances_plugins.py "Father class" for others plugins - glances_cpu.py Manage CPU stats - glances_load.py Manage LOAD stats - glances_mem.py Manage MEM (both RAM and SWAP) stats + glances_plugins.py "Father class" for others plugins + glances_cpu.py Manage CPU stats + glances_load.py Manage LOAD stats + glances_mem.py Manage MEM (both RAM and SWAP) stats ... outputs/ - glances_curse.py The Curse (console) interface - glances_csv.py The CSV interface - glances_html.py The HTML interface + glances_curse.py The Curse interface + glances_csv.py The CSV interface + glances_html.py The HTML interface ... diff --git a/glances/core/glances_globals.py b/glances/core/glances_globals.py index 13165c77..3eaf978f 100644 --- a/glances/core/glances_globals.py +++ b/glances/core/glances_globals.py @@ -30,6 +30,9 @@ import os import gettext import locale +# Import Glances libs +from ..core.glances_logs import glancesLogs + # Import PsUtil try: from psutil import __version__ as __psutil_version__ @@ -74,3 +77,6 @@ elif os.path.exists(sys_i18n_path): else: locale_dir = None gettext.install(gettext_domain, locale_dir) + +# Logs instance share between all scripts +glances_logs = glancesLogs() diff --git a/glances/core/glances_logs.py b/glances/core/glances_logs.py new file mode 100644 index 00000000..60a8cec3 --- /dev/null +++ b/glances/core/glances_logs.py @@ -0,0 +1,181 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- +# +# Glances - An eye on your system +# +# Copyright (C) 2014 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/>. + +# Import system libs +import time +from datetime import datetime + +class glancesLogs: + """ + Manage 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"] + """ + + def __init__(self): + """ + Init the logs class + """ + + # Maximum size of the logs list + self.logs_max = 10 + + # Init the logs list + self.logs_list = [] + + # Automaticaly define the sort to apply on the processes list + self.sort_process_by = 'none' + + + def get(self): + """ + Return the logs list (RAW) + """ + return self.logs_list + + + def len(self): + """ + Return the number of item in the log list + """ + return self.logs_list.__len__() + + + def __itemexist__(self, item_type): + """ + An item exist in the list if: + * end is < 0 + * item_type is matching + """ + 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 add(self, item_state, item_type, item_value, proc_list=[], proc_desc=""): + """ + If item is a 'new one': + Add the new item at the beginning of the logs list + Else: + Update the existing item + """ + # Add Top process sort depending on alert type + self.sort_process_by = 'none' + if (item_type.startswith("MEM")): + # Sort TOP process by memory_percent + self.sort_process_by = 'memory_percent' + elif (item_type.startswith("CPU IO")): + # Sort TOP process by io_counters (only for Linux OS) + self.sort_process_by = 'io_counters' + elif (item_type.startswith("MON")): + # Do no sort process for monitored prcesses list + self.sort_process_by = 'none' + else: + # Default TOP process sort is cpu_percent + self.sort_process_by = 'cpu_percent' + + # Sort processes + if (self.sort_process_by != 'none'): + topprocess = sorted(proc_list, key=lambda process: process[self.sort_process_by], + reverse=True) + else: + topprocess = proc_list + + # Add or update the log + item_index = self.__itemexist__(item_type) + if (item_index < 0): + # Item did not exist, add if WARNING or CRITICAL + if ((item_state == "WARNING") or (item_state == "CRITICAL")): + # Time is stored in Epoch format + # Epoch -> DMYHMS = datetime.fromtimestamp(epoch) + item = [] + # START DATE + item.append(time.mktime(datetime.now().timetuple())) + # END DATE + item.append(-1) + item.append(item_state) # STATE: WARNING|CRITICAL + item.append(item_type) # TYPE: CPU, LOAD, MEM... + item.append(item_value) # MAX + item.append(item_value) # AVG + item.append(item_value) # MIN + item.append(item_value) # SUM + item.append(1) # COUNT + item.append(topprocess[0:3]) # TOP 3 PROCESS LIST + item.append(proc_desc) # MONITORED PROCESSES DESC + self.logs_list.insert(0, item) + if self.len() > self.logs_max: + self.logs_list.pop() + else: + # Item exist, update + if ((item_state == "OK") or (item_state == "CAREFUL")): + # Close the item + self.logs_list[item_index][1] = time.mktime( + datetime.now().timetuple()) + # TOP PROCESS LIST + self.logs_list[item_index][9] = [] + 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 + 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 + self.logs_list[item_index][9] = topprocess[0:3] + # MONITORED PROCESSES DESC + self.logs_list[item_index][10] = proc_desc + + return self.len() + + + def clean(self, critical=False): + """ + Clean the log list by deleting finished item + 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] == "CRITICAL"): + clean_logs_list.insert(0, item) + # The list is now the clean one + self.logs_list = clean_logs_list + return self.len() diff --git a/glances/core/glances_standalone.py b/glances/core/glances_standalone.py index 40fab08f..f1a5af06 100644 --- a/glances/core/glances_standalone.py +++ b/glances/core/glances_standalone.py @@ -50,7 +50,7 @@ class GlancesStandalone(): self.stats = GlancesStats(config) # Initial update - # !!! The first time Glances display wrong CPU information + # !!! The first time Glances display wrong CPU/MEM information self.stats.update() self.refresh_time = args.time diff --git a/glances/plugins/glances_alert.py b/glances/plugins/glances_alert.py new file mode 100644 index 00000000..e6c37986 --- /dev/null +++ b/glances/plugins/glances_alert.py @@ -0,0 +1,71 @@ +#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+#
+# Glances - An eye on your system
+#
+# Copyright (C) 2014 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/>.
+
+# Import Glances lib
+from glances_plugin import GlancesPlugin
+from glances.core.glances_globals import glances_logs
+
+
+class Plugin(GlancesPlugin):
+ """
+ Glances's alert Plugin
+
+ Only for display
+ """
+
+ def __init__(self):
+ GlancesPlugin.__init__(self)
+
+ # We want to display the stat in the curse interface
+ self.display_curse = True
+ # Set the message position
+ # It is NOT the curse position but the Glances column/line
+ # Enter -1 to right align
+ self.column_curse = 1
+ # Enter -1 to diplay bottom
+ self.line_curse = 4
+
+
+ def update(self):
+ """
+ Nothing to do here
+ Just return the global glances_log
+ """
+
+ self.stats = glances_logs.get()
+
+
+ def msg_curse(self, args=None):
+ """
+ Return the dict to display in the curse interface
+ """
+ # Init the return message
+ ret = []
+
+ # Build the string message
+ # Header
+ if (self.stats == []):
+ msg = "{0:8}".format(_("No alert detected"))
+ ret.append(self.curse_add_line(msg, "TITLE"))
+ else:
+ msg = "{0:8}".format(_("ALERT"))
+ ret.append(self.curse_add_line(msg, "TITLE"))
+
+ return ret
diff --git a/glances/plugins/glances_cpu.py b/glances/plugins/glances_cpu.py index 3966728b..72eedaff 100644 --- a/glances/plugins/glances_cpu.py +++ b/glances/plugins/glances_cpu.py @@ -25,6 +25,7 @@ from psutil import cpu_times, cpu_times_percent # from ..plugins.glances_plugin import GlancesPlugin
from glances_plugin import GlancesPlugin
+
class Plugin(GlancesPlugin):
"""
Glances' Cpu Plugin
@@ -51,7 +52,10 @@ class Plugin(GlancesPlugin): """
# Grab CPU using the PSUtil cpu_times_percent method (PSUtil 0.7 or higher)
- cputimespercent = cpu_times_percent(interval=0, percpu=False)
+ try:
+ cputimespercent = cpu_times_percent(interval=0, percpu=False)
+ except:
+ return self.update_deprecated()
self.stats = {}
for cpu in ['user', 'system', 'idle', 'nice',
@@ -64,8 +68,8 @@ class Plugin(GlancesPlugin): def update_deprecated(self):
"""
- !!! Not used anymore...
Update CPU stats
+ Only used if cpu_times_percent failed
"""
# Grab CPU using the PSUtil cpu_times method
diff --git a/glances/plugins/glances_diskio.py b/glances/plugins/glances_diskio.py index 09e85291..a8f4344a 100644 --- a/glances/plugins/glances_diskio.py +++ b/glances/plugins/glances_diskio.py @@ -18,8 +18,10 @@ # 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/>.
+# Import system lib
from psutil import disk_io_counters
+# Import Glances lib
from glances.core.glances_globals import is_Mac
from glances_plugin import GlancesPlugin, getTimeSinceLastUpdate
diff --git a/glances/plugins/glances_plugin.py b/glances/plugins/glances_plugin.py index e15ccb9f..7cefd83c 100644 --- a/glances/plugins/glances_plugin.py +++ b/glances/plugins/glances_plugin.py @@ -18,13 +18,16 @@ # 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/>.
+# Import system libs
import json
from time import time
+# Import Glances lib
+from glances.core.glances_globals import glances_logs
+
# Global list to manage the elapsed time
last_update_times = {}
-
def getTimeSinceLastUpdate(IOType):
global last_update_times
# assert(IOType in ['net', 'disk', 'process_disk'])
@@ -112,27 +115,31 @@ class GlancesPlugin(object): except ZeroDivisionError:
return 'DEFAULT'
- # If log is enable than add _LOG to the return string
- if (log):
- log_str = "_LOG"
- else:
- log_str = ""
-
- # if (self.plugin_name == "processlist"):
- # print "*"*300
- # print self.limits
- # sys.exit(0)
-
# Manage limits
+ ret = 'OK'
if (value > self.get_limit_critical(header=header)):
- return 'CRITICAL'+log_str
+ ret = 'CRITICAL'
elif (value > self.get_limit_warning(header=header)):
- return 'WARNING'+log_str
+ ret = 'WARNING'
elif (value > self.get_limit_careful(header=header)):
- return 'CAREFUL'+log_str
+ ret = 'CAREFUL'
+
+ # Manage log (if needed)
+ log_str = ""
+ if (log):
+ # Add _LOG to the return string
+ # So stats will be highlited with a specific color
+ log_str = "_LOG"
+ # Get the stat_name = plugin_name (+ header)
+ if (header == ""):
+ stat_name = self.plugin_name
+ else:
+ stat_name = self.plugin_name + '_' + header
+ # !!! TODO: Manage the process list (last param => [])
+ glances_logs.add(ret, stat_name.upper(), value, [])
# Default is ok
- return 'OK'+log_str
+ return ret + log_str
def get_alert_log(self, current=0, min=0, max=100, header=""):
|