Test Failed
Push — develop ( 504450...f0e8ef )
by Nicolas
03:16
created

glances/plugins/glances_load.py (1 issue)

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
23
import psutil
24
25
from glances.compat import iteritems
26
from glances.plugins.glances_core import Plugin as CorePlugin
27
from glances.plugins.glances_plugin import GlancesPlugin
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',
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',
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, config=None):
0 ignored issues
show
This code seems to be duplicated in your project.
Loading history...
54
        """Init the plugin."""
55
        super(Plugin, self).__init__(args=args,
56
                                     config=config,
57
                                     items_history_list=items_history_list)
58
59
        # We want to display the stat in the curse interface
60
        self.display_curse = True
61
62
        # Call CorePlugin in order to display the core number
63
        try:
64
            self.nb_log_core = CorePlugin(args=self.args).update()["log"]
65
        except Exception:
66
            self.nb_log_core = 1
67
68
    def _getloadavg(self):
69
        """Get load average. On both Linux and Windows thanks to PsUtil"""
70
        try:
71
            return psutil.getloadavg()
72
        except AttributeError:
73
            pass
74
        try:
75
            return os.getloadavg()
76
        except (AttributeError, OSError):
77
            return None
78
79
    @GlancesPlugin._check_decorator
80
    @GlancesPlugin._log_result_decorator
81
    def update(self):
82
        """Update load stats."""
83
        # Init new stats
84
        stats = self.get_init_value()
85
86
        if self.input_method == 'local':
87
            # Update stats using the standard system lib
88
89
            # Get the load using the os standard lib
90
            load = self._getloadavg()
91
            if load is None:
92
                stats = self.get_init_value()
93
            else:
94
                stats = {'min1': load[0],
95
                         'min5': load[1],
96
                         'min15': load[2],
97
                         'cpucore': self.nb_log_core}
98
99
        elif self.input_method == 'snmp':
100
            # Update stats using SNMP
101
            stats = self.get_stats_snmp(snmp_oid=snmp_oid)
102
103
            if stats['min1'] == '':
104
                stats = self.get_init_value()
105
                return stats
106
107
            # Python 3 return a dict like:
108
            # {'min1': "b'0.08'", 'min5': "b'0.12'", 'min15': "b'0.15'"}
109
            for k, v in iteritems(stats):
110
                stats[k] = float(v)
111
112
            stats['cpucore'] = self.nb_log_core
113
114
        # Update the stats
115
        self.stats = stats
116
117
        return self.stats
118
119
    def update_views(self):
120
        """Update stats views."""
121
        # Call the father's method
122
        super(Plugin, self).update_views()
123
124
        # Add specifics informations
125
        try:
126
            # Alert and log
127
            self.views['min15']['decoration'] = self.get_alert_log(self.stats['min15'], maximum=100 * self.stats['cpucore'])
128
            # Alert only
129
            self.views['min5']['decoration'] = self.get_alert(self.stats['min5'], maximum=100 * self.stats['cpucore'])
130
        except KeyError:
131
            # try/except mandatory for Windows compatibility (no load stats)
132
            pass
133
134
    def msg_curse(self, args=None, max_width=None):
135
        """Return the dict to display in the curse interface."""
136
        # Init the return message
137
        ret = []
138
139
        # Only process if stats exist, not empty (issue #871) and plugin not disabled
140
        if not self.stats or (self.stats == {}) or self.is_disable():
141
            return ret
142
143
        # Build the string message
144
        # Header
145
        msg = '{:8}'.format('LOAD')
146
        ret.append(self.curse_add_line(msg, "TITLE"))
147
        # Core number
148
        if 'cpucore' in self.stats and self.stats['cpucore'] > 0:
149
            msg = '{}-core'.format(int(self.stats['cpucore']))
150
            ret.append(self.curse_add_line(msg))
151
        # New line
152
        ret.append(self.curse_new_line())
153
        # 1min load
154
        msg = '{:8}'.format('1 min:')
155
        ret.append(self.curse_add_line(msg))
156
        msg = '{:>6.2f}'.format(self.stats['min1'])
157
        ret.append(self.curse_add_line(msg))
158
        # New line
159
        ret.append(self.curse_new_line())
160
        # 5min load
161
        msg = '{:8}'.format('5 min:')
162
        ret.append(self.curse_add_line(msg))
163
        msg = '{:>6.2f}'.format(self.stats['min5'])
164
        ret.append(self.curse_add_line(
165
            msg, self.get_views(key='min5', option='decoration')))
166
        # New line
167
        ret.append(self.curse_new_line())
168
        # 15min load
169
        msg = '{:8}'.format('15 min:')
170
        ret.append(self.curse_add_line(msg))
171
        msg = '{:>6.2f}'.format(self.stats['min15'])
172
        ret.append(self.curse_add_line(
173
            msg, self.get_views(key='min15', option='decoration')))
174
175
        return ret
176