|
|
- # -*- 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/>.
-
- """The stats manager."""
-
- import collections
- import os
- import sys
- import threading
- import traceback
-
- from glances.globals import exports_path, plugins_path, sys_path
- from glances.logger import logger
-
-
- class GlancesStats(object):
-
- """This class stores, updates and gives stats."""
-
- # Script header constant
- header = "glances_"
-
- def __init__(self, config=None, args=None):
- # Set the config instance
- self.config = config
-
- # Set the argument instance
- self.args = args
-
- # Load plugins and exports modules
- self.load_modules(self.args)
-
- # Load the limits (for plugins)
- self.load_limits(self.config)
-
- def __getattr__(self, item):
- """Overwrite the getattr method in case of attribute is not found.
-
- The goal is to dynamically generate the following methods:
- - getPlugname(): return Plugname stat in JSON format
- - getViewsPlugname(): return views of the Plugname stat in JSON format
- """
- # Check if the attribute starts with 'get'
- if item.startswith('getViews'):
- # Get the plugin name
- plugname = item[len('getViews'):].lower()
- # Get the plugin instance
- plugin = self._plugins[plugname]
- if hasattr(plugin, 'get_json_views'):
- # The method get_views exist, return it
- return getattr(plugin, 'get_json_views')
- else:
- # The method get_views is not found for the plugin
- raise AttributeError(item)
- elif item.startswith('get'):
- # Get the plugin name
- plugname = item[len('get'):].lower()
- # Get the plugin instance
- plugin = self._plugins[plugname]
- if hasattr(plugin, 'get_stats'):
- # The method get_stats exist, return it
- return getattr(plugin, 'get_stats')
- else:
- # The method get_stats is not found for the plugin
- raise AttributeError(item)
- else:
- # Default behavior
- raise AttributeError(item)
-
- def load_modules(self, args):
- """Wrapper to load: plugins and export modules."""
-
- # Init the plugins dict
- # Active plugins dictionnary
- self._plugins = collections.defaultdict(dict)
- # Load the plugins
- self.load_plugins(args=args)
-
- # Init the export modules dict
- # Active exporters dictionnary
- self._exports = collections.defaultdict(dict)
- # All available exporters dictionnary
- self._exports_all = collections.defaultdict(dict)
- # Load the export modules
- self.load_exports(args=args)
-
- # Restoring system path
- sys.path = sys_path
-
- def _load_plugin(self, plugin_script, args=None, config=None):
- """Load the plugin (script), init it and add to the _plugin dict."""
- # The key is the plugin name
- # for example, the file glances_xxx.py
- # generate self._plugins_list["xxx"] = ...
- name = plugin_script[len(self.header):-3].lower()
- try:
- # Import the plugin
- plugin = __import__(plugin_script[:-3])
- # Init and add the plugin to the dictionary
- if name in ('help', 'amps', 'ports'):
- self._plugins[name] = plugin.Plugin(args=args, config=config)
- else:
- self._plugins[name] = plugin.Plugin(args=args)
- # Set the disable_<name> to False by default
- if self.args is not None:
- setattr(self.args,
- 'disable_' + name,
- getattr(self.args, 'disable_' + name, False))
- except Exception as e:
- # If a plugin can not be log, display a critical message
- # on the console but do not crash
- logger.critical("Error while initializing the {} plugin ({})".format(name, e))
- logger.error(traceback.format_exc())
-
- def load_plugins(self, args=None):
- """Load all plugins in the 'plugins' folder."""
- for item in os.listdir(plugins_path):
- if (item.startswith(self.header) and
- item.endswith(".py") and
- item != (self.header + "plugin.py")):
- # Load the plugin
- self._load_plugin(os.path.basename(item),
- args=args, config=self.config)
-
- # Log plugins list
- logger.debug("Active plugins list: {}".format(self.getPluginsList()))
-
- def load_exports(self, args=None):
- """Load all export modules in the 'exports' folder."""
- if args is None:
- return False
- header = "glances_"
- # Build the export module available list
- args_var = vars(locals()['args'])
- for item in os.listdir(exports_path):
- export_name = os.path.basename(item)[len(header):-3].lower()
- if (item.startswith(header) and
- item.endswith(".py") and
- item != (header + "export.py") and
- item != (header + "history.py")):
- self._exports_all[export_name] = os.path.basename(item)[:-3]
- # Set the disable_<name> to False by default
- setattr(self.args,
- 'export_' + export_name,
- getattr(self.args, 'export_' + export_name, False))
-
- # Aim is to check if the export module should be loaded
- for export_name in self._exports_all:
- if getattr(self.args, 'export_' + export_name, False):
- # Import the export module
- export_module = __import__(self._exports_all[export_name])
- # Add the export to the dictionary
- # The key is the module name
- # for example, the file glances_xxx.py
- # generate self._exports_list["xxx"] = ...
- self._exports[export_name] = export_module.Export(args=args,
- config=self.config)
- self._exports_all[export_name] = self._exports[export_name]
-
- # Log plugins list
- logger.debug("Active exports modules list: {}".format(self.getExportsList()))
- return True
-
- def getPluginsList(self, enable=True):
- """Return the plugins list.
-
- if enable is True, only return the active plugins (default)
- if enable is False, return all the plugins
-
- Return: list of plugin name
- """
- if enable:
- return [p for p in self._plugins if self._plugins[p].is_enable()]
- else:
- return [p for p in self._plugins]
-
- def getExportsList(self, enable=True):
- """Return the exports list.
-
- if enable is True, only return the active exporters (default)
- if enable is False, return all the exporters
-
- Return: list of export module name
- """
- if enable:
- return [e for e in self._exports]
- else:
- return [e for e in self._exports_all]
-
- def load_limits(self, config=None):
- """Load the stats limits (except the one in the exclude list)."""
- # For each plugins, call the load_limits method
- for p in self._plugins:
- self._plugins[p].load_limits(config)
-
- def update(self):
- """Wrapper method to update the stats."""
- # For standalone and server modes
- # For each plugins, call the update method
- for p in self._plugins:
- if self._plugins[p].is_disable():
- # If current plugin is disable
- # then continue to next plugin
- continue
- # Update the stats...
- self._plugins[p].update()
- # ... the history
- self._plugins[p].update_stats_history()
- # ... and the views
- self._plugins[p].update_views()
-
- def export(self, input_stats=None):
- """Export all the stats.
-
- Each export module is ran in a dedicated thread.
- """
- # threads = []
- input_stats = input_stats or {}
-
- for e in self._exports:
- logger.debug("Export stats using the %s module" % e)
- thread = threading.Thread(target=self._exports[e].update,
- args=(input_stats,))
- # threads.append(thread)
- thread.start()
-
- def getAll(self):
- """Return all the stats (list)."""
- return [self._plugins[p].get_raw() for p in self._plugins]
-
- def getAllAsDict(self):
- """Return all the stats (dict)."""
- return {p: self._plugins[p].get_raw() for p in self._plugins}
-
- def getAllExports(self):
- """
- Return all the stats to be exported (list).
- Default behavor is to export all the stat
- """
- return [self._plugins[p].get_export() for p in self._plugins]
-
- def getAllExportsAsDict(self, plugin_list=None):
- """
- Return all the stats to be exported (list).
- Default behavor is to export all the stat
- if plugin_list is provided, only export stats of given plugin (list)
- """
- if plugin_list is None:
- # All plugins should be exported
- plugin_list = self._plugins
- return {p: self._plugins[p].get_export() for p in plugin_list}
-
- def getAllLimits(self):
- """Return the plugins limits list."""
- return [self._plugins[p].limits for p in self._plugins]
-
- def getAllLimitsAsDict(self, plugin_list=None):
- """
- Return all the stats limits (dict).
- Default behavor is to export all the limits
- if plugin_list is provided, only export limits of given plugin (list)
- """
- if plugin_list is None:
- # All plugins should be exported
- plugin_list = self._plugins
- return {p: self._plugins[p].limits for p in plugin_list}
-
- def getAllViews(self):
- """Return the plugins views."""
- return [self._plugins[p].get_views() for p in self._plugins]
-
- def getAllViewsAsDict(self):
- """Return all the stats views (dict)."""
- return {p: self._plugins[p].get_views() for p in self._plugins}
-
- def get_plugin_list(self):
- """Return the plugin list."""
- return self._plugins
-
- def get_plugin(self, plugin_name):
- """Return the plugin name."""
- if plugin_name in self._plugins:
- return self._plugins[plugin_name]
- else:
- return None
-
- def end(self):
- """End of the Glances stats."""
- # Close export modules
- for e in self._exports:
- self._exports[e].exit()
- # Close plugins
- for p in self._plugins:
- self._plugins[p].exit()
|