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

glances/plugins/glances_cpu.py (4 issues)

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 View Code Duplication
        if 'user' in self.stats:
0 ignored issues
show
This code seems to be duplicated in your project.
Loading history...
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 View Code Duplication
        if 'system' in self.stats and not idle_tag:
0 ignored issues
show
This code seems to be duplicated in your project.
Loading history...
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 View Code Duplication
        if 'iowait' in self.stats:
0 ignored issues
show
This code seems to be duplicated in your project.
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 View Code Duplication
        if 'steal' in self.stats:
0 ignored issues
show
This code seems to be duplicated in your project.
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