1
|
|
|
# -*- coding: utf-8 -*- |
2
|
|
|
# |
3
|
|
|
# This file is part of Glances. |
4
|
|
|
# |
5
|
|
|
# SPDX-FileCopyrightText: 2022 Nicolas Hennion <[email protected]> |
6
|
|
|
# |
7
|
|
|
# SPDX-License-Identifier: LGPL-3.0-only |
8
|
|
|
# |
9
|
|
|
|
10
|
|
|
""" |
11
|
|
|
Help plugin. |
12
|
|
|
|
13
|
|
|
Just a stupid plugin to display the help screen. |
14
|
|
|
""" |
15
|
|
|
import sys |
16
|
|
|
from glances.globals import iteritems |
17
|
|
|
from glances import __version__, psutil_version |
18
|
|
|
from glances.plugins.plugin.model import GlancesPluginModel |
19
|
|
|
from itertools import chain |
20
|
|
|
|
21
|
|
|
|
22
|
|
|
class PluginModel(GlancesPluginModel): |
23
|
|
|
"""Glances help plugin.""" |
24
|
|
|
|
25
|
|
|
def __init__(self, args=None, config=None): |
26
|
|
|
"""Init the plugin.""" |
27
|
|
|
super(PluginModel, self).__init__(args=args, config=config) |
28
|
|
|
|
29
|
|
|
# Set the config instance |
30
|
|
|
self.config = config |
31
|
|
|
self.args = args |
32
|
|
|
|
33
|
|
|
# We want to display the stat in the curse interface |
34
|
|
|
self.display_curse = True |
35
|
|
|
|
36
|
|
|
# init data dictionary, to preserve insertion order |
37
|
|
|
if sys.version_info < (3, 6): |
38
|
|
|
from collections import OrderedDict |
39
|
|
|
|
40
|
|
|
self.view_data = OrderedDict() |
41
|
|
|
else: |
42
|
|
|
self.view_data = {} |
43
|
|
|
self.generate_view_data() |
44
|
|
|
|
45
|
|
|
def reset(self): |
46
|
|
|
"""No stats. It is just a plugin to display the help.""" |
47
|
|
|
|
48
|
|
|
def update(self): |
49
|
|
|
"""No stats. It is just a plugin to display the help.""" |
50
|
|
|
|
51
|
|
|
def generate_view_data(self): |
52
|
|
|
"""Generate the views.""" |
53
|
|
|
self.view_data['version'] = '{} {}'.format('Glances', __version__) |
54
|
|
|
self.view_data['psutil_version'] = ' with psutil {}'.format(psutil_version) |
55
|
|
|
|
56
|
|
|
try: |
57
|
|
|
self.view_data['configuration_file'] = 'Configuration file: {}'.format(self.config.loaded_config_file) |
58
|
|
|
except AttributeError: |
59
|
|
|
pass |
60
|
|
|
|
61
|
|
|
msg_col = ' {0:1} {1:34}' |
62
|
|
|
msg_header = '{0:39}' |
63
|
|
|
|
64
|
|
|
self.view_data.update( |
65
|
|
|
[ |
66
|
|
|
# First column |
67
|
|
|
# |
68
|
|
|
('header_sort', msg_header.format('SORT PROCESSES:')), |
69
|
|
|
('sort_auto', msg_col.format('a', 'Automatically')), |
70
|
|
|
('sort_cpu', msg_col.format('c', 'CPU%')), |
71
|
|
|
('sort_io_rate', msg_col.format('i', 'I/O rate')), |
72
|
|
|
('sort_mem', msg_col.format('m', 'MEM%')), |
73
|
|
|
('sort_process_name', msg_col.format('p', 'Process name')), |
74
|
|
|
('sort_cpu_times', msg_col.format('t', 'TIME')), |
75
|
|
|
('sort_user', msg_col.format('u', 'USER')), |
76
|
|
|
('header_show_hide', msg_header.format('SHOW/HIDE SECTION:')), |
77
|
|
|
('show_hide_application_monitoring', msg_col.format('A', 'Application monitoring')), |
78
|
|
|
('show_hide_diskio', msg_col.format('d', 'Disk I/O')), |
79
|
|
|
('show_hide_docker', msg_col.format('D', 'Docker')), |
80
|
|
|
('show_hide_top_extended_stats', msg_col.format('e', 'Top extended stats')), |
81
|
|
|
('show_hide_filesystem', msg_col.format('f', 'Filesystem')), |
82
|
|
|
('show_hide_gpu', msg_col.format('G', 'GPU')), |
83
|
|
|
('show_hide_ip', msg_col.format('I', 'IP')), |
84
|
|
|
('show_hide_tcp_connection', msg_col.format('K', 'TCP')), |
85
|
|
|
('show_hide_alert', msg_col.format('l', 'Alert logs')), |
86
|
|
|
('show_hide_network', msg_col.format('n', 'Network')), |
87
|
|
|
('show_hide_current_time', msg_col.format('N', 'Time')), |
88
|
|
|
('show_hide_irq', msg_col.format('Q', 'IRQ')), |
89
|
|
|
('show_hide_raid_plugin', msg_col.format('R', 'RAID')), |
90
|
|
|
('show_hide_sensors', msg_col.format('s', 'Sensors')), |
91
|
|
|
('show_hide_wifi_module', msg_col.format('W', 'Wifi')), |
92
|
|
|
('show_hide_processes', msg_col.format('z', 'Processes')), |
93
|
|
|
('show_hide_left_sidebar', msg_col.format('2', 'Left sidebar')), |
94
|
|
|
# Second column |
95
|
|
|
# |
96
|
|
|
('show_hide_quick_look', msg_col.format('3', 'Quick Look')), |
97
|
|
|
('show_hide_cpu_mem_swap', msg_col.format('4', 'CPU, MEM, and SWAP')), |
98
|
|
|
('show_hide_all', msg_col.format('5', 'ALL')), |
99
|
|
|
('header_toggle', msg_header.format('TOGGLE DATA TYPE:')), |
100
|
|
|
('toggle_bits_bytes', msg_col.format('b', 'Network I/O, bits/bytes')), |
101
|
|
|
('toggle_count_rate', msg_col.format('B', 'Disk I/O, count/rate')), |
102
|
|
|
('toggle_used_free', msg_col.format('F', 'Filesystem space, used/free')), |
103
|
|
|
('toggle_bar_sparkline', msg_col.format('S', 'Quick Look, bar/sparkline')), |
104
|
|
|
('toggle_separate_combined', msg_col.format('T', 'Network I/O, separate/combined')), |
105
|
|
|
('toggle_live_cumulative', msg_col.format('U', 'Network I/O, live/cumulative')), |
106
|
|
|
('toggle_linux_percentage', msg_col.format('0', 'Load, Linux/percentage')), |
107
|
|
|
('toggle_cpu_individual_combined', msg_col.format('1', 'CPU, individual/combined')), |
108
|
|
|
('toggle_gpu_individual_combined', msg_col.format('6', 'GPU, individual/combined')), |
109
|
|
|
( |
110
|
|
|
'toggle_short_full', |
111
|
|
|
( |
112
|
|
|
msg_col.format('S', 'Process names, short/full') |
113
|
|
|
if self.args and self.args.webserver |
114
|
|
|
else msg_col.format('/', 'Process names, short/full') |
115
|
|
|
), |
116
|
|
|
), |
117
|
|
|
('header_miscellaneous', msg_header.format('MISCELLANEOUS:')), |
118
|
|
|
( |
119
|
|
|
'misc_erase_process_filter', |
120
|
|
|
'' if self.args and self.args.webserver else msg_col.format('E', 'Erase process filter'), |
121
|
|
|
), |
122
|
|
|
( |
123
|
|
|
'misc_generate_history_graphs', |
124
|
|
|
'' if self.args and self.args.webserver else msg_col.format('g', 'Generate history graphs'), |
125
|
|
|
), |
126
|
|
|
('misc_help', msg_col.format('h', 'HELP')), |
127
|
|
|
( |
128
|
|
|
'misc_accumulate_processes_by_program', |
129
|
|
|
'' if self.args and self.args.webserver else msg_col.format('j', 'Display threads or programs'), |
130
|
|
|
), |
131
|
|
|
('misc_increase_nice_process', msg_col.format('+', 'Increase nice process')), |
132
|
|
|
('misc_decrease_nice_process', msg_col.format('-', 'Decrease nice process (need admin rights)')), |
133
|
|
|
('misc_kill_process', '' if self.args and self.args.webserver else msg_col.format('k', 'Kill process')), |
134
|
|
|
( |
135
|
|
|
'misc_reset_processes_summary_min_max', |
136
|
|
|
'' if self.args and self.args.webserver else msg_col.format('M', 'Reset processes summary min/max'), |
137
|
|
|
), |
138
|
|
|
( |
139
|
|
|
'misc_quit', |
140
|
|
|
'' if self.args and self.args.webserver else msg_col.format('q', 'QUIT (or Esc or Ctrl-C)'), |
141
|
|
|
), |
142
|
|
|
('misc_reset_history', msg_col.format('r', 'Reset history')), |
143
|
|
|
('misc_delete_warning_alerts', msg_col.format('w', 'Delete warning alerts')), |
144
|
|
|
('misc_delete_warning_and_critical_alerts', msg_col.format('x', 'Delete warning & critical alerts')), |
145
|
|
|
( |
146
|
|
|
'misc_edit_process_filter_pattern', |
147
|
|
|
'' if self.args and self.args.webserver else ' ENTER: Edit process filter pattern', |
148
|
|
|
), |
149
|
|
|
] |
150
|
|
|
) |
151
|
|
|
|
152
|
|
|
def get_view_data(self, args=None): |
153
|
|
|
"""Return the view.""" |
154
|
|
|
return self.view_data |
155
|
|
|
|
156
|
|
|
def msg_curse(self, args=None, max_width=None): |
157
|
|
|
"""Return the list to display in the curse interface.""" |
158
|
|
|
# Init the return message |
159
|
|
|
ret = [] |
160
|
|
|
|
161
|
|
|
# Build the header message |
162
|
|
|
ret.append(self.curse_add_line(self.view_data['version'], 'TITLE')) |
163
|
|
|
ret.append(self.curse_add_line(self.view_data['psutil_version'])) |
164
|
|
|
ret.append(self.curse_new_line()) |
165
|
|
|
|
166
|
|
|
# Build the configuration file path |
167
|
|
|
if 'configuration_file' in self.view_data: |
168
|
|
|
ret.append(self.curse_add_line(self.view_data['configuration_file'])) |
169
|
|
|
ret.append(self.curse_new_line()) |
170
|
|
|
|
171
|
|
|
ret.append(self.curse_new_line()) |
172
|
|
|
|
173
|
|
|
# key-shortcuts |
174
|
|
|
# |
175
|
|
|
# Collect all values after the 1st key-msg |
176
|
|
|
# in a list of curse-lines. |
177
|
|
|
# |
178
|
|
|
shortcuts = [] |
179
|
|
|
collecting = False |
180
|
|
|
for k, v in iteritems(self.view_data): |
181
|
|
|
if collecting: |
182
|
|
|
pass |
183
|
|
|
elif k == 'header_sort': |
184
|
|
|
collecting = True |
185
|
|
|
else: |
186
|
|
|
continue |
187
|
|
|
shortcuts.append(self.curse_add_line(v)) |
188
|
|
|
# Divide shortcuts into 2 columns |
189
|
|
|
# and if number of schortcuts is even, |
190
|
|
|
# make the 1st column taller (len+1). |
191
|
|
|
# |
192
|
|
|
nlines = (len(shortcuts) + 1) // 2 |
193
|
|
|
ret.extend( |
194
|
|
|
msg |
195
|
|
|
for triplet in zip( |
196
|
|
|
iter(shortcuts[:nlines]), |
197
|
|
|
chain(shortcuts[nlines:], iter(lambda: self.curse_add_line(''), None)), |
198
|
|
|
iter(self.curse_new_line, None), |
199
|
|
|
) |
200
|
|
|
for msg in triplet |
201
|
|
|
) |
202
|
|
|
|
203
|
|
|
ret.append(self.curse_new_line()) |
204
|
|
|
ret.append(self.curse_add_line('For an exhaustive list of key bindings:')) |
205
|
|
|
ret.append(self.curse_new_line()) |
206
|
|
|
ret.append(self.curse_add_line('https://glances.readthedocs.io/en/latest/cmds.html#interactive-commands')) |
207
|
|
|
ret.append(self.curse_new_line()) |
208
|
|
|
|
209
|
|
|
ret.append(self.curse_new_line()) |
210
|
|
|
ret.append(self.curse_add_line('Colors binding:')) |
211
|
|
|
ret.append(self.curse_new_line()) |
212
|
|
|
for c in [ |
213
|
|
|
'DEFAULT', |
214
|
|
|
'UNDERLINE', |
215
|
|
|
'BOLD', |
216
|
|
|
'SORT', |
217
|
|
|
'OK', |
218
|
|
|
'MAX', |
219
|
|
|
'FILTER', |
220
|
|
|
'TITLE', |
221
|
|
|
'PROCESS', |
222
|
|
|
'PROCESS_SELECTED', |
223
|
|
|
'STATUS', |
224
|
|
|
'NICE', |
225
|
|
|
'CPU_TIME', |
226
|
|
|
'CAREFUL', |
227
|
|
|
'WARNING', |
228
|
|
|
'CRITICAL', |
229
|
|
|
'OK_LOG', |
230
|
|
|
'CAREFUL_LOG', |
231
|
|
|
'WARNING_LOG', |
232
|
|
|
'CRITICAL_LOG', |
233
|
|
|
'PASSWORD', |
234
|
|
|
'SELECTED', |
235
|
|
|
'INFO', |
236
|
|
|
'ERROR', |
237
|
|
|
'SEPARATOR', |
238
|
|
|
]: |
239
|
|
|
ret.append(self.curse_add_line(c, decoration=c)) |
240
|
|
|
if c == 'CPU_TIME': |
241
|
|
|
ret.append(self.curse_new_line()) |
242
|
|
|
else: |
243
|
|
|
ret.append(self.curse_add_line(' ')) |
244
|
|
|
|
245
|
|
|
# Return the message with decoration |
246
|
|
|
return ret |
247
|
|
|
|