summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorNicolas Hennion <nicolas@nicolargo.com>2014-02-23 17:06:03 +0100
committerNicolas Hennion <nicolas@nicolargo.com>2014-02-23 17:06:03 +0100
commit471b04fe85fb4f8fa41f21449fe7d503399aba2f (patch)
tree0ddaab7c9d1adad63b5bddc0e813ec4f2f96a06c
parent8b93077e1a9c6fd1bcd6abdcd183e59a485bd698 (diff)
First commit for the Alert module
-rw-r--r--glances/README.txt36
-rw-r--r--glances/core/glances_globals.py6
-rw-r--r--glances/core/glances_logs.py181
-rw-r--r--glances/core/glances_standalone.py2
-rw-r--r--glances/plugins/glances_alert.py71
-rw-r--r--glances/plugins/glances_cpu.py8
-rw-r--r--glances/plugins/glances_diskio.py2
-rw-r--r--glances/plugins/glances_plugin.py39
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=""):