Completed
Push — master ( 1806d1...053f07 )
by Nicolas
01:42
created

GlancesStats   B

Complexity

Total Complexity 50

Size/Duplication

Total Lines 201
Duplicated Lines 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
c 1
b 0
f 0
dl 0
loc 201
rs 8.6206
wmc 50

20 Methods

Rating   Name   Duplication   Size   Complexity  
B load_plugins() 0 20 6
A getAllPlugins() 0 3 2
A getAllViewsAsDict() 0 6 2
A getAllViews() 0 3 2
A getAllExports() 0 6 2
A getAllAsDict() 0 8 2
A load_plugins_and_exports() 0 14 1
A load_limits() 0 6 2
A getAll() 0 3 2
A get_plugin() 0 6 2
A __getattr__() 0 21 3
F load_exports() 0 26 9
A update() 0 7 2
A getAllLimits() 0 3 2
A end() 0 8 3
A get_plugin_list() 0 3 1
A export() 0 14 2
A getAllLimitsAsDict() 0 6 2
A getExportList() 0 3 2
A __init__() 0 12 1

How to fix   Complexity   

Complex Class

Complex classes like GlancesStats often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

1
# -*- coding: utf-8 -*-
2
#
3
# This file is part of Glances.
4
#
5
# Copyright (C) 2016 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
27
from glances.globals import exports_path, plugins_path, sys_path
28
from glances.logger import logger
29
30
31
class GlancesStats(object):
32
33
    """This class stores, updates and gives stats."""
34
35
    def __init__(self, config=None, args=None):
36
        # Set the argument instance
37
        self.args = args
38
39
        # Set the config instance
40
        self.config = config
41
42
        # Load plugins and export modules
43
        self.load_plugins_and_exports(self.args)
44
45
        # Load the limits
46
        self.load_limits(config)
47
48
    def __getattr__(self, item):
49
        """Overwrite the getattr method in case of attribute is not found.
50
51
        The goal is to dynamically generate the following methods:
52
        - getPlugname(): return Plugname stat in JSON format
53
        """
54
        # Check if the attribute starts with 'get'
55
        if item.startswith('get'):
56
            # Get the plugin name
57
            plugname = item[len('get'):].lower()
58
            # Get the plugin instance
59
            plugin = self._plugins[plugname]
60
            if hasattr(plugin, 'get_stats'):
61
                # The method get_stats exist, return it
62
                return getattr(plugin, 'get_stats')
63
            else:
64
                # The method get_stats is not found for the plugin
65
                raise AttributeError(item)
66
        else:
67
            # Default behavior
68
            raise AttributeError(item)
69
70
    def load_plugins_and_exports(self, args):
71
        """Wrapper to load both plugins and export modules."""
72
        # Init the plugins dict
73
        self._plugins = collections.defaultdict(dict)
74
        # Load the plugins
75
        self.load_plugins(args=args)
76
77
        # Init the export modules dict
78
        self._exports = collections.defaultdict(dict)
79
        # Load the export modules
80
        self.load_exports(args=args)
81
82
        # Restoring system path
83
        sys.path = sys_path
84
85
    def load_plugins(self, args=None):
86
        """Load all plugins in the 'plugins' folder."""
87
        header = "glances_"
88
        for item in os.listdir(plugins_path):
89
            if (item.startswith(header) and
90
                    item.endswith(".py") and
91
                    item != (header + "plugin.py")):
92
                # Import the plugin
93
                plugin = __import__(os.path.basename(item)[:-3])
94
                # Add the plugin to the dictionary
95
                # The key is the plugin name
96
                # for example, the file glances_xxx.py
97
                # generate self._plugins_list["xxx"] = ...
98
                plugin_name = os.path.basename(item)[len(header):-3].lower()
99
                if plugin_name == 'help':
100
                    self._plugins[plugin_name] = plugin.Plugin(args=args, config=self.config)
101
                else:
102
                    self._plugins[plugin_name] = plugin.Plugin(args=args)
103
        # Log plugins list
104
        logger.debug("Available plugins list: {0}".format(self.getAllPlugins()))
105
106
    def load_exports(self, args=None):
107
        """Load all export modules in the 'exports' folder."""
108
        if args is None:
109
            return False
110
        header = "glances_"
111
        # Transform the arguments list into a dict
112
        # The aim is to chec if the export module should be loaded
113
        args_var = vars(locals()['args'])
114
        for item in os.listdir(exports_path):
115
            export_name = os.path.basename(item)[len(header):-3].lower()
116
            if (item.startswith(header) and
117
                    item.endswith(".py") and
118
                    item != (header + "export.py") and
119
                    item != (header + "history.py") and
120
                    args_var['export_' + export_name] is not None and
121
                    args_var['export_' + export_name] is not False):
122
                # Import the export module
123
                export_module = __import__(os.path.basename(item)[:-3])
124
                # Add the export to the dictionary
125
                # The key is the module name
126
                # for example, the file glances_xxx.py
127
                # generate self._exports_list["xxx"] = ...
128
                self._exports[export_name] = export_module.Export(args=args, config=self.config)
129
        # Log plugins list
130
        logger.debug("Available exports modules list: {0}".format(self.getExportList()))
131
        return True
132
133
    def getAllPlugins(self):
134
        """Return the plugins list."""
135
        return [p for p in self._plugins]
136
137
    def getExportList(self):
138
        """Return the exports modules list."""
139
        return [p for p in self._exports]
140
141
    def load_limits(self, config=None):
142
        """Load the stats limits."""
143
        # For each plugins, call the init_limits method
144
        for p in self._plugins:
145
            # logger.debug("Load limits for %s" % p)
146
            self._plugins[p].load_limits(config)
147
148
    def update(self):
149
        """Wrapper method to update the stats."""
150
        # For standalone and server modes
151
        # For each plugins, call the update method
152
        for p in self._plugins:
153
            # logger.debug("Update %s stats" % p)
154
            self._plugins[p].update()
155
156
    def export(self, input_stats=None):
157
        """Export all the stats.
158
159
        Each export module is ran in a dedicated thread.
160
        """
161
        # threads = []
162
        input_stats = input_stats or {}
163
164
        for e in self._exports:
165
            logger.debug("Export stats using the %s module" % e)
166
            thread = threading.Thread(target=self._exports[e].update,
167
                                      args=(input_stats,))
168
            # threads.append(thread)
169
            thread.start()
170
171
    def getAll(self):
172
        """Return all the stats (list)."""
173
        return [self._plugins[p].get_raw() for p in self._plugins]
174
175
    def getAllExports(self):
176
        """
177
        Return all the stats to be exported (list).
178
        Default behavor is to export all the stat
179
        """
180
        return [self._plugins[p].get_export() for p in self._plugins]
181
182
    def getAllAsDict(self):
183
        """Return all the stats (dict)."""
184
        # Python > 2.6
185
        # {p: self._plugins[p].get_raw() for p in self._plugins}
186
        ret = {}
187
        for p in self._plugins:
188
            ret[p] = self._plugins[p].get_raw()
189
        return ret
190
191
    def getAllLimits(self):
192
        """Return the plugins limits list."""
193
        return [self._plugins[p].limits for p in self._plugins]
194
195
    def getAllLimitsAsDict(self):
196
        """Return all the stats limits (dict)."""
197
        ret = {}
198
        for p in self._plugins:
199
            ret[p] = self._plugins[p].limits
200
        return ret
201
202
    def getAllViews(self):
203
        """Return the plugins views."""
204
        return [self._plugins[p].get_views() for p in self._plugins]
205
206
    def getAllViewsAsDict(self):
207
        """Return all the stats views (dict)."""
208
        ret = {}
209
        for p in self._plugins:
210
            ret[p] = self._plugins[p].get_views()
211
        return ret
212
213
    def get_plugin_list(self):
214
        """Return the plugin list."""
215
        return self._plugins
216
217
    def get_plugin(self, plugin_name):
218
        """Return the plugin name."""
219
        if plugin_name in self._plugins:
220
            return self._plugins[plugin_name]
221
        else:
222
            return None
223
224
    def end(self):
225
        """End of the Glances stats."""
226
        # Close export modules
227
        for e in self._exports:
228
            self._exports[e].exit()
229
        # Close plugins
230
        for p in self._plugins:
231
            self._plugins[p].exit()
232