1
|
|
|
# -*- coding: utf-8 -*- |
2
|
|
|
# |
3
|
|
|
# This file is part of Glances. |
4
|
|
|
# |
5
|
|
|
# SPDX-FileCopyrightText: 2024 Nicolas Hennion <[email protected]> |
6
|
|
|
# |
7
|
|
|
# SPDX-License-Identifier: LGPL-3.0-only |
8
|
|
|
# |
9
|
|
|
|
10
|
|
|
"""Glances main class.""" |
11
|
|
|
|
12
|
|
|
import argparse |
13
|
|
|
import sys |
14
|
|
|
import tempfile |
15
|
|
|
from logging import DEBUG |
16
|
|
|
from warnings import simplefilter |
17
|
|
|
|
18
|
|
|
from glances import __version__, psutil_version, __apiversion__ |
19
|
|
|
from glances.globals import WINDOWS, disable, enable |
20
|
|
|
from glances.config import Config |
21
|
|
|
from glances.processes import sort_processes_key_list |
22
|
|
|
from glances.logger import logger, LOG_FILENAME |
23
|
|
|
|
24
|
|
|
|
25
|
|
|
class GlancesMain(object): |
26
|
|
|
"""Main class to manage Glances instance.""" |
27
|
|
|
|
28
|
|
|
# Default stats' minimum refresh time is 2 seconds |
29
|
|
|
DEFAULT_REFRESH_TIME = 2 |
30
|
|
|
# Set the default cache lifetime to 1 second (only for server) |
31
|
|
|
cached_time = 1 |
32
|
|
|
# By default, Glances is ran in standalone mode (no client/server) |
33
|
|
|
client_tag = False |
34
|
|
|
# Server TCP port number (default is 61209) |
35
|
|
|
server_port = 61209 |
36
|
|
|
# Web Server TCP port number (default is 61208) |
37
|
|
|
web_server_port = 61208 |
38
|
|
|
# Default username/password for client/server mode |
39
|
|
|
username = "glances" |
40
|
|
|
password = "" |
41
|
|
|
|
42
|
|
|
# Examples of use |
43
|
|
|
example_of_use = """ |
44
|
|
|
Examples of use: |
45
|
|
|
Monitor local machine (standalone mode): |
46
|
|
|
$ glances |
47
|
|
|
|
48
|
|
|
Display all Glances modules (plugins and exporters) and exit: |
49
|
|
|
$ glances --module-list |
50
|
|
|
|
51
|
|
|
Monitor local machine with the Web interface and start RESTful server: |
52
|
|
|
$ glances -w |
53
|
|
|
Glances web server started on http://0.0.0.0:61208/ |
54
|
|
|
|
55
|
|
|
Only start RESTful API (without the WebUI): |
56
|
|
|
$ glances -w --disable-webui |
57
|
|
|
Glances API available on http://0.0.0.0:61208/api/ |
58
|
|
|
|
59
|
|
|
Monitor local machine and export stats to a CSV file (standalone mode): |
60
|
|
|
$ glances --export csv --export-csv-file /tmp/glances.csv |
61
|
|
|
|
62
|
|
|
Monitor local machine and export stats to a InfluxDB server with 5s refresh rate (standalone mode): |
63
|
|
|
$ glances -t 5 --export influxdb |
64
|
|
|
|
65
|
|
|
Start a Glances XML-RPC server (server mode): |
66
|
|
|
$ glances -s |
67
|
|
|
|
68
|
|
|
Connect Glances to a Glances XML-RPC server (client mode): |
69
|
|
|
$ glances -c <ip_server> |
70
|
|
|
|
71
|
|
|
Connect Glances to a Glances server and export stats to a StatsD server (client mode): |
72
|
|
|
$ glances -c <ip_server> --export statsd |
73
|
|
|
|
74
|
|
|
Start the client browser (browser mode): |
75
|
|
|
$ glances --browser |
76
|
|
|
|
77
|
|
|
Display stats to stdout (one stat per line, possible to go inside stats using plugin.attribute): |
78
|
|
|
$ glances --stdout now,cpu.user,mem.used,load |
79
|
|
|
|
80
|
|
|
Display JSON stats to stdout (one stats per line): |
81
|
|
|
$ glances --stdout-json now,cpu,mem,load |
82
|
|
|
|
83
|
|
|
Display CSV stats to stdout (all stats in one line): |
84
|
|
|
$ glances --stdout-csv now,cpu.user,mem.used,load |
85
|
|
|
|
86
|
|
|
Enable some plugins disabled by default (comma-separated list): |
87
|
|
|
$ glances --enable-plugin sensors |
88
|
|
|
|
89
|
|
|
Disable some plugins (comma-separated list): |
90
|
|
|
$ glances --disable-plugin network,ports |
91
|
|
|
|
92
|
|
|
Disable all plugins except some (comma-separated list): |
93
|
|
|
$ glances --disable-plugin all --enable-plugin cpu,mem,load |
94
|
|
|
|
95
|
|
|
""" |
96
|
|
|
|
97
|
|
|
def __init__(self): |
98
|
|
|
"""Manage the command line arguments.""" |
99
|
|
|
# Read the command line arguments |
100
|
|
|
self.args = self.parse_args() |
101
|
|
|
|
102
|
|
|
def version_msg(self): |
103
|
|
|
"""Return the version message.""" |
104
|
|
|
version = 'Glances version:\t{}\n'.format(__version__) |
105
|
|
|
version += 'Glances API version:\t{}\n'.format(__apiversion__) |
106
|
|
|
version += 'PsUtil version:\t\t{}\n'.format(psutil_version) |
107
|
|
|
version += 'Log file:\t\t{}\n'.format(LOG_FILENAME) |
108
|
|
|
return version |
109
|
|
|
|
110
|
|
|
def init_args(self): |
111
|
|
|
"""Init all the command line arguments.""" |
112
|
|
|
parser = argparse.ArgumentParser( |
113
|
|
|
prog='glances', |
114
|
|
|
conflict_handler='resolve', |
115
|
|
|
formatter_class=argparse.RawDescriptionHelpFormatter, |
116
|
|
|
epilog=self.example_of_use, |
117
|
|
|
) |
118
|
|
|
parser.add_argument('-V', '--version', action='version', version=self.version_msg()) |
119
|
|
|
parser.add_argument('-d', '--debug', action='store_true', default=False, dest='debug', help='enable debug mode') |
120
|
|
|
parser.add_argument('-C', '--config', dest='conf_file', help='path to the configuration file') |
121
|
|
|
parser.add_argument('-P', '--plugins', dest='plugin_dir', help='path to additional plugin directory') |
122
|
|
|
# Disable plugin |
123
|
|
|
parser.add_argument( |
124
|
|
|
'--modules-list', |
125
|
|
|
'--module-list', |
126
|
|
|
action='store_true', |
127
|
|
|
default=False, |
128
|
|
|
dest='modules_list', |
129
|
|
|
help='display modules (plugins & exports) list and exit', |
130
|
|
|
) |
131
|
|
|
parser.add_argument( |
132
|
|
|
'--disable-plugin', |
133
|
|
|
'--disable-plugins', |
134
|
|
|
'--disable', |
135
|
|
|
dest='disable_plugin', |
136
|
|
|
help='disable plugin (comma-separated list or all). If all is used, \ |
137
|
|
|
then you need to configure --enable-plugin.', |
138
|
|
|
) |
139
|
|
|
parser.add_argument( |
140
|
|
|
'--enable-plugin', |
141
|
|
|
'--enable-plugins', |
142
|
|
|
'--enable', |
143
|
|
|
dest='enable_plugin', |
144
|
|
|
help='enable plugin (comma-separated list)', |
145
|
|
|
) |
146
|
|
|
parser.add_argument( |
147
|
|
|
'--disable-process', |
148
|
|
|
action='store_true', |
149
|
|
|
default=False, |
150
|
|
|
dest='disable_process', |
151
|
|
|
help='disable process module', |
152
|
|
|
) |
153
|
|
|
# Enable or disable option |
154
|
|
|
parser.add_argument( |
155
|
|
|
'--disable-webui', |
156
|
|
|
action='store_true', |
157
|
|
|
default=False, |
158
|
|
|
dest='disable_webui', |
159
|
|
|
help='disable the Web Interface', |
160
|
|
|
) |
161
|
|
|
parser.add_argument( |
162
|
|
|
'--light', |
163
|
|
|
'--enable-light', |
164
|
|
|
action='store_true', |
165
|
|
|
default=False, |
166
|
|
|
dest='enable_light', |
167
|
|
|
help='light mode for Curses UI (disable all but the top menu)', |
168
|
|
|
) |
169
|
|
|
parser.add_argument( |
170
|
|
|
'-0', |
171
|
|
|
'--disable-irix', |
172
|
|
|
action='store_true', |
173
|
|
|
default=False, |
174
|
|
|
dest='disable_irix', |
175
|
|
|
help='task\'s cpu usage will be divided by the total number of CPUs', |
176
|
|
|
) |
177
|
|
|
parser.add_argument( |
178
|
|
|
'-1', |
179
|
|
|
'--percpu', |
180
|
|
|
'--per-cpu', |
181
|
|
|
action='store_true', |
182
|
|
|
default=False, |
183
|
|
|
dest='percpu', |
184
|
|
|
help='start Glances in per CPU mode', |
185
|
|
|
) |
186
|
|
|
parser.add_argument( |
187
|
|
|
'-2', |
188
|
|
|
'--disable-left-sidebar', |
189
|
|
|
action='store_true', |
190
|
|
|
default=False, |
191
|
|
|
dest='disable_left_sidebar', |
192
|
|
|
help='disable network, disk I/O, FS and sensors modules', |
193
|
|
|
) |
194
|
|
|
parser.add_argument( |
195
|
|
|
'-3', |
196
|
|
|
'--disable-quicklook', |
197
|
|
|
action='store_true', |
198
|
|
|
default=False, |
199
|
|
|
dest='disable_quicklook', |
200
|
|
|
help='disable quick look module', |
201
|
|
|
) |
202
|
|
|
parser.add_argument( |
203
|
|
|
'-4', |
204
|
|
|
'--full-quicklook', |
205
|
|
|
action='store_true', |
206
|
|
|
default=False, |
207
|
|
|
dest='full_quicklook', |
208
|
|
|
help='disable all but quick look and load', |
209
|
|
|
) |
210
|
|
|
parser.add_argument( |
211
|
|
|
'-5', |
212
|
|
|
'--disable-top', |
213
|
|
|
action='store_true', |
214
|
|
|
default=False, |
215
|
|
|
dest='disable_top', |
216
|
|
|
help='disable top menu (QL, CPU, MEM, SWAP and LOAD)', |
217
|
|
|
) |
218
|
|
|
parser.add_argument( |
219
|
|
|
'-6', '--meangpu', action='store_true', default=False, dest='meangpu', help='start Glances in mean GPU mode' |
220
|
|
|
) |
221
|
|
|
parser.add_argument( |
222
|
|
|
'--disable-history', |
223
|
|
|
action='store_true', |
224
|
|
|
default=False, |
225
|
|
|
dest='disable_history', |
226
|
|
|
help='disable stats history', |
227
|
|
|
) |
228
|
|
|
parser.add_argument( |
229
|
|
|
'--disable-bold', |
230
|
|
|
action='store_true', |
231
|
|
|
default=False, |
232
|
|
|
dest='disable_bold', |
233
|
|
|
help='disable bold mode in the terminal', |
234
|
|
|
) |
235
|
|
|
parser.add_argument( |
236
|
|
|
'--disable-bg', |
237
|
|
|
action='store_true', |
238
|
|
|
default=False, |
239
|
|
|
dest='disable_bg', |
240
|
|
|
help='disable background colors in the terminal', |
241
|
|
|
) |
242
|
|
|
parser.add_argument( |
243
|
|
|
'--enable-irq', action='store_true', default=False, dest='enable_irq', help='enable IRQ module' |
244
|
|
|
), |
245
|
|
|
parser.add_argument( |
246
|
|
|
'--enable-process-extended', |
247
|
|
|
action='store_true', |
248
|
|
|
default=False, |
249
|
|
|
dest='enable_process_extended', |
250
|
|
|
help='enable extended stats on top process', |
251
|
|
|
) |
252
|
|
|
parser.add_argument( |
253
|
|
|
'--disable-separator', |
254
|
|
|
action='store_false', |
255
|
|
|
default=True, |
256
|
|
|
dest='enable_separator', |
257
|
|
|
help='disable separator in the UI (between top and others modules)', |
258
|
|
|
), |
259
|
|
|
parser.add_argument( |
260
|
|
|
'--disable-cursor', |
261
|
|
|
action='store_true', |
262
|
|
|
default=False, |
263
|
|
|
dest='disable_cursor', |
264
|
|
|
help='disable cursor (process selection) in the UI', |
265
|
|
|
), |
266
|
|
|
# Sort processes list |
267
|
|
|
parser.add_argument( |
268
|
|
|
'--sort-processes', |
269
|
|
|
dest='sort_processes_key', |
270
|
|
|
choices=sort_processes_key_list, |
271
|
|
|
help='Sort processes by: {}'.format(', '.join(sort_processes_key_list)), |
272
|
|
|
) |
273
|
|
|
# Display processes list by program name and not by thread |
274
|
|
|
parser.add_argument( |
275
|
|
|
'--programs', |
276
|
|
|
'--program', |
277
|
|
|
action='store_true', |
278
|
|
|
default=False, |
279
|
|
|
dest='programs', |
280
|
|
|
help='Accumulate processes by program', |
281
|
|
|
) |
282
|
|
|
# Export modules feature |
283
|
|
|
parser.add_argument('--export', dest='export', help='enable export module (comma-separated list)') |
284
|
|
|
parser.add_argument( |
285
|
|
|
'--export-csv-file', default='./glances.csv', dest='export_csv_file', help='file path for CSV exporter' |
286
|
|
|
) |
287
|
|
|
parser.add_argument( |
288
|
|
|
'--export-csv-overwrite', |
289
|
|
|
action='store_true', |
290
|
|
|
default=False, |
291
|
|
|
dest='export_csv_overwrite', |
292
|
|
|
help='overwrite existing CSV file', |
293
|
|
|
) |
294
|
|
|
parser.add_argument( |
295
|
|
|
'--export-json-file', default='./glances.json', dest='export_json_file', help='file path for JSON exporter' |
296
|
|
|
) |
297
|
|
|
parser.add_argument( |
298
|
|
|
'--export-graph-path', |
299
|
|
|
default=tempfile.gettempdir(), |
300
|
|
|
dest='export_graph_path', |
301
|
|
|
help='Folder for Graph exporter', |
302
|
|
|
) |
303
|
|
|
parser.add_argument( |
304
|
|
|
'--export-process-filter', |
305
|
|
|
default=None, |
306
|
|
|
type=str, |
307
|
|
|
dest='export_process_filter', |
308
|
|
|
help='set the export process filter (comman separated list of regular expression)', |
309
|
|
|
) |
310
|
|
|
# Client/Server option |
311
|
|
|
parser.add_argument( |
312
|
|
|
'-c', '--client', dest='client', help='connect to a Glances server by IPv4/IPv6 address or hostname' |
313
|
|
|
) |
314
|
|
|
parser.add_argument( |
315
|
|
|
'-s', '--server', action='store_true', default=False, dest='server', help='run Glances in server mode' |
316
|
|
|
) |
317
|
|
|
parser.add_argument( |
318
|
|
|
'--browser', |
319
|
|
|
action='store_true', |
320
|
|
|
default=False, |
321
|
|
|
dest='browser', |
322
|
|
|
help='start the client browser (list of servers)', |
323
|
|
|
) |
324
|
|
|
parser.add_argument( |
325
|
|
|
'--disable-autodiscover', |
326
|
|
|
action='store_true', |
327
|
|
|
default=False, |
328
|
|
|
dest='disable_autodiscover', |
329
|
|
|
help='disable autodiscover feature', |
330
|
|
|
) |
331
|
|
|
parser.add_argument( |
332
|
|
|
'-p', |
333
|
|
|
'--port', |
334
|
|
|
default=None, |
335
|
|
|
type=int, |
336
|
|
|
dest='port', |
337
|
|
|
help='define the client/server TCP port [default: {}]'.format(self.server_port), |
338
|
|
|
) |
339
|
|
|
parser.add_argument( |
340
|
|
|
'-B', |
341
|
|
|
'--bind', |
342
|
|
|
default='0.0.0.0', |
343
|
|
|
dest='bind_address', |
344
|
|
|
help='bind server to the given IPv4/IPv6 address or hostname', |
345
|
|
|
) |
346
|
|
|
parser.add_argument( |
347
|
|
|
'--username', |
348
|
|
|
action='store_true', |
349
|
|
|
default=False, |
350
|
|
|
dest='username_prompt', |
351
|
|
|
help='define a client/server username', |
352
|
|
|
) |
353
|
|
|
parser.add_argument( |
354
|
|
|
'--password', |
355
|
|
|
action='store_true', |
356
|
|
|
default=False, |
357
|
|
|
dest='password_prompt', |
358
|
|
|
help='define a client/server password', |
359
|
|
|
) |
360
|
|
|
parser.add_argument('-u', dest='username_used', help='use the given client/server username') |
361
|
|
|
parser.add_argument('--snmp-community', default='public', dest='snmp_community', help='SNMP community') |
362
|
|
|
parser.add_argument('--snmp-port', default=161, type=int, dest='snmp_port', help='SNMP port') |
363
|
|
|
parser.add_argument('--snmp-version', default='2c', dest='snmp_version', help='SNMP version (1, 2c or 3)') |
364
|
|
|
parser.add_argument('--snmp-user', default='private', dest='snmp_user', help='SNMP username (only for SNMPv3)') |
365
|
|
|
parser.add_argument( |
366
|
|
|
'--snmp-auth', default='password', dest='snmp_auth', help='SNMP authentication key (only for SNMPv3)' |
367
|
|
|
) |
368
|
|
|
parser.add_argument( |
369
|
|
|
'--snmp-force', action='store_true', default=False, dest='snmp_force', help='force SNMP mode' |
370
|
|
|
) |
371
|
|
|
parser.add_argument( |
372
|
|
|
'-t', |
373
|
|
|
'--time', |
374
|
|
|
default=self.DEFAULT_REFRESH_TIME, |
375
|
|
|
type=float, |
376
|
|
|
dest='time', |
377
|
|
|
help='set minimum refresh rate in seconds [default: {} sec]'.format(self.DEFAULT_REFRESH_TIME), |
378
|
|
|
) |
379
|
|
|
parser.add_argument( |
380
|
|
|
'-w', |
381
|
|
|
'--webserver', |
382
|
|
|
action='store_true', |
383
|
|
|
default=False, |
384
|
|
|
dest='webserver', |
385
|
|
|
help='run Glances in web server mode (FastAPI, Uvicorn, Jinja2 and OrJsonLib needed)', |
386
|
|
|
) |
387
|
|
|
parser.add_argument( |
388
|
|
|
'--cached-time', |
389
|
|
|
default=self.cached_time, |
390
|
|
|
type=int, |
391
|
|
|
dest='cached_time', |
392
|
|
|
help='set the server cache time [default: {} sec]'.format(self.cached_time), |
393
|
|
|
) |
394
|
|
|
parser.add_argument( |
395
|
|
|
'--stop-after', |
396
|
|
|
default=None, |
397
|
|
|
type=int, |
398
|
|
|
dest='stop_after', |
399
|
|
|
help='stop Glances after n refresh', |
400
|
|
|
) |
401
|
|
|
parser.add_argument( |
402
|
|
|
'--open-web-browser', |
403
|
|
|
action='store_true', |
404
|
|
|
default=False, |
405
|
|
|
dest='open_web_browser', |
406
|
|
|
help='try to open the Web UI in the default Web browser', |
407
|
|
|
) |
408
|
|
|
# Display options |
409
|
|
|
parser.add_argument( |
410
|
|
|
'-q', |
411
|
|
|
'--quiet', |
412
|
|
|
default=False, |
413
|
|
|
action='store_true', |
414
|
|
|
dest='quiet', |
415
|
|
|
help='do not display the curses interface', |
416
|
|
|
) |
417
|
|
|
parser.add_argument( |
418
|
|
|
'-f', |
419
|
|
|
'--process-filter', |
420
|
|
|
default=None, |
421
|
|
|
type=str, |
422
|
|
|
dest='process_filter', |
423
|
|
|
help='set the process filter pattern (regular expression)', |
424
|
|
|
) |
425
|
|
|
parser.add_argument( |
426
|
|
|
'--process-short-name', |
427
|
|
|
action='store_true', |
428
|
|
|
default=True, |
429
|
|
|
dest='process_short_name', |
430
|
|
|
help='force short name for processes name', |
431
|
|
|
) |
432
|
|
|
parser.add_argument( |
433
|
|
|
'--process-long-name', |
434
|
|
|
action='store_false', |
435
|
|
|
default=False, |
436
|
|
|
dest='process_short_name', |
437
|
|
|
help='force long name for processes name', |
438
|
|
|
) |
439
|
|
|
parser.add_argument( |
440
|
|
|
'--stdout', |
441
|
|
|
default=None, |
442
|
|
|
dest='stdout', |
443
|
|
|
help='display stats to stdout, one stat per line (comma-separated list of plugins/plugins.attribute)', |
444
|
|
|
) |
445
|
|
|
parser.add_argument( |
446
|
|
|
'--stdout-json', |
447
|
|
|
default=None, |
448
|
|
|
dest='stdout_json', |
449
|
|
|
help='display stats to stdout, JSON format (comma-separated list of plugins/plugins.attribute)', |
450
|
|
|
) |
451
|
|
|
parser.add_argument( |
452
|
|
|
'--stdout-csv', |
453
|
|
|
default=None, |
454
|
|
|
dest='stdout_csv', |
455
|
|
|
help='display stats to stdout, CSV format (comma-separated list of plugins/plugins.attribute)', |
456
|
|
|
) |
457
|
|
|
parser.add_argument( |
458
|
|
|
'--issue', |
459
|
|
|
default=None, |
460
|
|
|
action='store_true', |
461
|
|
|
dest='stdout_issue', |
462
|
|
|
help='test all plugins and exit (please copy/paste the output if you open an issue)', |
463
|
|
|
) |
464
|
|
|
parser.add_argument( |
465
|
|
|
'--trace-malloc', |
466
|
|
|
default=False, |
467
|
|
|
action='store_true', |
468
|
|
|
dest='trace_malloc', |
469
|
|
|
help='trace memory allocation and display it at the end of the process (python 3.4 or higher needed)', |
470
|
|
|
) |
471
|
|
|
parser.add_argument( |
472
|
|
|
'--memory-leak', |
473
|
|
|
default=False, |
474
|
|
|
action='store_true', |
475
|
|
|
dest='memory_leak', |
476
|
|
|
help='test memory leak (python 3.4 or higher needed)', |
477
|
|
|
) |
478
|
|
|
parser.add_argument( |
479
|
|
|
'--api-doc', default=None, action='store_true', dest='stdout_apidoc', help='display fields descriptions' |
480
|
|
|
) |
481
|
|
|
if not WINDOWS: |
482
|
|
|
parser.add_argument( |
483
|
|
|
'--hide-kernel-threads', |
484
|
|
|
action='store_true', |
485
|
|
|
default=False, |
486
|
|
|
dest='no_kernel_threads', |
487
|
|
|
help='hide kernel threads in the process list (not available on Windows)', |
488
|
|
|
) |
489
|
|
|
parser.add_argument( |
490
|
|
|
'-b', |
491
|
|
|
'--byte', |
492
|
|
|
action='store_true', |
493
|
|
|
default=False, |
494
|
|
|
dest='byte', |
495
|
|
|
help='display network rate in bytes per second', |
496
|
|
|
) |
497
|
|
|
parser.add_argument( |
498
|
|
|
'--diskio-show-ramfs', |
499
|
|
|
action='store_true', |
500
|
|
|
default=False, |
501
|
|
|
dest='diskio_show_ramfs', |
502
|
|
|
help='show RAM Fs in the DiskIO plugin', |
503
|
|
|
) |
504
|
|
|
parser.add_argument( |
505
|
|
|
'--diskio-iops', |
506
|
|
|
action='store_true', |
507
|
|
|
default=False, |
508
|
|
|
dest='diskio_iops', |
509
|
|
|
help='show IO per second in the DiskIO plugin', |
510
|
|
|
) |
511
|
|
|
parser.add_argument( |
512
|
|
|
'--fahrenheit', |
513
|
|
|
action='store_true', |
514
|
|
|
default=False, |
515
|
|
|
dest='fahrenheit', |
516
|
|
|
help='display temperature in Fahrenheit (default is Celsius)', |
517
|
|
|
) |
518
|
|
|
parser.add_argument( |
519
|
|
|
'--fs-free-space', |
520
|
|
|
action='store_true', |
521
|
|
|
default=False, |
522
|
|
|
dest='fs_free_space', |
523
|
|
|
help='display FS free space instead of used', |
524
|
|
|
) |
525
|
|
|
parser.add_argument( |
526
|
|
|
'--sparkline', |
527
|
|
|
action='store_true', |
528
|
|
|
default=False, |
529
|
|
|
dest='sparkline', |
530
|
|
|
help='display sparklines instead of bar in the curses interface', |
531
|
|
|
) |
532
|
|
|
parser.add_argument( |
533
|
|
|
'--disable-unicode', |
534
|
|
|
action='store_true', |
535
|
|
|
default=False, |
536
|
|
|
dest='disable_unicode', |
537
|
|
|
help='disable unicode characters in the curses interface', |
538
|
|
|
) |
539
|
|
|
parser.add_argument( |
540
|
|
|
'--hide-public-info', |
541
|
|
|
action='store_true', |
542
|
|
|
default=False, |
543
|
|
|
help='hide public information (like public IP)', |
544
|
|
|
) |
545
|
|
|
# Globals options |
546
|
|
|
parser.add_argument( |
547
|
|
|
'--disable-check-update', |
548
|
|
|
action='store_true', |
549
|
|
|
default=False, |
550
|
|
|
dest='disable_check_update', |
551
|
|
|
help='disable online Glances version ckeck', |
552
|
|
|
) |
553
|
|
|
parser.add_argument( |
554
|
|
|
'--strftime', |
555
|
|
|
dest='strftime_format', |
556
|
|
|
default='', |
557
|
|
|
help='strftime format string for displaying current date in standalone mode', |
558
|
|
|
) |
559
|
|
|
|
560
|
|
|
return parser |
561
|
|
|
|
562
|
|
|
def init_debug(self, args): |
563
|
|
|
"""Init Glances debug mode.""" |
564
|
|
|
if args.debug: |
565
|
|
|
logger.setLevel(DEBUG) |
566
|
|
|
else: |
567
|
|
|
simplefilter("ignore") |
568
|
|
|
|
569
|
|
|
def init_refresh_rate(self, args): |
570
|
|
|
"""Init Glances refresh rate""" |
571
|
|
|
if self.config.has_section('global'): |
572
|
|
|
global_refresh = self.config.get_float_value('global', 'refresh', default=self.DEFAULT_REFRESH_TIME) |
573
|
|
|
else: |
574
|
|
|
global_refresh = self.DEFAULT_REFRESH_TIME |
575
|
|
|
|
576
|
|
|
# The configuration key can be overwrite from the command line (-t <time>) |
577
|
|
|
if args.time == self.DEFAULT_REFRESH_TIME: |
578
|
|
|
args.time = global_refresh |
579
|
|
|
|
580
|
|
|
logger.debug('Global refresh rate is set to {} seconds'.format(args.time)) |
581
|
|
|
|
582
|
|
|
def init_plugins(self, args): |
583
|
|
|
"""Init Glances plugins""" |
584
|
|
|
# Allow users to disable plugins from the glances.conf (issue #1378) |
585
|
|
|
for s in self.config.sections(): |
586
|
|
|
if self.config.has_section(s) and (self.config.get_bool_value(s, 'disable', False)): |
587
|
|
|
disable(args, s) |
588
|
|
|
logger.debug('{} disabled by the configuration file'.format(s)) |
589
|
|
|
# The configuration key can be overwrite from the command line |
590
|
|
|
if args and args.disable_plugin and 'all' in args.disable_plugin.split(','): |
591
|
|
|
if not args.enable_plugin: |
592
|
|
|
logger.critical("'all' key in --disable-plugin needs to be used with --enable-plugin") |
593
|
|
|
sys.exit(2) |
594
|
|
|
else: |
595
|
|
|
logger.info( |
596
|
|
|
"'all' key in --disable-plugin, only plugins defined with --enable-plugin will be available" |
597
|
|
|
) |
598
|
|
|
if args.disable_plugin is not None: |
599
|
|
|
for p in args.disable_plugin.split(','): |
600
|
|
|
disable(args, p) |
601
|
|
|
if args.enable_plugin is not None: |
602
|
|
|
for p in args.enable_plugin.split(','): |
603
|
|
|
enable(args, p) |
604
|
|
|
|
605
|
|
|
# Exporters activation |
606
|
|
|
if args.export is not None: |
607
|
|
|
for p in args.export.split(','): |
608
|
|
|
setattr(args, 'export_' + p, True) |
609
|
|
|
|
610
|
|
|
# By default help is hidden |
611
|
|
|
args.help_tag = False |
612
|
|
|
|
613
|
|
|
# Display Rx and Tx, not the sum for the network |
614
|
|
|
args.network_sum = False |
615
|
|
|
args.network_cumul = False |
616
|
|
|
|
617
|
|
|
# Processlist id updated in processcount |
618
|
|
|
if getattr(args, 'enable_processlist', False): |
619
|
|
|
enable(args, 'processcount') |
620
|
|
|
|
621
|
|
|
# Set a default export_process_filter (with all process) when using the stdout mode |
622
|
|
|
if getattr(args, 'stdout', True) and args.process_filter is None: |
623
|
|
|
setattr(args, 'export_process_filter', '.*') |
624
|
|
|
|
625
|
|
|
def init_client_server(self, args): |
626
|
|
|
"""Init Glances client/server mode.""" |
627
|
|
|
|
628
|
|
|
# Client/server Port |
629
|
|
|
if args.port is None: |
630
|
|
|
if args.webserver: |
631
|
|
|
args.port = self.web_server_port |
632
|
|
|
else: |
633
|
|
|
args.port = self.server_port |
634
|
|
|
# Port in the -c URI #996 |
635
|
|
|
if args.client is not None: |
636
|
|
|
args.client, args.port = ( |
637
|
|
|
x if x else y for (x, y) in zip(args.client.partition(':')[::2], (args.client, args.port)) |
|
|
|
|
638
|
|
|
) |
639
|
|
|
|
640
|
|
|
# Client autodiscover mode |
641
|
|
|
if args.disable_autodiscover: |
642
|
|
|
logger.info("Auto discover mode is disabled") |
643
|
|
|
|
644
|
|
|
# Server or client login/password |
645
|
|
|
if args.username_prompt: |
646
|
|
|
# Every username needs a password |
647
|
|
|
args.password_prompt = True |
648
|
|
|
# Prompt username |
649
|
|
|
if args.server: |
650
|
|
|
args.username = self.__get_username(description='Define the Glances server username: ') |
651
|
|
|
elif args.webserver: |
652
|
|
|
args.username = self.__get_username(description='Define the Glances webserver username: ') |
653
|
|
|
elif args.client: |
654
|
|
|
args.username = self.__get_username(description='Enter the Glances server username: ') |
655
|
|
|
else: |
656
|
|
|
if args.username_used: |
657
|
|
|
# A username has been set using the -u option ? |
658
|
|
|
args.username = args.username_used |
659
|
|
|
else: |
660
|
|
|
# Default user name is 'glances' |
661
|
|
|
args.username = self.username |
662
|
|
|
|
663
|
|
|
if args.password_prompt or args.username_used: |
664
|
|
|
# Interactive or file password |
665
|
|
|
if args.server: |
666
|
|
|
args.password = self.__get_password( |
667
|
|
|
description='Define the Glances server password ({} username): '.format(args.username), |
668
|
|
|
confirm=True, |
669
|
|
|
username=args.username, |
670
|
|
|
) |
671
|
|
|
elif args.webserver: |
672
|
|
|
args.password = self.__get_password( |
673
|
|
|
description='Define the Glances webserver password ({} username): '.format(args.username), |
674
|
|
|
confirm=True, |
675
|
|
|
username=args.username, |
676
|
|
|
) |
677
|
|
|
elif args.client: |
678
|
|
|
args.password = self.__get_password( |
679
|
|
|
description='Enter the Glances server password ({} username): '.format(args.username), |
680
|
|
|
clear=True, |
681
|
|
|
username=args.username, |
682
|
|
|
) |
683
|
|
|
else: |
684
|
|
|
# Default is no password |
685
|
|
|
args.password = self.password |
686
|
|
|
|
687
|
|
|
def init_ui_mode(self, args): |
688
|
|
|
# Manage light mode |
689
|
|
|
if getattr(args, 'enable_light', False): |
690
|
|
|
logger.info("Light mode is on") |
691
|
|
|
args.disable_left_sidebar = True |
692
|
|
|
disable(args, 'process') |
693
|
|
|
disable(args, 'alert') |
694
|
|
|
disable(args, 'amps') |
695
|
|
|
disable(args, 'containers') |
696
|
|
|
|
697
|
|
|
# Manage full quicklook option |
698
|
|
|
if getattr(args, 'full_quicklook', False): |
699
|
|
|
logger.info("Full quicklook mode") |
700
|
|
|
enable(args, 'quicklook') |
701
|
|
|
disable(args, 'cpu') |
702
|
|
|
disable(args, 'mem') |
703
|
|
|
disable(args, 'memswap') |
704
|
|
|
enable(args, 'load') |
705
|
|
|
|
706
|
|
|
# Manage disable_top option |
707
|
|
|
if getattr(args, 'disable_top', False): |
708
|
|
|
logger.info("Disable top menu") |
709
|
|
|
disable(args, 'quicklook') |
710
|
|
|
disable(args, 'cpu') |
711
|
|
|
disable(args, 'mem') |
712
|
|
|
disable(args, 'memswap') |
713
|
|
|
disable(args, 'load') |
714
|
|
|
|
715
|
|
|
# Memory leak |
716
|
|
|
if getattr(args, 'memory_leak', False): |
717
|
|
|
logger.info('Memory leak detection enabled') |
718
|
|
|
args.quiet = True |
719
|
|
|
if not args.stop_after: |
720
|
|
|
args.stop_after = 60 |
721
|
|
|
args.time = 1 |
722
|
|
|
args.disable_history = True |
723
|
|
|
|
724
|
|
|
def parse_args(self): |
725
|
|
|
"""Parse command line arguments.""" |
726
|
|
|
args = self.init_args().parse_args() |
727
|
|
|
|
728
|
|
|
# Load the configuration file, if it exists |
729
|
|
|
# This function should be called after the parse_args |
730
|
|
|
# because the configuration file path can be defined |
731
|
|
|
self.config = Config(args.conf_file) |
732
|
|
|
|
733
|
|
|
# Init Glances debug mode |
734
|
|
|
self.init_debug(args) |
735
|
|
|
|
736
|
|
|
# Plugins Glances refresh rate |
737
|
|
|
self.init_refresh_rate(args) |
738
|
|
|
|
739
|
|
|
# Manage Plugins disable/enable option |
740
|
|
|
self.init_plugins(args) |
741
|
|
|
|
742
|
|
|
# Init Glances client/server mode |
743
|
|
|
self.init_client_server(args) |
744
|
|
|
|
745
|
|
|
# Init UI mode |
746
|
|
|
self.init_ui_mode(args) |
747
|
|
|
|
748
|
|
|
# Init the generate_graph tag |
749
|
|
|
# Should be set to True to generate graphs |
750
|
|
|
args.generate_graph = False |
751
|
|
|
|
752
|
|
|
# Control parameter and exit if it is not OK |
753
|
|
|
self.args = args |
754
|
|
|
|
755
|
|
|
# Export is only available in standalone or client mode (issue #614) |
756
|
|
|
export_tag = self.args.export is not None and any(self.args.export) |
757
|
|
|
if WINDOWS and export_tag: |
758
|
|
|
# On Windows, export is possible but only in quiet mode |
759
|
|
|
# See issue #1038 |
760
|
|
|
logger.info("On Windows OS, export disable the Web interface") |
761
|
|
|
self.args.quiet = True |
762
|
|
|
self.args.webserver = False |
763
|
|
|
elif not (self.is_standalone() or self.is_client()) and export_tag: |
764
|
|
|
logger.critical("Export is only available in standalone or client mode") |
765
|
|
|
sys.exit(2) |
766
|
|
|
|
767
|
|
|
# Filter is only available in standalone mode |
768
|
|
|
if not args.process_filter and not self.is_standalone(): |
769
|
|
|
logger.debug("Process filter is only available in standalone mode") |
770
|
|
|
|
771
|
|
|
# Cursor option is only available in standalone mode |
772
|
|
|
if not args.disable_cursor and not self.is_standalone(): |
773
|
|
|
logger.debug("Cursor is only available in standalone mode") |
774
|
|
|
|
775
|
|
|
# Let the plugins known the Glances mode |
776
|
|
|
self.args.is_standalone = self.is_standalone() |
777
|
|
|
self.args.is_client = self.is_client() |
778
|
|
|
self.args.is_client_browser = self.is_client_browser() |
779
|
|
|
self.args.is_server = self.is_server() |
780
|
|
|
self.args.is_webserver = self.is_webserver() |
781
|
|
|
|
782
|
|
|
# Check mode compatibility |
783
|
|
|
self.check_mode_compatibility() |
784
|
|
|
|
785
|
|
|
return args |
786
|
|
|
|
787
|
|
|
def check_mode_compatibility(self): |
788
|
|
|
"""Check mode compatibility""" |
789
|
|
|
# Server and Web server are not compatible |
790
|
|
|
if self.args.is_server and self.args.is_webserver: |
791
|
|
|
logger.critical("Server and Web server modes should not be used together") |
792
|
|
|
sys.exit(2) |
793
|
|
|
|
794
|
|
|
# Trace malloc option |
795
|
|
|
if getattr(self.args, 'trace_malloc', True) and not self.is_standalone(): |
796
|
|
|
logger.critical("Option --trace-malloc is only available in the terminal mode") |
797
|
|
|
sys.exit(2) |
798
|
|
|
|
799
|
|
|
# Memory leak option |
800
|
|
|
if getattr(self.args, 'memory_leak', True) and not self.is_standalone(): |
801
|
|
|
logger.critical("Option --memory-leak is only available in the terminal mode") |
802
|
|
|
sys.exit(2) |
803
|
|
|
|
804
|
|
|
def is_standalone(self): |
805
|
|
|
"""Return True if Glances is running in standalone mode.""" |
806
|
|
|
return not self.args.client and not self.args.browser and not self.args.server and not self.args.webserver |
807
|
|
|
|
808
|
|
|
def is_client(self): |
809
|
|
|
"""Return True if Glances is running in client mode.""" |
810
|
|
|
return (self.args.client or self.args.browser) and not self.args.server |
811
|
|
|
|
812
|
|
|
def is_client_browser(self): |
813
|
|
|
"""Return True if Glances is running in client browser mode.""" |
814
|
|
|
return self.args.browser and not self.args.server |
815
|
|
|
|
816
|
|
|
def is_server(self): |
817
|
|
|
"""Return True if Glances is running in server mode.""" |
818
|
|
|
return not self.args.client and self.args.server |
819
|
|
|
|
820
|
|
|
def is_webserver(self): |
821
|
|
|
"""Return True if Glances is running in Web server mode.""" |
822
|
|
|
return not self.args.client and self.args.webserver |
823
|
|
|
|
824
|
|
|
def get_config(self): |
825
|
|
|
"""Return configuration file object.""" |
826
|
|
|
return self.config |
827
|
|
|
|
828
|
|
|
def get_args(self): |
829
|
|
|
"""Return the arguments.""" |
830
|
|
|
return self.args |
831
|
|
|
|
832
|
|
|
def get_mode(self): |
833
|
|
|
"""Return the mode.""" |
834
|
|
|
return self.mode |
835
|
|
|
|
836
|
|
|
def __get_username(self, description=''): |
837
|
|
|
"""Read an username from the command line.""" |
838
|
|
|
return input(description) |
839
|
|
|
|
840
|
|
|
def __get_password(self, description='', confirm=False, clear=False, username='glances'): |
841
|
|
|
"""Read a password from the command line. |
842
|
|
|
|
843
|
|
|
- if confirm = True, with confirmation |
844
|
|
|
- if clear = True, plain (clear password) |
845
|
|
|
""" |
846
|
|
|
from glances.password import GlancesPassword |
847
|
|
|
|
848
|
|
|
password = GlancesPassword(username=username, config=self.get_config()) |
849
|
|
|
return password.get_password(description, confirm, clear) |
850
|
|
|
|