Completed
Push — master ( a1acfe...a11662 )
by Nicolas
01:53 queued 19s
created

GlancesStats._load_plugin()   A

Complexity

Conditions 3

Size

Total Lines 19

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 3
dl 0
loc 19
rs 9.4285
c 1
b 0
f 0
1
# -*- coding: utf-8 -*-
2
#
3
# This file is part of Glances.
4
#
5
# Copyright (C) 2017 Nicolargo <[email protected]>
6
#
7
# Glances is free software; you can redistribute it and/or modify
8
# it under the terms of the GNU Lesser General Public License as published by
9
# the Free Software Foundation, either version 3 of the License, or
10
# (at your option) any later version.
11
#
12
# Glances is distributed in the hope that it will be useful,
13
# but WITHOUT ANY WARRANTY; without even the implied warranty of
14
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15
# GNU Lesser General Public License for more details.
16
#
17
# You should have received a copy of the GNU Lesser General Public License
18
# along with this program. If not, see <http://www.gnu.org/licenses/>.
19
20
"""The stats manager."""
21
22
import collections
23
import os
24
import sys
25
import threading
26
import traceback
27
28
from glances.globals import exports_path, plugins_path, sys_path
29
from glances.logger import logger
30
31
32
class GlancesStats(object):
33
34
    """This class stores, updates and gives stats."""
35
36
    # Script header constant
37
    header = "glances_"
38
39
    def __init__(self, config=None, args=None):
40
        # Set the config instance
41
        self.config = config
42
43
        # Set the argument instance
44
        self.args = args
45
46
        # Load plugins and exports modules
47
        self.load_modules(self.args)
48
49
        # Load the limits (for plugins)
50
        self.load_limits(self.config)
51
52
    def __getattr__(self, item):
53
        """Overwrite the getattr method in case of attribute is not found.
54
55
        The goal is to dynamically generate the following methods:
56
        - getPlugname(): return Plugname stat in JSON format
57
        """
58
        # Check if the attribute starts with 'get'
59
        if item.startswith('get'):
60
            # Get the plugin name
61
            plugname = item[len('get'):].lower()
62
            # Get the plugin instance
63
            plugin = self._plugins[plugname]
64
            if hasattr(plugin, 'get_stats'):
65
                # The method get_stats exist, return it
66
                return getattr(plugin, 'get_stats')
67
            else:
68
                # The method get_stats is not found for the plugin
69
                raise AttributeError(item)
70
        else:
71
            # Default behavior
72
            raise AttributeError(item)
73
74
    def load_modules(self, args):
75
        """Wrapper to load: plugins and export modules."""
76
77
        # Init the plugins dict
78
        self._plugins = collections.defaultdict(dict)
79
80
        # Load the plugins
81
        self.load_plugins(args=args)
82
83
        # Init the export modules dict
84
        self._exports = collections.defaultdict(dict)
85
86
        # Load the export modules
87
        self.load_exports(args=args)
88
89
        # Restoring system path
90
        sys.path = sys_path
91
92
    def _load_plugin(self, plugin_script, args=None, config=None):
93
        """Load the plugin (script), init it and add to the _plugin dict"""
94
        # The key is the plugin name
95
        # for example, the file glances_xxx.py
96
        # generate self._plugins_list["xxx"] = ...
97
        name = plugin_script[len(self.header):-3].lower()
98
        try:
99
            # Import the plugin
100
            plugin = __import__(plugin_script[:-3])
101
            # Init and add the plugin to the dictionary
102
            if name in ('help', 'amps', 'ports'):
103
                self._plugins[name] = plugin.Plugin(args=args, config=config)
104
            else:
105
                self._plugins[name] = plugin.Plugin(args=args)
106
        except Exception as e:
107
            # If a plugin can not be log, display a critical message
108
            # on the console but do not crash
109
            logger.critical("Error while initializing the {} plugin ({}})".format(name, e))
110
            logger.error(traceback.format_exc())
111
112
    def load_plugins(self, args=None):
113
        """Load all plugins in the 'plugins' folder."""
114
        for item in os.listdir(plugins_path):
115
            if (item.startswith(self.header) and
116
                    item.endswith(".py") and
117
                    item != (self.header + "plugin.py")):
118
                # Load the plugin
119
                self._load_plugin(os.path.basename(item),
120
                                  args=args, config=self.config)
121
122
        # Log plugins list
123
        logger.debug("Available plugins list: {}".format(self.getAllPlugins()))
124
125
    def load_exports(self, args=None):
126
        """Load all export modules in the 'exports' folder."""
127
        if args is None:
128
            return False
129
        header = "glances_"
130
        # Transform the arguments list into a dict
131
        # The aim is to chec if the export module should be loaded
132
        args_var = vars(locals()['args'])
133
        for item in os.listdir(exports_path):
134
            export_name = os.path.basename(item)[len(header):-3].lower()
135
            if (item.startswith(header) and
136
                    item.endswith(".py") and
137
                    item != (header + "export.py") and
138
                    item != (header + "history.py") and
139
                    args_var['export_' + export_name] is not None and
140
                    args_var['export_' + export_name] is not False):
141
                # Import the export module
142
                export_module = __import__(os.path.basename(item)[:-3])
143
                # Add the export to the dictionary
144
                # The key is the module name
145
                # for example, the file glances_xxx.py
146
                # generate self._exports_list["xxx"] = ...
147
                self._exports[export_name] = export_module.Export(args=args, config=self.config)
148
        # Log plugins list
149
        logger.debug("Available exports modules list: {}".format(self.getExportList()))
150
        return True
151
152
    def getAllPlugins(self, enable=True):
153
        """Return the enable plugins list.
154
        if enable is False, return the list of all the plugins"""
155
        if enable:
156
            return [p for p in self._plugins if self._plugins[p].is_enable()]
157
        else:
158
            return [p for p in self._plugins]
159
160
    def getExportList(self):
161
        """Return the exports modules list."""
162
        return [e for e in self._exports]
163
164
    def load_limits(self, config=None):
165
        """Load the stats limits (except the one in the exclude list)."""
166
        # For each plugins, call the load_limits method
167
        for p in self._plugins:
168
            self._plugins[p].load_limits(config)
169
170
    def update(self):
171
        """Wrapper method to update the stats."""
172
        # For standalone and server modes
173
        # For each plugins, call the update method
174
        for p in self._plugins:
175
            if self._plugins[p].is_disable():
176
                # If current plugin is disable
177
                # then continue to next plugin
178
                continue
179
            # Update the stats...
180
            self._plugins[p].update()
181
            # ... the history
182
            self._plugins[p].update_stats_history()
183
            # ... and the views
184
            self._plugins[p].update_views()
185
186
    def export(self, input_stats=None):
187
        """Export all the stats.
188
189
        Each export module is ran in a dedicated thread.
190
        """
191
        # threads = []
192
        input_stats = input_stats or {}
193
194
        for e in self._exports:
195
            logger.debug("Export stats using the %s module" % e)
196
            thread = threading.Thread(target=self._exports[e].update,
197
                                      args=(input_stats,))
198
            # threads.append(thread)
199
            thread.start()
200
201
    def getAll(self):
202
        """Return all the stats (list)."""
203
        return [self._plugins[p].get_raw() for p in self._plugins]
204
205
    def getAllAsDict(self):
206
        """Return all the stats (dict)."""
207
        return {p: self._plugins[p].get_raw() for p in self._plugins}
208
209
    def getAllExports(self):
210
        """
211
        Return all the stats to be exported (list).
212
        Default behavor is to export all the stat
213
        """
214
        return [self._plugins[p].get_export() for p in self._plugins]
215
216
    def getAllExportsAsDict(self, plugin_list=None):
217
        """
218
        Return all the stats to be exported (list).
219
        Default behavor is to export all the stat
220
        if plugin_list is provided, only export stats of given plugin (list)
221
        """
222
        if plugin_list is None:
223
            # All plugins should be exported
224
            plugin_list = self._plugins
225
        return {p: self._plugins[p].get_export() for p in plugin_list}
226
227
    def getAllLimits(self):
228
        """Return the plugins limits list."""
229
        return [self._plugins[p].limits for p in self._plugins]
230
231
    def getAllLimitsAsDict(self, plugin_list=None):
232
        """
233
        Return all the stats limits (dict).
234
        Default behavor is to export all the limits
235
        if plugin_list is provided, only export limits of given plugin (list)
236
        """
237
        if plugin_list is None:
238
            # All plugins should be exported
239
            plugin_list = self._plugins
240
        return {p: self._plugins[p].limits for p in plugin_list}
241
242
    def getAllViews(self):
243
        """Return the plugins views."""
244
        return [self._plugins[p].get_views() for p in self._plugins]
245
246
    def getAllViewsAsDict(self):
247
        """Return all the stats views (dict)."""
248
        return {p: self._plugins[p].get_views() for p in self._plugins}
249
250
    def get_plugin_list(self):
251
        """Return the plugin list."""
252
        return self._plugins
253
254
    def get_plugin(self, plugin_name):
255
        """Return the plugin name."""
256
        if plugin_name in self._plugins:
257
            return self._plugins[plugin_name]
258
        else:
259
            return None
260
261
    def end(self):
262
        """End of the Glances stats."""
263
        # Close export modules
264
        for e in self._exports:
265
            self._exports[e].exit()
266
        # Close plugins
267
        for p in self._plugins:
268
            self._plugins[p].exit()
269