|
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
|
|
|
('toggle_short_full', |
|
110
|
|
|
msg_col.format('S', |
|
111
|
|
|
'Process names, short/full') if self.args.webserver else msg_col.format('/', 'Process names, short/full')), |
|
112
|
|
|
('header_miscellaneous', msg_header.format('MISCELLANEOUS:')), |
|
113
|
|
|
('misc_erase_process_filter', |
|
114
|
|
|
'' if self.args.webserver else msg_col.format('E', 'Erase process filter')), |
|
115
|
|
|
('misc_generate_history_graphs', |
|
116
|
|
|
'' if self.args.webserver else msg_col.format('g', 'Generate history graphs')), |
|
117
|
|
|
('misc_help', msg_col.format('h', 'HELP')), |
|
118
|
|
|
('misc_accumulate_processes_by_program', |
|
119
|
|
|
'' if self.args.webserver else msg_col.format('j', 'Display threads or programs')), |
|
120
|
|
|
('misc_increase_nice_process', msg_col.format('+', 'Increase nice process')), |
|
121
|
|
|
('misc_decrease_nice_process', msg_col.format('-', 'Decrease nice process (need admin rights)')), |
|
122
|
|
|
('misc_kill_process', |
|
123
|
|
|
'' if self.args.webserver else msg_col.format('k', 'Kill process')), |
|
124
|
|
|
('misc_reset_processes_summary_min_max', |
|
125
|
|
|
'' if self.args.webserver else msg_col.format('M', 'Reset processes summary min/max')), |
|
126
|
|
|
('misc_quit', |
|
127
|
|
|
'' if self.args.webserver else msg_col.format('q', 'QUIT (or Esc or Ctrl-C)')), |
|
128
|
|
|
('misc_reset_history', msg_col.format('r', 'Reset history')), |
|
129
|
|
|
('misc_delete_warning_alerts', msg_col.format('w', 'Delete warning alerts')), |
|
130
|
|
|
('misc_delete_warning_and_critical_alerts', msg_col.format('x', 'Delete warning & critical alerts')), |
|
131
|
|
|
('misc_edit_process_filter_pattern', |
|
132
|
|
|
'' if self.args.webserver else ' ENTER: Edit process filter pattern'), |
|
133
|
|
|
] |
|
134
|
|
|
) |
|
135
|
|
|
|
|
136
|
|
|
def get_view_data(self, args=None): |
|
137
|
|
|
"""Return the view.""" |
|
138
|
|
|
return self.view_data |
|
139
|
|
|
|
|
140
|
|
|
def msg_curse(self, args=None, max_width=None): |
|
141
|
|
|
"""Return the list to display in the curse interface.""" |
|
142
|
|
|
# Init the return message |
|
143
|
|
|
ret = [] |
|
144
|
|
|
|
|
145
|
|
|
# Build the header message |
|
146
|
|
|
ret.append(self.curse_add_line(self.view_data['version'], 'TITLE')) |
|
147
|
|
|
ret.append(self.curse_add_line(self.view_data['psutil_version'])) |
|
148
|
|
|
ret.append(self.curse_new_line()) |
|
149
|
|
|
|
|
150
|
|
|
# Build the configuration file path |
|
151
|
|
|
if 'configuration_file' in self.view_data: |
|
152
|
|
|
ret.append(self.curse_add_line(self.view_data['configuration_file'])) |
|
153
|
|
|
ret.append(self.curse_new_line()) |
|
154
|
|
|
|
|
155
|
|
|
ret.append(self.curse_new_line()) |
|
156
|
|
|
|
|
157
|
|
|
# key-shortcuts |
|
158
|
|
|
# |
|
159
|
|
|
# Collect all values after the 1st key-msg |
|
160
|
|
|
# in a list of curse-lines. |
|
161
|
|
|
# |
|
162
|
|
|
shortcuts = [] |
|
163
|
|
|
collecting = False |
|
164
|
|
|
for k, v in iteritems(self.view_data): |
|
165
|
|
|
if collecting: |
|
166
|
|
|
pass |
|
167
|
|
|
elif k == 'header_sort': |
|
168
|
|
|
collecting = True |
|
169
|
|
|
else: |
|
170
|
|
|
continue |
|
171
|
|
|
shortcuts.append(self.curse_add_line(v)) |
|
172
|
|
|
# Divide shortcuts into 2 columns |
|
173
|
|
|
# and if number of schortcuts is even, |
|
174
|
|
|
# make the 1st column taller (len+1). |
|
175
|
|
|
# |
|
176
|
|
|
nlines = (len(shortcuts) + 1) // 2 |
|
177
|
|
|
ret.extend( |
|
178
|
|
|
msg |
|
179
|
|
|
for triplet in zip( |
|
180
|
|
|
iter(shortcuts[:nlines]), |
|
181
|
|
|
chain(shortcuts[nlines:], iter(lambda: self.curse_add_line(''), None)), |
|
182
|
|
|
iter(self.curse_new_line, None), |
|
183
|
|
|
) |
|
184
|
|
|
for msg in triplet |
|
185
|
|
|
) |
|
186
|
|
|
|
|
187
|
|
|
ret.append(self.curse_new_line()) |
|
188
|
|
|
ret.append(self.curse_add_line('For an exhaustive list of key bindings:')) |
|
189
|
|
|
ret.append(self.curse_new_line()) |
|
190
|
|
|
ret.append(self.curse_add_line('https://glances.readthedocs.io/en/latest/cmds.html#interactive-commands')) |
|
191
|
|
|
ret.append(self.curse_new_line()) |
|
192
|
|
|
|
|
193
|
|
|
ret.append(self.curse_new_line()) |
|
194
|
|
|
ret.append(self.curse_add_line('Colors binding:')) |
|
195
|
|
|
ret.append(self.curse_new_line()) |
|
196
|
|
|
for c in [ |
|
197
|
|
|
'DEFAULT', |
|
198
|
|
|
'UNDERLINE', |
|
199
|
|
|
'BOLD', |
|
200
|
|
|
'SORT', |
|
201
|
|
|
'OK', |
|
202
|
|
|
'MAX', |
|
203
|
|
|
'FILTER', |
|
204
|
|
|
'TITLE', |
|
205
|
|
|
'PROCESS', |
|
206
|
|
|
'PROCESS_SELECTED', |
|
207
|
|
|
'STATUS', |
|
208
|
|
|
'NICE', |
|
209
|
|
|
'CPU_TIME', |
|
210
|
|
|
'CAREFUL', |
|
211
|
|
|
'WARNING', |
|
212
|
|
|
'CRITICAL', |
|
213
|
|
|
'OK_LOG', |
|
214
|
|
|
'CAREFUL_LOG', |
|
215
|
|
|
'WARNING_LOG', |
|
216
|
|
|
'CRITICAL_LOG', |
|
217
|
|
|
'PASSWORD', |
|
218
|
|
|
'SELECTED', |
|
219
|
|
|
'INFO', |
|
220
|
|
|
'ERROR', |
|
221
|
|
|
'SEPARATOR', |
|
222
|
|
|
]: |
|
223
|
|
|
ret.append(self.curse_add_line(c, decoration=c)) |
|
224
|
|
|
if c == 'CPU_TIME': |
|
225
|
|
|
ret.append(self.curse_new_line()) |
|
226
|
|
|
else: |
|
227
|
|
|
ret.append(self.curse_add_line(' ')) |
|
228
|
|
|
|
|
229
|
|
|
# Return the message with decoration |
|
230
|
|
|
return ret |
|
231
|
|
|
|