Test Failed
Push — master ( b668b0...91d406 )
by Nicolas
07:51 queued 03:03
created

glances.plugins.glances_load.Plugin._getloadavg()   A

Complexity

Conditions 3

Size

Total Lines 10
Code Lines 9

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 3
eloc 9
nop 1
dl 0
loc 10
rs 9.95
c 0
b 0
f 0
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
"""Load plugin."""
21
22
import os
0 ignored issues
show
introduced by
import missing from __future__ import absolute_import
Loading history...
23
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...
24
25
from glances.compat import iteritems
0 ignored issues
show
introduced by
import missing from __future__ import absolute_import
Loading history...
26
from glances.plugins.glances_core import Plugin as CorePlugin
0 ignored issues
show
introduced by
import missing from __future__ import absolute_import
Loading history...
27
from glances.plugins.glances_plugin import GlancesPlugin
0 ignored issues
show
introduced by
import missing from __future__ import absolute_import
Loading history...
28
29
# SNMP OID
30
# 1 minute Load: .1.3.6.1.4.1.2021.10.1.3.1
31
# 5 minute Load: .1.3.6.1.4.1.2021.10.1.3.2
32
# 15 minute Load: .1.3.6.1.4.1.2021.10.1.3.3
33
snmp_oid = {'min1': '1.3.6.1.4.1.2021.10.1.3.1',
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...
34
            'min5': '1.3.6.1.4.1.2021.10.1.3.2',
35
            'min15': '1.3.6.1.4.1.2021.10.1.3.3'}
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': 'min1',
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': '1 minute load'},
41
                      {'name': 'min5',
42
                       'description': '5 minutes load'},
43
                      {'name': 'min15',
44
                       'description': '15 minutes load'}]
45
46
47
class Plugin(GlancesPlugin):
48
    """Glances load plugin.
49
50
    stats is a dict
51
    """
52
53 View Code Duplication
    def __init__(self, args=None):
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated in your project.
Loading history...
54
        """Init the plugin."""
55
        super(Plugin, self).__init__(args=args,
56
                                     items_history_list=items_history_list)
57
58
        # We want to display the stat in the curse interface
59
        self.display_curse = True
60
61
        # Call CorePlugin in order to display the core number
62
        try:
63
            self.nb_log_core = CorePlugin(args=self.args).update()["log"]
64
        except Exception:
0 ignored issues
show
Best Practice introduced by
Catching very general exceptions such as Exception is usually not recommended.

Generally, you would want to handle very specific errors in the exception handler. This ensure that you do not hide other types of errors which should be fixed.

So, unless you specifically plan to handle any error, consider adding a more specific exception.

Loading history...
65
            self.nb_log_core = 1
66
67
    def _getloadavg(self):
0 ignored issues
show
Coding Style introduced by
This method could be written as a function/class method.

If a method does not access any attributes of the class, it could also be implemented as a function or static method. This can help improve readability. For example

class Foo:
    def some_method(self, x, y):
        return x + y;

could be written as

class Foo:
    @classmethod
    def some_method(cls, x, y):
        return x + y;
Loading history...
68
        """Get load average. On both Linux and Windows thanks to PsUtil"""
69
        try:
70
            return psutil.getloadavg()
71
        except AttributeError:
72
            pass
73
        try:
74
            return os.getloadavg()
75
        except (AttributeError, OSError):
76
            return None
77
78
    @GlancesPlugin._check_decorator
79
    @GlancesPlugin._log_result_decorator
80
    def update(self):
81
        """Update load stats."""
82
        # Init new stats
83
        stats = self.get_init_value()
84
85
        if self.input_method == 'local':
86
            # Update stats using the standard system lib
87
88
            # Get the load using the os standard lib
89
            load = self._getloadavg()
90
            if load is None:
91
                stats = self.get_init_value()
92
            else:
93
                stats = {'min1': load[0],
94
                         'min5': load[1],
95
                         'min15': load[2],
96
                         'cpucore': self.nb_log_core}
97
98
        elif self.input_method == 'snmp':
99
            # Update stats using SNMP
100
            stats = self.get_stats_snmp(snmp_oid=snmp_oid)
101
102
            if stats['min1'] == '':
103
                stats = self.get_init_value()
104
                return stats
105
106
            # Python 3 return a dict like:
107
            # {'min1': "b'0.08'", 'min5': "b'0.12'", 'min15': "b'0.15'"}
108
            for k, v in iteritems(stats):
0 ignored issues
show
Coding Style Naming introduced by
The name v 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...
109
                stats[k] = float(v)
110
111
            stats['cpucore'] = self.nb_log_core
112
113
        # Update the stats
114
        self.stats = stats
115
116
        return self.stats
117
118
    def update_views(self):
119
        """Update stats views."""
120
        # Call the father's method
121
        super(Plugin, self).update_views()
122
123
        # Add specifics informations
124
        try:
125
            # Alert and log
126
            self.views['min15']['decoration'] = self.get_alert_log(self.stats['min15'], maximum=100 * self.stats['cpucore'])
0 ignored issues
show
Coding Style introduced by
This line is too long as per the coding-style (124/80).

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

Loading history...
127
            # Alert only
128
            self.views['min5']['decoration'] = self.get_alert(self.stats['min5'], maximum=100 * self.stats['cpucore'])
0 ignored issues
show
Coding Style introduced by
This line is too long as per the coding-style (118/80).

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

Loading history...
129
        except KeyError:
130
            # try/except mandatory for Windows compatibility (no load stats)
131
            pass
132
133
    def msg_curse(self, args=None, max_width=None):
134
        """Return the dict to display in the curse interface."""
135
        # Init the return message
136
        ret = []
137
138
        # Only process if stats exist, not empty (issue #871) and plugin not disabled
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...
139
        if not self.stats or (self.stats == {}) or self.is_disable():
140
            return ret
141
142
        # Build the string message
143
        # Header
144
        msg = '{:8}'.format('LOAD')
145
        ret.append(self.curse_add_line(msg, "TITLE"))
146
        # Core number
147
        if 'cpucore' in self.stats and self.stats['cpucore'] > 0:
148
            msg = '{}-core'.format(int(self.stats['cpucore']))
149
            ret.append(self.curse_add_line(msg))
150
        # New line
151
        ret.append(self.curse_new_line())
152
        # 1min load
153
        msg = '{:8}'.format('1 min:')
154
        ret.append(self.curse_add_line(msg))
155
        msg = '{:>6.2f}'.format(self.stats['min1'])
156
        ret.append(self.curse_add_line(msg))
157
        # New line
158
        ret.append(self.curse_new_line())
159
        # 5min load
160
        msg = '{:8}'.format('5 min:')
161
        ret.append(self.curse_add_line(msg))
162
        msg = '{:>6.2f}'.format(self.stats['min5'])
163
        ret.append(self.curse_add_line(
164
            msg, self.get_views(key='min5', option='decoration')))
165
        # New line
166
        ret.append(self.curse_new_line())
167
        # 15min load
168
        msg = '{:8}'.format('15 min:')
169
        ret.append(self.curse_add_line(msg))
170
        msg = '{:>6.2f}'.format(self.stats['min15'])
171
        ret.append(self.curse_add_line(
172
            msg, self.get_views(key='min15', option='decoration')))
173
174
        return ret
175