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
Duplication
introduced
by
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
|
|||
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
|
|||
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
|
|||
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 |