Completed
Push — master ( 12bab0...1806d1 )
by Nicolas
01:07
created

glances.plugins.Plugin.update_views()   B

Complexity

Conditions 7

Size

Total Lines 18

Duplication

Lines 0
Ratio 0 %
Metric Value
cc 7
dl 0
loc 18
rs 7.3333
1
# -*- coding: utf-8 -*-
2
#
3
# This file is part of Glances.
4
#
5
# Copyright (C) 2015 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
"""CPU plugin."""
21
22
from glances.compat import iterkeys
23
from glances.cpu_percent import cpu_percent
24
from glances.plugins.glances_plugin import GlancesPlugin
25
26
import psutil
27
28
# SNMP OID
29
# percentage of user CPU time: .1.3.6.1.4.1.2021.11.9.0
30
# percentages of system CPU time: .1.3.6.1.4.1.2021.11.10.0
31
# percentages of idle CPU time: .1.3.6.1.4.1.2021.11.11.0
32
snmp_oid = {'default': {'user': '1.3.6.1.4.1.2021.11.9.0',
33
                        'system': '1.3.6.1.4.1.2021.11.10.0',
34
                        'idle': '1.3.6.1.4.1.2021.11.11.0'},
35
            'windows': {'percent': '1.3.6.1.2.1.25.3.3.1.2'},
36
            'esxi': {'percent': '1.3.6.1.2.1.25.3.3.1.2'},
37
            'netapp': {'system': '1.3.6.1.4.1.789.1.2.1.3.0',
38
                       'idle': '1.3.6.1.4.1.789.1.2.1.5.0',
39
                       'nb_log_core': '1.3.6.1.4.1.789.1.2.1.6.0'}}
40
41
# Define the history items list
42
# - 'name' define the stat identifier
43
# - 'color' define the graph color in #RGB format
44
# - 'y_unit' define the Y label
45
# All items in this list will be historised if the --enable-history tag is set
46
items_history_list = [{'name': 'user', 'color': '#00FF00', 'y_unit': '%'},
47
                      {'name': 'system', 'color': '#FF0000', 'y_unit': '%'}]
48
49
50
class Plugin(GlancesPlugin):
51
52
    """Glances CPU plugin.
53
54
    'stats' is a dictionary that contains the system-wide CPU utilization as a
55
    percentage.
56
    """
57
58
    def __init__(self, args=None):
59
        """Init the CPU plugin."""
60
        super(Plugin, self).__init__(args=args, items_history_list=items_history_list)
61
62
        # We want to display the stat in the curse interface
63
        self.display_curse = True
64
65
        # Init stats
66
        self.reset()
67
68
    def reset(self):
69
        """Reset/init the stats."""
70
        self.stats = {}
71
72
    @GlancesPlugin._log_result_decorator
73
    def update(self):
74
        """Update CPU stats using the input method."""
75
        # Reset stats
76
        self.reset()
77
78
        # Grab CPU stats using psutil's cpu_percent and cpu_times_percent
79
        # methods
80
        if self.input_method == 'local':
81
            # Get all possible values for CPU stats: user, system, idle,
82
            # nice (UNIX), iowait (Linux), irq (Linux, FreeBSD), steal (Linux 2.6.11+)
83
            # The following stats are returned by the API but not displayed in the UI:
84
            # softirq (Linux), guest (Linux 2.6.24+), guest_nice (Linux 3.2.0+)
85
            self.stats['total'] = cpu_percent.get()
86
            cpu_times_percent = psutil.cpu_times_percent(interval=0.0)
87
            for stat in ['user', 'system', 'idle', 'nice', 'iowait',
88
                         'irq', 'softirq', 'steal', 'guest', 'guest_nice']:
89
                if hasattr(cpu_times_percent, stat):
90
                    self.stats[stat] = getattr(cpu_times_percent, stat)
91
        elif self.input_method == 'snmp':
92
            # Update stats using SNMP
93
            if self.short_system_name in ('windows', 'esxi'):
94
                # Windows or VMWare ESXi
95
                # You can find the CPU utilization of windows system by querying the oid
96
                # Give also the number of core (number of element in the table)
97
                try:
98
                    cpu_stats = self.get_stats_snmp(snmp_oid=snmp_oid[self.short_system_name],
99
                                                    bulk=True)
100
                except KeyError:
101
                    self.reset()
102
103
                # Iter through CPU and compute the idle CPU stats
104
                self.stats['nb_log_core'] = 0
105
                self.stats['idle'] = 0
106
                for c in cpu_stats:
107
                    if c.startswith('percent'):
108
                        self.stats['idle'] += float(cpu_stats['percent.3'])
109
                        self.stats['nb_log_core'] += 1
110
                if self.stats['nb_log_core'] > 0:
111
                    self.stats['idle'] = self.stats[
112
                        'idle'] / self.stats['nb_log_core']
113
                self.stats['idle'] = 100 - self.stats['idle']
114
                self.stats['total'] = 100 - self.stats['idle']
115
116
            else:
117
                # Default behavor
118
                try:
119
                    self.stats = self.get_stats_snmp(
120
                        snmp_oid=snmp_oid[self.short_system_name])
121
                except KeyError:
122
                    self.stats = self.get_stats_snmp(
123
                        snmp_oid=snmp_oid['default'])
124
125
                if self.stats['idle'] == '':
126
                    self.reset()
127
                    return self.stats
128
129
                # Convert SNMP stats to float
130
                for key in iterkeys(self.stats):
131
                    self.stats[key] = float(self.stats[key])
132
                self.stats['total'] = 100 - self.stats['idle']
133
134
        # Update the history list
135
        self.update_stats_history()
136
137
        # Update the view
138
        self.update_views()
139
140
        return self.stats
141
142
    def update_views(self):
143
        """Update stats views."""
144
        # Call the father's method
145
        super(Plugin, self).update_views()
146
147
        # Add specifics informations
148
        # Alert and log
149
        for key in ['user', 'system', 'iowait']:
150
            if key in self.stats:
151
                self.views[key]['decoration'] = self.get_alert_log(self.stats[key], header=key)
152
        # Alert only
153
        for key in ['steal', 'total']:
154
            if key in self.stats:
155
                self.views[key]['decoration'] = self.get_alert(self.stats[key], header=key)
156
        # Optional
157
        for key in ['nice', 'irq', 'iowait', 'steal']:
158
            if key in self.stats:
159
                self.views[key]['optional'] = True
160
161
    def msg_curse(self, args=None):
162
        """Return the list to display in the UI."""
163
        # Init the return message
164
        ret = []
165
166
        # Only process if stats exist and plugin not disable
167
        if not self.stats or args.disable_cpu:
168
            return ret
169
170
        # Build the string message
171
        # If user stat is not here, display only idle / total CPU usage (for
172
        # exemple on Windows OS)
173
        idle_tag = 'user' not in self.stats
174
        # Header
175
        msg = '{0:8}'.format('CPU')
176
        ret.append(self.curse_add_line(msg, "TITLE"))
177
        # Total CPU usage
178
        msg = '{0:>5}%'.format(self.stats['total'])
179
        if idle_tag:
180
            ret.append(self.curse_add_line(
181
                msg, self.get_views(key='total', option='decoration')))
182
        else:
183
            ret.append(self.curse_add_line(msg))
184
        # Nice CPU
185
        if 'nice' in self.stats:
186
            msg = '  {0:8}'.format('nice:')
187
            ret.append(self.curse_add_line(msg, optional=self.get_views(key='nice', option='optional')))
188
            msg = '{0:>5}%'.format(self.stats['nice'])
189
            ret.append(self.curse_add_line(msg, optional=self.get_views(key='nice', option='optional')))
190
        # New line
191
        ret.append(self.curse_new_line())
192
        # User CPU
193
        if 'user' in self.stats:
194
            msg = '{0:8}'.format('user:')
195
            ret.append(self.curse_add_line(msg))
196
            msg = '{0:>5}%'.format(self.stats['user'])
197
            ret.append(self.curse_add_line(
198
                msg, self.get_views(key='user', option='decoration')))
199
        elif 'idle' in self.stats:
200
            msg = '{0:8}'.format('idle:')
201
            ret.append(self.curse_add_line(msg))
202
            msg = '{0:>5}%'.format(self.stats['idle'])
203
            ret.append(self.curse_add_line(msg))
204
        # IRQ CPU
205
        if 'irq' in self.stats:
206
            msg = '  {0:8}'.format('irq:')
207
            ret.append(self.curse_add_line(msg, optional=self.get_views(key='irq', option='optional')))
208
            msg = '{0:>5}%'.format(self.stats['irq'])
209
            ret.append(self.curse_add_line(msg, optional=self.get_views(key='irq', option='optional')))
210
        # New line
211
        ret.append(self.curse_new_line())
212
        # System CPU
213
        if 'system' in self.stats and not idle_tag:
214
            msg = '{0:8}'.format('system:')
215
            ret.append(self.curse_add_line(msg))
216
            msg = '{0:>5}%'.format(self.stats['system'])
217
            ret.append(self.curse_add_line(
218
                msg, self.get_views(key='system', option='decoration')))
219
        else:
220
            msg = '{0:8}'.format('core:')
221
            ret.append(self.curse_add_line(msg))
222
            msg = '{0:>6}'.format(self.stats['nb_log_core'])
223
            ret.append(self.curse_add_line(msg))
224
        # IOWait CPU
225
        if 'iowait' in self.stats:
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
226
            msg = '  {0:8}'.format('iowait:')
227
            ret.append(self.curse_add_line(msg, optional=self.get_views(key='iowait', option='optional')))
228
            msg = '{0:>5}%'.format(self.stats['iowait'])
229
            ret.append(self.curse_add_line(
230
                msg, self.get_views(key='iowait', option='decoration'),
231
                optional=self.get_views(key='iowait', option='optional')))
232
        # New line
233
        ret.append(self.curse_new_line())
234
        # Idle CPU
235
        if 'idle' in self.stats and not idle_tag:
236
            msg = '{0:8}'.format('idle:')
237
            ret.append(self.curse_add_line(msg))
238
            msg = '{0:>5}%'.format(self.stats['idle'])
239
            ret.append(self.curse_add_line(msg))
240
        # Steal CPU usage
241
        if 'steal' in self.stats:
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
242
            msg = '  {0:8}'.format('steal:')
243
            ret.append(self.curse_add_line(msg, optional=self.get_views(key='steal', option='optional')))
244
            msg = '{0:>5}%'.format(self.stats['steal'])
245
            ret.append(self.curse_add_line(
246
                msg, self.get_views(key='steal', option='decoration'),
247
                optional=self.get_views(key='steal', option='optional')))
248
249
        # Return the message with decoration
250
        return ret
251