Test Failed
Push — master ( 69b639...e7fa0a )
by Nicolas
04:05 queued 01:05
created

glances.plugins.glances_quicklook   A

Complexity

Total Complexity 34

Size/Duplication

Total Lines 197
Duplicated Lines 0 %

Importance

Changes 0
Metric Value
eloc 108
dl 0
loc 197
rs 9.68
c 0
b 0
f 0
wmc 34

7 Methods

Rating   Name   Duplication   Size   Complexity  
A Plugin.update_views() 0 10 3
A Plugin.__init__() 0 7 1
B Plugin.update() 0 35 6
A Plugin._hz_to_ghz() 0 3 1
A Plugin._msg_create_line() 0 11 1
A Plugin._mhz_to_hz() 0 3 1
F Plugin.msg_curse() 0 69 21
1
# -*- coding: utf-8 -*-
2
#
3
# This file is part of Glances.
4
#
5
# Copyright (C) 2020 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
# along with this program. If not, see <http://www.gnu.org/licenses/>.
18
# You should have received a copy of the GNU Lesser General Public License
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
31
# Define the history items list
32
# All items in this list will be historised if the --enable-history tag is set
33
items_history_list = [{'name': 'cpu',
34
                       'description': 'CPU percent usage',
35
                       'y_unit': '%'},
36
                      {'name': 'percpu',
37
                       'description': 'PERCPU percent usage',
38
                       'y_unit': '%'},
39
                      {'name': 'mem',
40
                       'description': 'MEM percent usage',
41
                       'y_unit': '%'},
42
                      {'name': 'swap',
43
                       'description': 'SWAP percent usage',
44
                       'y_unit': '%'}]
45
46
47
class Plugin(GlancesPlugin):
48
    """Glances quicklook plugin.
49
50
    'stats' is a dictionary.
51
    """
52
53
    def __init__(self, args=None, config=None):
54
        """Init the quicklook plugin."""
55
        super(Plugin, self).__init__(args=args,
56
                                     config=config,
57
                                     items_history_list=items_history_list)
58
        # We want to display the stat in the curse interface
59
        self.display_curse = True
60
61
    @GlancesPlugin._check_decorator
62
    @GlancesPlugin._log_result_decorator
63
    def update(self):
64
        """Update quicklook stats using the input method."""
65
        # Init new stats
66
        stats = self.get_init_value()
67
68
        # Grab quicklook stats: CPU, MEM and SWAP
69
        if self.input_method == 'local':
70
            # Get the latest CPU percent value
71
            stats['cpu'] = cpu_percent.get()
72
            stats['percpu'] = cpu_percent.get(percpu=True)
73
74
            # Use the psutil lib for the memory (virtual and swap)
75
            stats['mem'] = psutil.virtual_memory().percent
76
            try:
77
                stats['swap'] = psutil.swap_memory().percent
78
            except RuntimeError:
79
                # Correct issue in Illumos OS (see #1767)
80
                stats['swap'] = None
81
82
            # Get additional information
83
            cpu_info = cpu_percent.get_info()
84
            stats['cpu_name'] = cpu_info['cpu_name']
85
            stats['cpu_hz_current'] = self._mhz_to_hz(cpu_info['cpu_hz_current']) if cpu_info['cpu_hz_current'] is not None else None
86
            stats['cpu_hz'] = self._mhz_to_hz(cpu_info['cpu_hz']) if cpu_info['cpu_hz'] is not None else None
87
88
        elif self.input_method == 'snmp':
89
            # Not available
90
            pass
91
92
        # Update the stats
93
        self.stats = stats
94
95
        return self.stats
96
97
    def update_views(self):
98
        """Update stats views."""
99
        # Call the father's method
100
        super(Plugin, self).update_views()
101
102
        # Add specifics informations
103
        # Alert only
104
        for key in ['cpu', 'mem', 'swap']:
105
            if key in self.stats:
106
                self.views[key]['decoration'] = self.get_alert(self.stats[key], header=key)
107
108
    def msg_curse(self, args=None, max_width=10):
109
        """Return the list to display in the UI."""
110
        # Init the return message
111
        ret = []
112
113
        # Only process if stats exist...
114
        if not self.stats or self.is_disable():
115
            return ret
116
117
        # Define the data: Bar (default behavor) or Sparkline
118
        sparkline_tag = False
119
        if self.args.sparkline and self.history_enable() and not self.args.client:
120
            data = Sparkline(max_width)
121
            sparkline_tag = data.available
122
        if not sparkline_tag:
123
            # Fallback to bar if Sparkline module is not installed
124
            data = Bar(max_width,
125
                       percentage_char=self.get_conf_value('percentage_char',
126
                                                           default=['|'])[0])
127
128
        # Build the string message
129
        if 'cpu_name' in self.stats and 'cpu_hz_current' in self.stats and 'cpu_hz' in self.stats:
130
            msg_name = self.stats['cpu_name']
131
            if self.stats['cpu_hz_current'] and self.stats['cpu_hz']:
132
                msg_freq = ' - {:.2f}/{:.2f}GHz'.format(self._hz_to_ghz(self.stats['cpu_hz_current']),
133
                                                        self._hz_to_ghz(self.stats['cpu_hz']))
134
            else:
135
                msg_freq = ''
136
            if len(msg_name + msg_freq) - 6 <= max_width:
137
                ret.append(self.curse_add_line(msg_name))
138
            ret.append(self.curse_add_line(msg_freq))
139
            ret.append(self.curse_new_line())
140
        for key in ['cpu', 'mem', 'swap']:
141
            if key == 'cpu' and args.percpu:
142
                if sparkline_tag:
143
                    raw_cpu = self.get_raw_history(item='percpu', nb=data.size)
0 ignored issues
show
introduced by
The variable data does not seem to be defined in case self.args.sparkline and ...le() and BooleanNotNode on line 119 is False. Are you sure this can never be the case?
Loading history...
144
                for cpu_index, cpu in enumerate(self.stats['percpu']):
145
                    if sparkline_tag:
146
                        # Sparkline display an history
147
                        data.percents = [i[1][cpu_index]['total'] for i in raw_cpu]
0 ignored issues
show
introduced by
The variable raw_cpu does not seem to be defined for all execution paths.
Loading history...
148
                        # A simple padding in order to align metrics to the right
149
                        data.percents += [None] * (data.size - len(data.percents))
150
                    else:
151
                        # Bar only the last value
152
                        data.percent = cpu['total']
153
                    if cpu[cpu['key']] < 10:
154
                        msg = '{:3}{} '.format(key.upper(), cpu['cpu_number'])
155
                    else:
156
                        msg = '{:4} '.format(cpu['cpu_number'])
157
                    ret.extend(self._msg_create_line(msg, data, key))
158
                    ret.append(self.curse_new_line())
159
            else:
160
                if sparkline_tag:
161
                    # Sparkline display an history
162
                    data.percents = [i[1] for i in self.get_raw_history(item=key, nb=data.size)]
163
                    # A simple padding in order to align metrics to the right
164
                    data.percents += [None] * (data.size - len(data.percents))
165
                else:
166
                    # Bar only the last value
167
                    data.percent = self.stats[key]
168
                msg = '{:4} '.format(key.upper())
169
                ret.extend(self._msg_create_line(msg, data, key))
170
                ret.append(self.curse_new_line())
171
172
        # Remove the last new line
173
        ret.pop()
174
175
        # Return the message with decoration
176
        return ret
177
178
    def _msg_create_line(self, msg, data, key):
179
        """Create a new line to the Quickview."""
180
        ret = []
181
182
        ret.append(self.curse_add_line(msg))
183
        ret.append(self.curse_add_line(data.pre_char, decoration='BOLD'))
184
        ret.append(self.curse_add_line(data.get(), self.get_views(key=key, option='decoration')))
185
        ret.append(self.curse_add_line(data.post_char, decoration='BOLD'))
186
        ret.append(self.curse_add_line('  '))
187
188
        return ret
189
190
    def _hz_to_ghz(self, hz):
191
        """Convert Hz to Ghz."""
192
        return hz / 1000000000.0
193
194
    def _mhz_to_hz(self, hz):
195
        """Convert Mhz to Hz."""
196
        return hz * 1000000.0