Test Failed
Push — develop ( 66c9ff...e21229 )
by Nicolas
05:06
created

glances/plugins/glances_quicklook.py (2 issues)

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
The variable data does not seem to be defined in case self.args.sparkline and self.history_enable() on line 128 is False. Are you sure this can never be the case?
Loading history...
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
The variable raw_cpu does not seem to be defined for all execution paths.
Loading history...
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