diff options
Diffstat (limited to 'glances/plugins/glances_plugin.py')
-rw-r--r-- | glances/plugins/glances_plugin.py | 131 |
1 files changed, 104 insertions, 27 deletions
diff --git a/glances/plugins/glances_plugin.py b/glances/plugins/glances_plugin.py index 48cc7cd3..98bec585 100644 --- a/glances/plugins/glances_plugin.py +++ b/glances/plugins/glances_plugin.py @@ -27,11 +27,12 @@ import re import json from operator import itemgetter -from glances.compat import iterkeys, itervalues, listkeys, map +from glances.compat import iterkeys, itervalues, listkeys, map, mean from glances.actions import GlancesActions from glances.history import GlancesHistory from glances.logger import logger from glances.logs import glances_logs +from glances.thresholds import glances_thresholds class GlancesPlugin(object): @@ -39,7 +40,28 @@ class GlancesPlugin(object): """Main class for Glances plugin.""" def __init__(self, args=None, items_history_list=None): - """Init the plugin of plugins class.""" + """Init the plugin of plugins class. + + All Glances' plugins should inherit from this class. Most of the + methods are already implemented in the father classes. + + Your plugin should return a dict or a list of dicts (stored in the + self.stats). As an example, you can have a look on the mem plugin + (for dict) or network (for list of dicts). + + A plugin should implement: + - the __init__ constructor: define the self.display_curse + - the reset method: to set your self.stats variable to {} or [] + - the update method: where your self.stats variable is set + and optionnaly: + - the get_key method: set the key of the dict (only for list of dict) + - the update_view method: only if you need to trick your output + - the msg_curse: define the curse (UI) message (if display_curse is True) + + :args: args parameters + :items_history_list: list of items to store in the history + """ + # Plugin name (= module name without glances_) self.plugin_name = self.__class__.__module__[len('glances_'):] # logger.debug("Init plugin %s" % self.plugin_name) @@ -54,9 +76,6 @@ class GlancesPlugin(object): self._input_method = 'local' self._short_system_name = None - # Init the stats list - self.stats = None - # Init the history list self.items_history_list = items_history_list self.stats_history = self.init_stats_history() @@ -70,9 +89,9 @@ class GlancesPlugin(object): # Init the views self.views = dict() - def exit(self): - """Method to be called when Glances exit""" - logger.debug("Stop the {} plugin".format(self.plugin_name)) + # Init the stats (dict of list or dict) + self.stats = None + self.reset() def __repr__(self): """Return the raw stats.""" @@ -82,6 +101,15 @@ class GlancesPlugin(object): """Return the human-readable stats.""" return str(self.stats) + def reset(self): + """Reset the stats. + This method should be overwrited by childs' classes""" + self.stats = None + + def exit(self): + """Method to be called when Glances exit""" + logger.debug("Stop the {} plugin".format(self.plugin_name)) + def get_key(self): """Return the key of the list.""" return None @@ -156,12 +184,13 @@ class GlancesPlugin(object): """Return the items history list.""" return self.items_history_list - def get_raw_history(self, item=None): + def get_raw_history(self, item=None, nb=0): """Return - the stats history (dict of list) if item is None - the stats history for the given item (list) instead - - None if item did not exist in the history""" - s = self.stats_history.get() + - None if item did not exist in the history + Limit to lasts nb items (all if nb=0)""" + s = self.stats_history.get(nb=nb) if item is None: return s else: @@ -215,6 +244,17 @@ class GlancesPlugin(object): else: return None + def get_trend(self, item, nb=6): + """Get the trend regarding to the last nb values + The trend is the diff between the mean of the last nb values + and the current one. + """ + raw_history = self.get_raw_history(item=item, nb=nb) + if raw_history is None or len(raw_history) < nb: + return None + last_nb = [v[1] for v in raw_history] + return last_nb[-1] - mean(last_nb[:-1]) + @property def input_method(self): """Get the input method.""" @@ -417,6 +457,10 @@ class GlancesPlugin(object): else: return 'DEFAULT' + def get_json_views(self, item=None, key=None, option=None): + """Return views in JSON""" + return self._json_dumps(self.get_views(item, key, option)) + def load_limits(self, config): """Load limits from the configuration file, if it exists.""" @@ -533,12 +577,22 @@ class GlancesPlugin(object): # Add the log to the list glances_logs.add(ret, stat_name.upper(), value) + # Manage threshold + self.manage_threshold(stat_name, ret) + # Manage action self.manage_action(stat_name, ret.lower(), header, action_key) - # Default is ok + # Default is 'OK' return ret + log_str + def manage_threshold(self, + stat_name, + trigger): + """Manage the threshold for the current stat""" + glances_thresholds.add(stat_name, trigger) + # logger.info(glances_thresholds.get()) + def manage_action(self, stat_name, trigger, @@ -547,7 +601,7 @@ class GlancesPlugin(object): """Manage the action for the current stat""" # Here is a command line for the current trigger ? try: - command = self.get_limit_action(trigger, stat_name=stat_name) + command, repeat = self.get_limit_action(trigger, stat_name=stat_name) except KeyError: # Reset the trigger self.actions.set(stat_name, trigger) @@ -572,7 +626,8 @@ class GlancesPlugin(object): mustache_dict = self.get_stats_action() # 2) Run the action self.actions.run( - stat_name, trigger, command, mustache_dict=mustache_dict) + stat_name, trigger, + command, repeat, mustache_dict=mustache_dict) def get_alert_log(self, current=0, @@ -605,18 +660,22 @@ class GlancesPlugin(object): return limit def get_limit_action(self, criticity, stat_name=""): - """Return the action for the alert.""" + """Return the tuple (action, repeat) for the alert. + - action is a command line + - repeat is a bool""" # Get the action for stat + header # Exemple: network_wlan0_rx_careful_action - try: - ret = self._limits[stat_name + '_' + criticity + '_action'] - except KeyError: - # Try fallback to plugin default limit - # Exemple: network_careful_action - ret = self._limits[self.plugin_name + '_' + criticity + '_action'] - - # Return the action list - return ret + # Action key available ? + ret = [(stat_name + '_' + criticity + '_action', False), + (stat_name + '_' + criticity + '_action_repeat', True), + (self.plugin_name + '_' + criticity + '_action', False), + (self.plugin_name + '_' + criticity + '_action_repeat', True)] + for r in ret: + if r[0] in self._limits: + return self._limits[r[0]], r[1] + + # No key found, the raise an error + raise KeyError def get_limit_log(self, stat_name, default_action=False): """Return the log tag for the alert.""" @@ -750,7 +809,10 @@ class GlancesPlugin(object): """ self._align = value - def auto_unit(self, number, low_precision=False): + def auto_unit(self, number, + low_precision=False, + min_symbol='K' + ): """Make a nice human-readable string out of number. Number of decimal places increases as quantity approaches 1. @@ -764,10 +826,13 @@ class GlancesPlugin(object): CASE: 1073741824 RESULT: 1024M low_precision: 1024M CASE: 1181116006 RESULT: 1.10G low_precision: 1.1G - 'low_precision=True' returns less decimal places potentially - sacrificing precision for more readability. + :low_precision: returns less decimal places potentially (default is False) + sacrificing precision for more readability. + :min_symbol: Do not approache if number < min_symbol (default is K) """ symbols = ('K', 'M', 'G', 'T', 'P', 'E', 'Z', 'Y') + if min_symbol in symbols: + symbols = symbols[symbols.index(min_symbol):] prefix = { 'Y': 1208925819614629174706176, 'Z': 1180591620717411303424, @@ -798,6 +863,18 @@ class GlancesPlugin(object): value, decimal=decimal_precision, symbol=symbol) return '{!s}'.format(number) + def trend_msg(self, trend, significant=1): + """Return the trend message + Do not take into account if trend < significant""" + ret = '-' + if trend is None: + ret = ' ' + elif trend > significant: + ret = '/' + elif trend < -significant: + ret = '\\' + return ret + def _check_decorator(fct): """Check if the plugin is enabled.""" def wrapper(self, *args, **kw): |