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 | """Quicklook plugin.""" |
||
21 | |||
22 | from glances.cpu_percent import cpu_percent |
||
23 | from glances.logger import logger |
||
24 | from glances.outputs.glances_bars import Bar |
||
25 | from glances.outputs.glances_sparklines import Sparkline |
||
26 | from glances.plugins.glances_plugin import GlancesPlugin |
||
27 | |||
28 | import psutil |
||
29 | |||
30 | # Import plugin specific dependency |
||
31 | try: |
||
32 | from cpuinfo import cpuinfo |
||
33 | except ImportError as e: |
||
34 | cpuinfo_tag = False |
||
35 | logger.warning("Missing Python Lib ({}), Quicklook plugin will not display CPU info".format(e)) |
||
36 | else: |
||
37 | cpuinfo_tag = True |
||
38 | |||
39 | |||
40 | # Define the history items list |
||
41 | # All items in this list will be historised if the --enable-history tag is set |
||
42 | items_history_list = [{'name': 'cpu', |
||
43 | 'description': 'CPU percent usage', |
||
44 | 'y_unit': '%'}, |
||
45 | {'name': 'percpu', |
||
46 | 'description': 'PERCPU percent usage', |
||
47 | 'y_unit': '%'}, |
||
48 | {'name': 'mem', |
||
49 | 'description': 'MEM percent usage', |
||
50 | 'y_unit': '%'}, |
||
51 | {'name': 'swap', |
||
52 | 'description': 'SWAP percent usage', |
||
53 | 'y_unit': '%'}] |
||
54 | |||
55 | |||
56 | class Plugin(GlancesPlugin): |
||
57 | """Glances quicklook plugin. |
||
58 | |||
59 | 'stats' is a dictionary. |
||
60 | """ |
||
61 | |||
62 | def __init__(self, args=None, config=None): |
||
63 | """Init the quicklook plugin.""" |
||
64 | super(Plugin, self).__init__(args=args, |
||
65 | config=config, |
||
66 | items_history_list=items_history_list) |
||
67 | # We want to display the stat in the curse interface |
||
68 | self.display_curse = True |
||
69 | |||
70 | @GlancesPlugin._check_decorator |
||
71 | @GlancesPlugin._log_result_decorator |
||
72 | def update(self): |
||
73 | """Update quicklook stats using the input method.""" |
||
74 | # Init new stats |
||
75 | stats = self.get_init_value() |
||
76 | |||
77 | # Grab quicklook stats: CPU, MEM and SWAP |
||
78 | if self.input_method == 'local': |
||
79 | # Get the latest CPU percent value |
||
80 | stats['cpu'] = cpu_percent.get() |
||
81 | stats['percpu'] = cpu_percent.get(percpu=True) |
||
82 | # Use the psutil lib for the memory (virtual and swap) |
||
83 | stats['mem'] = psutil.virtual_memory().percent |
||
84 | stats['swap'] = psutil.swap_memory().percent |
||
85 | elif self.input_method == 'snmp': |
||
86 | # Not available |
||
87 | pass |
||
88 | |||
89 | # Optionnaly, get the CPU name/frequency |
||
90 | # thanks to the cpuinfo lib: https://github.com/workhorsy/py-cpuinfo |
||
91 | if cpuinfo_tag: |
||
92 | cpu_info = cpuinfo.get_cpu_info() |
||
93 | # Check cpu_info (issue #881) |
||
94 | if cpu_info is not None: |
||
95 | stats['cpu_name'] = cpu_info.get('brand', 'CPU') |
||
96 | if 'hz_actual_raw' in cpu_info: |
||
97 | stats['cpu_hz_current'] = cpu_info['hz_actual_raw'][0] |
||
98 | if 'hz_advertised_raw' in cpu_info: |
||
99 | stats['cpu_hz'] = cpu_info['hz_advertised_raw'][0] |
||
100 | |||
101 | # Update the stats |
||
102 | self.stats = stats |
||
103 | |||
104 | return self.stats |
||
105 | |||
106 | def update_views(self): |
||
107 | """Update stats views.""" |
||
108 | # Call the father's method |
||
109 | super(Plugin, self).update_views() |
||
110 | |||
111 | # Add specifics informations |
||
112 | # Alert only |
||
113 | for key in ['cpu', 'mem', 'swap']: |
||
114 | if key in self.stats: |
||
115 | self.views[key]['decoration'] = self.get_alert(self.stats[key], header=key) |
||
116 | |||
117 | def msg_curse(self, args=None, max_width=10): |
||
118 | """Return the list to display in the UI.""" |
||
119 | # Init the return message |
||
120 | ret = [] |
||
121 | |||
122 | # Only process if stats exist... |
||
123 | if not self.stats or self.is_disable(): |
||
124 | return ret |
||
125 | |||
126 | # Define the data: Bar (default behavor) or Sparkline |
||
127 | sparkline_tag = False |
||
128 | if self.args.sparkline and self.history_enable(): |
||
129 | data = Sparkline(max_width) |
||
130 | sparkline_tag = data.available |
||
131 | if not sparkline_tag: |
||
132 | # Fallback to bar if Sparkline module is not installed |
||
133 | data = Bar(max_width, |
||
134 | percentage_char=self.get_conf_value('percentage_char', |
||
135 | default=['|'])[0]) |
||
136 | |||
137 | # Build the string message |
||
138 | if 'cpu_name' in self.stats and 'cpu_hz_current' in self.stats and 'cpu_hz' in self.stats: |
||
139 | msg_name = '{} - '.format(self.stats['cpu_name']) |
||
140 | msg_freq = '{:.2f}/{:.2f}GHz'.format(self._hz_to_ghz(self.stats['cpu_hz_current']), |
||
141 | self._hz_to_ghz(self.stats['cpu_hz'])) |
||
142 | if len(msg_name + msg_freq) - 6 <= max_width: |
||
143 | ret.append(self.curse_add_line(msg_name)) |
||
144 | ret.append(self.curse_add_line(msg_freq)) |
||
145 | ret.append(self.curse_new_line()) |
||
146 | for key in ['cpu', 'mem', 'swap']: |
||
147 | if key == 'cpu' and args.percpu: |
||
148 | if sparkline_tag: |
||
149 | raw_cpu = self.get_raw_history(item='percpu', nb=data.size) |
||
0 ignored issues
–
show
introduced
by
![]() |
|||
150 | for cpu_index, cpu in enumerate(self.stats['percpu']): |
||
151 | if sparkline_tag: |
||
152 | # Sparkline display an history |
||
153 | data.percents = [i[1][cpu_index]['total'] for i in raw_cpu] |
||
0 ignored issues
–
show
|
|||
154 | # A simple padding in order to align metrics to the right |
||
155 | data.percents += [None] * (data.size - len(data.percents)) |
||
156 | else: |
||
157 | # Bar only the last value |
||
158 | data.percent = cpu['total'] |
||
159 | if cpu[cpu['key']] < 10: |
||
160 | msg = '{:3}{} '.format(key.upper(), cpu['cpu_number']) |
||
161 | else: |
||
162 | msg = '{:4} '.format(cpu['cpu_number']) |
||
163 | ret.extend(self._msg_create_line(msg, data, key)) |
||
164 | ret.append(self.curse_new_line()) |
||
165 | else: |
||
166 | if sparkline_tag: |
||
167 | # Sparkline display an history |
||
168 | data.percents = [i[1] for i in self.get_raw_history(item=key, nb=data.size)] |
||
169 | # A simple padding in order to align metrics to the right |
||
170 | data.percents += [None] * (data.size - len(data.percents)) |
||
171 | else: |
||
172 | # Bar only the last value |
||
173 | data.percent = self.stats[key] |
||
174 | msg = '{:4} '.format(key.upper()) |
||
175 | ret.extend(self._msg_create_line(msg, data, key)) |
||
176 | ret.append(self.curse_new_line()) |
||
177 | |||
178 | # Remove the last new line |
||
179 | ret.pop() |
||
180 | |||
181 | # Return the message with decoration |
||
182 | return ret |
||
183 | |||
184 | def _msg_create_line(self, msg, data, key): |
||
185 | """Create a new line to the Quickview.""" |
||
186 | ret = [] |
||
187 | |||
188 | ret.append(self.curse_add_line(msg)) |
||
189 | ret.append(self.curse_add_line(data.pre_char, decoration='BOLD')) |
||
190 | ret.append(self.curse_add_line(data.get(), self.get_views(key=key, option='decoration'))) |
||
191 | ret.append(self.curse_add_line(data.post_char, decoration='BOLD')) |
||
192 | ret.append(self.curse_add_line(' ')) |
||
193 | |||
194 | return ret |
||
195 | |||
196 | def _hz_to_ghz(self, hz): |
||
197 | """Convert Hz to Ghz.""" |
||
198 | return hz / 1000000000.0 |
||
199 |