Passed
Push — master ( cdb6bf...0d35d5 )
by Nicolas
04:08 queued 14s
created

glances.plugins.glances_memswap.Plugin.update()   F

Complexity

Conditions 15

Size

Total Lines 75
Code Lines 42

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 15
eloc 42
nop 1
dl 0
loc 75
rs 2.9998
c 0
b 0
f 0

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

Complexity

Complex classes like glances.plugins.glances_memswap.Plugin.update() 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) 2019 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
"""Swap memory plugin."""
21
22
from glances.compat import iterkeys
0 ignored issues
show
introduced by
import missing from __future__ import absolute_import
Loading history...
23
from glances.plugins.glances_plugin import GlancesPlugin
0 ignored issues
show
introduced by
import missing from __future__ import absolute_import
Loading history...
24
25
import psutil
0 ignored issues
show
introduced by
import missing from __future__ import absolute_import
Loading history...
introduced by
Unable to import 'psutil'
Loading history...
26
27
# SNMP OID
28
# Total Swap Size: .1.3.6.1.4.1.2021.4.3.0
29
# Available Swap Space: .1.3.6.1.4.1.2021.4.4.0
30
snmp_oid = {'default': {'total': '1.3.6.1.4.1.2021.4.3.0',
0 ignored issues
show
Coding Style Naming introduced by
The name snmp_oid does not conform to the constant naming conventions ((([A-Z_][A-Z0-9_]*)|(__.*__))$).

This check looks for invalid names for a range of different identifiers.

You can set regular expressions to which the identifiers must conform if the defaults do not match your requirements.

If your project includes a Pylint configuration file, the settings contained in that file take precedence.

To find out more about Pylint, please refer to their site.

Loading history...
31
                        'free': '1.3.6.1.4.1.2021.4.4.0'},
32
            'windows': {'mnt_point': '1.3.6.1.2.1.25.2.3.1.3',
33
                        'alloc_unit': '1.3.6.1.2.1.25.2.3.1.4',
34
                        'size': '1.3.6.1.2.1.25.2.3.1.5',
35
                        'used': '1.3.6.1.2.1.25.2.3.1.6'}}
36
37
# Define the history items list
38
# All items in this list will be historised if the --enable-history tag is set
39
items_history_list = [{'name': 'percent',
0 ignored issues
show
Coding Style Naming introduced by
The name items_history_list does not conform to the constant naming conventions ((([A-Z_][A-Z0-9_]*)|(__.*__))$).

This check looks for invalid names for a range of different identifiers.

You can set regular expressions to which the identifiers must conform if the defaults do not match your requirements.

If your project includes a Pylint configuration file, the settings contained in that file take precedence.

To find out more about Pylint, please refer to their site.

Loading history...
40
                       'description': 'Swap memory usage',
41
                       'y_unit': '%'}]
42
43
44
class Plugin(GlancesPlugin):
45
    """Glances swap memory plugin.
46
47
    stats is a dict
48
    """
49
50
    def __init__(self, args=None, config=None):
51
        """Init the plugin."""
52
        super(Plugin, self).__init__(args=args,
53
                                     config=config,
54
                                     items_history_list=items_history_list)
55
56
        # We want to display the stat in the curse interface
57
        self.display_curse = True
58
59
    @GlancesPlugin._check_decorator
60
    @GlancesPlugin._log_result_decorator
61
    def update(self):
62
        """Update swap memory stats using the input method."""
63
        # Init new stats
64
        stats = self.get_init_value()
65
66
        if self.input_method == 'local':
67
            # Update stats using the standard system lib
68
            # Grab SWAP using the psutil swap_memory method
69
            try:
70
                sm_stats = psutil.swap_memory()
71
            except RuntimeError:
72
                # Crash on startup on Illumos when no swap is configured #1767
73
                pass
74
            else:
75
                # Get all the swap stats (copy/paste of the psutil documentation)
0 ignored issues
show
Coding Style introduced by
This line is too long as per the coding-style (81/80).

This check looks for lines that are too long. You can specify the maximum line length.

Loading history...
76
                # total: total swap memory in bytes
77
                # used: used swap memory in bytes
78
                # free: free swap memory in bytes
79
                # percent: the percentage usage
80
                # sin: the number of bytes the system has swapped in from disk (cumulative)
0 ignored issues
show
Coding Style introduced by
This line is too long as per the coding-style (91/80).

This check looks for lines that are too long. You can specify the maximum line length.

Loading history...
81
                # sout: the number of bytes the system has swapped out from disk
82
                # (cumulative)
83
                for swap in ['total', 'used', 'free', 'percent',
84
                            'sin', 'sout']:
0 ignored issues
show
Coding Style introduced by
Wrong continued indentation (add 1 space).
Loading history...
85
                    if hasattr(sm_stats, swap):
86
                        stats[swap] = getattr(sm_stats, swap)
87
        elif self.input_method == 'snmp':
88
            # Update stats using SNMP
89
            if self.short_system_name == 'windows':
90
                # Mem stats for Windows OS are stored in the FS table
91
                try:
92
                    fs_stat = self.get_stats_snmp(snmp_oid=snmp_oid[self.short_system_name],
0 ignored issues
show
Coding Style introduced by
This line is too long as per the coding-style (92/80).

This check looks for lines that are too long. You can specify the maximum line length.

Loading history...
93
                                                  bulk=True)
94
                except KeyError:
95
                    self.reset()
96
                else:
97
                    for fs in fs_stat:
0 ignored issues
show
Coding Style Naming introduced by
The name fs does not conform to the variable naming conventions ((([a-z][a-z0-9_]{2,30})|(_[a-z0-9_]*))$).

This check looks for invalid names for a range of different identifiers.

You can set regular expressions to which the identifiers must conform if the defaults do not match your requirements.

If your project includes a Pylint configuration file, the settings contained in that file take precedence.

To find out more about Pylint, please refer to their site.

Loading history...
98
                        # The virtual memory concept is used by the operating
99
                        # system to extend (virtually) the physical memory and
100
                        # thus to run more programs by swapping unused memory
101
                        # zone (page) to a disk file.
102
                        if fs == 'Virtual Memory':
103
                            stats['total'] = int(
104
                                fs_stat[fs]['size']) * int(fs_stat[fs]['alloc_unit'])
0 ignored issues
show
Coding Style introduced by
This line is too long as per the coding-style (85/80).

This check looks for lines that are too long. You can specify the maximum line length.

Loading history...
105
                            stats['used'] = int(
106
                                fs_stat[fs]['used']) * int(fs_stat[fs]['alloc_unit'])
0 ignored issues
show
Coding Style introduced by
This line is too long as per the coding-style (85/80).

This check looks for lines that are too long. You can specify the maximum line length.

Loading history...
107
                            stats['percent'] = float(
108
                                stats['used'] * 100 / stats['total'])
0 ignored issues
show
introduced by
division w/o __future__ statement
Loading history...
109
                            stats['free'] = stats['total'] - stats['used']
110
                            break
111
            else:
112
                stats = self.get_stats_snmp(snmp_oid=snmp_oid['default'])
113
114
                if stats['total'] == '':
115
                    self.reset()
116
                    return stats
117
118
                for key in iterkeys(stats):
119
                    if stats[key] != '':
120
                        stats[key] = float(stats[key]) * 1024
121
122
                # used=total-free
123
                stats['used'] = stats['total'] - stats['free']
124
125
                # percent: the percentage usage calculated as (total -
126
                # available) / total * 100.
127
                stats['percent'] = float(
128
                    (stats['total'] - stats['free']) / stats['total'] * 100)
0 ignored issues
show
introduced by
division w/o __future__ statement
Loading history...
129
130
        # Update the stats
131
        self.stats = stats
132
133
        return self.stats
134
135
    def update_views(self):
136
        """Update stats views."""
137
        # Call the father's method
138
        super(Plugin, self).update_views()
139
140
        # Add specifics informations
141
        # Alert and log
142
        if 'used' in self.stats and 'total' in self.stats:
143
            self.views['used']['decoration'] = self.get_alert_log(self.stats['used'], maximum=self.stats['total'])
0 ignored issues
show
Coding Style introduced by
This line is too long as per the coding-style (114/80).

This check looks for lines that are too long. You can specify the maximum line length.

Loading history...
144
145
    def msg_curse(self, args=None, max_width=None):
146
        """Return the dict to display in the curse interface."""
147
        # Init the return message
148
        ret = []
149
150
        # Only process if stats exist and plugin not disabled
151
        if not self.stats or self.is_disable():
152
            return ret
153
154
        # Build the string message
155
        # Header
156
        msg = '{}'.format('SWAP')
157
        ret.append(self.curse_add_line(msg, "TITLE"))
158
        msg = ' {:3}'.format(self.trend_msg(self.get_trend('percent')))
159
        ret.append(self.curse_add_line(msg))
160
        # Percent memory usage
161
        msg = '{:>6.1%}'.format(self.stats['percent'] / 100)
0 ignored issues
show
introduced by
division w/o __future__ statement
Loading history...
162
        ret.append(self.curse_add_line(msg))
163
        # New line
164
        ret.append(self.curse_new_line())
165
        # Total memory usage
166
        msg = '{:8}'.format('total:')
167
        ret.append(self.curse_add_line(msg))
168
        msg = '{:>6}'.format(self.auto_unit(self.stats['total']))
169
        ret.append(self.curse_add_line(msg))
170
        # New line
171
        ret.append(self.curse_new_line())
172
        # Used memory usage
173
        msg = '{:8}'.format('used:')
174
        ret.append(self.curse_add_line(msg))
175
        msg = '{:>6}'.format(self.auto_unit(self.stats['used']))
176
        ret.append(self.curse_add_line(
177
            msg, self.get_views(key='used', option='decoration')))
178
        # New line
179
        ret.append(self.curse_new_line())
180
        # Free memory usage
181
        msg = '{:8}'.format('free:')
182
        ret.append(self.curse_add_line(msg))
183
        msg = '{:>6}'.format(self.auto_unit(self.stats['free']))
184
        ret.append(self.curse_add_line(msg))
185
186
        return ret
187