mirror of
https://github.com/nicolargo/glances.git
synced 2024-12-30 04:32:00 +03:00
Merge branch 'issue1444' into develop
This commit is contained in:
commit
a9502af99b
@ -463,6 +463,7 @@ port=5672
|
||||
user=guest
|
||||
password=guest
|
||||
queue=glances_queue
|
||||
#protocol=amqps
|
||||
|
||||
[mqtt]
|
||||
# Configuration for the --export mqtt option
|
||||
|
@ -128,6 +128,9 @@ The extended stats feature can be enabled using the
|
||||
``--enable-process-extended`` option (command line) or the ``e`` key
|
||||
(curses interface).
|
||||
|
||||
In curses/standalone mode, you can select a process using ``UP`` and ``DOWN`` and press:
|
||||
- ``k`` to kill the selected process
|
||||
|
||||
.. note::
|
||||
Limit for CPU and MEM percent values can be overwritten in the
|
||||
configuration file under the ``[processlist]`` section. It is also
|
||||
|
@ -18,3 +18,6 @@ There is no alert on this information.
|
||||
|
||||
.. note::
|
||||
This plugin is disabled by default in the configuration file.
|
||||
To enable it just use the following option:
|
||||
|
||||
# glances --enable-plugin sensors
|
||||
|
@ -15,6 +15,7 @@ following:
|
||||
user=glances
|
||||
password=glances
|
||||
queue=glances_queue
|
||||
#protocol=amqps
|
||||
|
||||
and run Glances with:
|
||||
|
||||
|
@ -395,6 +395,9 @@ Sort processes by I/O rate
|
||||
Show/hide IP module
|
||||
.TP
|
||||
.B \fBk\fP
|
||||
Kill selected process (only in curses/standalone mode)
|
||||
.TP
|
||||
.B \fBK\fP
|
||||
Show/hide TCP connections
|
||||
.TP
|
||||
.B \fBl\fP
|
||||
@ -480,6 +483,12 @@ Enable/disable mean GPU mode
|
||||
.B \fB/\fP
|
||||
Switch between process command line or command name
|
||||
.TP
|
||||
.B \fBUP\fP
|
||||
Up in the processes list
|
||||
.TP
|
||||
.B \fBDOWN\fP
|
||||
Down in the processes list
|
||||
.TP
|
||||
.B \fBF5\fP
|
||||
Refresh stats in curses user interface
|
||||
.UNINDENT
|
||||
|
@ -419,6 +419,13 @@ Examples of use:
|
||||
disable(args, 'hddtemp')
|
||||
logger.debug("Sensors and HDDTemp are disabled")
|
||||
|
||||
# Let the plugins known the Glances mode
|
||||
self.args.is_standalone = self.is_standalone()
|
||||
self.args.is_client = self.is_client()
|
||||
self.args.is_client_browser = self.is_client_browser()
|
||||
self.args.is_server = self.is_server()
|
||||
self.args.is_webserver = self.is_webserver()
|
||||
|
||||
return args
|
||||
|
||||
def is_standalone(self):
|
||||
|
@ -50,10 +50,13 @@ class _GlancesCurses(object):
|
||||
"""
|
||||
|
||||
_hotkeys = {
|
||||
# 'ENTER' > Edit the process filter
|
||||
'0': {'switch': 'disable_irix'},
|
||||
'1': {'switch': 'percpu'},
|
||||
'2': {'switch': 'disable_left_sidebar'},
|
||||
'3': {'switch': 'disable_quicklook'},
|
||||
# '4' > Enable or disable quicklook
|
||||
# '5' > Enable or disable top menu
|
||||
'6': {'switch': 'meangpu'},
|
||||
'/': {'switch': 'process_short_name'},
|
||||
'a': {'sort_key': 'auto'},
|
||||
@ -64,13 +67,17 @@ class _GlancesCurses(object):
|
||||
'C': {'switch': 'disable_cloud'},
|
||||
'd': {'switch': 'disable_diskio'},
|
||||
'D': {'switch': 'disable_docker'},
|
||||
# 'e' > Enable/Disable process extended
|
||||
# 'E' > Erase the process filter
|
||||
# 'f' > Show/hide fs / folder stats
|
||||
'F': {'switch': 'fs_free_space'},
|
||||
'g': {'switch': 'generate_graph'},
|
||||
'G': {'switch': 'disable_gpu'},
|
||||
'h': {'switch': 'help_tag'},
|
||||
'i': {'sort_key': 'io_counters'},
|
||||
'I': {'switch': 'disable_ip'},
|
||||
'k': {'switch': 'disable_connections'},
|
||||
# 'k' > Kill selected process
|
||||
'K': {'switch': 'disable_connections'},
|
||||
'l': {'switch': 'disable_alert'},
|
||||
'm': {'sort_key': 'memory_percent'},
|
||||
'M': {'switch': 'reset_minmax_tag'},
|
||||
@ -78,6 +85,7 @@ class _GlancesCurses(object):
|
||||
'N': {'switch': 'disable_now'},
|
||||
'p': {'sort_key': 'name'},
|
||||
'P': {'switch': 'disable_ports'},
|
||||
# 'q' or ESCAPE > Quit
|
||||
'Q': {'switch': 'enable_irq'},
|
||||
'r': {'switch': 'disable_smart'},
|
||||
'R': {'switch': 'disable_raid'},
|
||||
@ -87,7 +95,14 @@ class _GlancesCurses(object):
|
||||
'T': {'switch': 'network_sum'},
|
||||
'u': {'sort_key': 'username'},
|
||||
'U': {'switch': 'network_cumul'},
|
||||
# 'w' > Delete finished warning logs
|
||||
'W': {'switch': 'disable_wifi'},
|
||||
# 'x' > Delete finished warning and critical logs
|
||||
# 'z' > Enable or disable processes
|
||||
# "<" (left arrow) navigation through process sort
|
||||
# ">" (right arrow) navigation through process sort
|
||||
# 'UP' > Up in the server list
|
||||
# 'DOWN' > Down in the server list
|
||||
}
|
||||
|
||||
_sort_loop = ['cpu_percent', 'memory_percent', 'username',
|
||||
@ -144,9 +159,15 @@ class _GlancesCurses(object):
|
||||
# Init edit filter tag
|
||||
self.edit_filter = False
|
||||
|
||||
# Init kill process tag
|
||||
self.kill_process = False
|
||||
|
||||
# Init the process min/max reset
|
||||
self.args.reset_minmax_tag = False
|
||||
|
||||
# Init cursor
|
||||
self.args.cursor_position = 0
|
||||
|
||||
# Catch key pressed with non blocking mode
|
||||
self.term_window.keypad(1)
|
||||
self.term_window.nodelay(1)
|
||||
@ -188,6 +209,8 @@ class _GlancesCurses(object):
|
||||
try:
|
||||
if hasattr(curses, 'start_color'):
|
||||
curses.start_color()
|
||||
logger.debug(
|
||||
'Curses interface compatible with {} colors'.format(curses.COLORS))
|
||||
if hasattr(curses, 'use_default_colors'):
|
||||
curses.use_default_colors()
|
||||
except Exception as e:
|
||||
@ -226,35 +249,35 @@ class _GlancesCurses(object):
|
||||
curses.init_pair(8, curses.COLOR_BLUE, -1)
|
||||
|
||||
# Colors text styles
|
||||
if curses.COLOR_PAIRS > 8:
|
||||
try:
|
||||
curses.init_pair(9, curses.COLOR_MAGENTA, -1)
|
||||
except Exception:
|
||||
if self.is_theme('white'):
|
||||
curses.init_pair(9, curses.COLOR_BLACK, -1)
|
||||
else:
|
||||
curses.init_pair(9, curses.COLOR_WHITE, -1)
|
||||
try:
|
||||
curses.init_pair(10, curses.COLOR_CYAN, -1)
|
||||
except Exception:
|
||||
if self.is_theme('white'):
|
||||
curses.init_pair(10, curses.COLOR_BLACK, -1)
|
||||
else:
|
||||
curses.init_pair(10, curses.COLOR_WHITE, -1)
|
||||
|
||||
self.ifWARNING_color2 = curses.color_pair(9) | A_BOLD
|
||||
self.ifCRITICAL_color2 = curses.color_pair(6) | A_BOLD
|
||||
self.filter_color = curses.color_pair(10) | A_BOLD
|
||||
|
||||
self.no_color = curses.color_pair(1)
|
||||
self.default_color = curses.color_pair(3) | A_BOLD
|
||||
self.nice_color = curses.color_pair(9)
|
||||
self.cpu_time_color = curses.color_pair(9)
|
||||
self.nice_color = curses.color_pair(5)
|
||||
self.cpu_time_color = curses.color_pair(5)
|
||||
self.ifCAREFUL_color = curses.color_pair(4) | A_BOLD
|
||||
self.ifWARNING_color = curses.color_pair(5) | A_BOLD
|
||||
self.ifCRITICAL_color = curses.color_pair(2) | A_BOLD
|
||||
self.default_color2 = curses.color_pair(7)
|
||||
self.ifCAREFUL_color2 = curses.color_pair(8) | A_BOLD
|
||||
self.ifWARNING_color2 = curses.color_pair(5) | A_BOLD
|
||||
self.ifCRITICAL_color2 = curses.color_pair(6) | A_BOLD
|
||||
self.filter_color = A_BOLD
|
||||
self.selected_color = A_BOLD
|
||||
|
||||
if curses.COLOR_PAIRS > 8:
|
||||
colors_list = [curses.COLOR_MAGENTA, curses.COLOR_CYAN, curses.COLOR_YELLOW]
|
||||
for i in range(0, 3):
|
||||
try:
|
||||
curses.init_pair(i + 9, colors_list[i], -1)
|
||||
except Exception:
|
||||
if self.is_theme('white'):
|
||||
curses.init_pair(i + 9, curses.COLOR_BLACK, -1)
|
||||
else:
|
||||
curses.init_pair(i + 9, curses.COLOR_WHITE, -1)
|
||||
self.nice_color = curses.color_pair(9)
|
||||
self.cpu_time_color = curses.color_pair(9)
|
||||
self.ifWARNING_color2 = curses.color_pair(9) | A_BOLD
|
||||
self.filter_color = curses.color_pair(10) | A_BOLD
|
||||
self.selected_color = curses.color_pair(11) | A_BOLD
|
||||
|
||||
else:
|
||||
# The screen is NOT compatible with a colored design
|
||||
@ -271,6 +294,7 @@ class _GlancesCurses(object):
|
||||
self.ifWARNING_color2 = A_BOLD
|
||||
self.ifCRITICAL_color2 = curses.A_REVERSE
|
||||
self.filter_color = A_BOLD
|
||||
self.selected_color = A_BOLD
|
||||
|
||||
# Define the colors list (hash table) for stats
|
||||
self.colors_list = {
|
||||
@ -283,6 +307,7 @@ class _GlancesCurses(object):
|
||||
'FILTER': self.filter_color,
|
||||
'TITLE': self.title_color,
|
||||
'PROCESS': self.default_color2,
|
||||
'PROCESS_SELECTED': self.default_color2 | curses.A_UNDERLINE,
|
||||
'STATUS': self.default_color2,
|
||||
'NICE': self.nice_color,
|
||||
'CPU_TIME': self.cpu_time_color,
|
||||
@ -293,7 +318,8 @@ class _GlancesCurses(object):
|
||||
'CAREFUL_LOG': self.ifCAREFUL_color,
|
||||
'WARNING_LOG': self.ifWARNING_color,
|
||||
'CRITICAL_LOG': self.ifCRITICAL_color,
|
||||
'PASSWORD': curses.A_PROTECT
|
||||
'PASSWORD': curses.A_PROTECT,
|
||||
'SELECTED': self.selected_color
|
||||
}
|
||||
|
||||
def set_cursor(self, value):
|
||||
@ -331,22 +357,18 @@ class _GlancesCurses(object):
|
||||
self._hotkeys[hotkey]['sort_key'] == 'auto')
|
||||
|
||||
# Other actions...
|
||||
if self.pressedkey == ord('\x1b') or self.pressedkey == ord('q'):
|
||||
# 'ESC'|'q' > Quit
|
||||
if return_to_browser:
|
||||
logger.info("Stop Glances client and return to the browser")
|
||||
else:
|
||||
logger.info("Stop Glances (keypressed: {})".format(self.pressedkey))
|
||||
elif self.pressedkey == ord('\n'):
|
||||
if self.pressedkey == ord('\n'):
|
||||
# 'ENTER' > Edit the process filter
|
||||
self.edit_filter = not self.edit_filter
|
||||
elif self.pressedkey == ord('4'):
|
||||
# '4' > Enable or disable quicklook
|
||||
self.args.full_quicklook = not self.args.full_quicklook
|
||||
if self.args.full_quicklook:
|
||||
self.enable_fullquicklook()
|
||||
else:
|
||||
self.disable_fullquicklook()
|
||||
elif self.pressedkey == ord('5'):
|
||||
# '5' > Enable or disable top menu
|
||||
self.args.disable_top = not self.args.disable_top
|
||||
if self.args.disable_top:
|
||||
self.disable_top()
|
||||
@ -366,6 +388,9 @@ class _GlancesCurses(object):
|
||||
# 'f' > Show/hide fs / folder stats
|
||||
self.args.disable_fs = not self.args.disable_fs
|
||||
self.args.disable_folders = not self.args.disable_folders
|
||||
elif self.pressedkey == ord('k'):
|
||||
# 'k' > Kill selected process (after confirmation)
|
||||
self.kill_process = not self.kill_process
|
||||
elif self.pressedkey == ord('w'):
|
||||
# 'w' > Delete finished warning logs
|
||||
glances_events.clean()
|
||||
@ -387,6 +412,22 @@ class _GlancesCurses(object):
|
||||
# ">" (right arrow) navigation through process sort
|
||||
next_sort = (self.loop_position() + 1) % len(self._sort_loop)
|
||||
glances_processes.set_sort_key(self._sort_loop[next_sort], False)
|
||||
elif self.pressedkey == curses.KEY_UP or self.pressedkey == 65:
|
||||
# 'UP' > Up in the server list
|
||||
if self.args.cursor_position > 0:
|
||||
self.args.cursor_position -= 1
|
||||
elif self.pressedkey == curses.KEY_DOWN or self.pressedkey == 66:
|
||||
# 'DOWN' > Down in the server list
|
||||
# if self.args.cursor_position < glances_processes.max_processes - 2:
|
||||
if self.args.cursor_position < glances_processes.processes_count:
|
||||
self.args.cursor_position += 1
|
||||
elif self.pressedkey == ord('\x1b') or self.pressedkey == ord('q'):
|
||||
# 'ESC'|'q' > Quit
|
||||
if return_to_browser:
|
||||
logger.info("Stop Glances client and return to the browser")
|
||||
else:
|
||||
logger.info(
|
||||
"Stop Glances (keypressed: {})".format(self.pressedkey))
|
||||
elif self.pressedkey == curses.KEY_F5:
|
||||
# "F5" manual refresh requested
|
||||
pass
|
||||
@ -594,13 +635,39 @@ class _GlancesCurses(object):
|
||||
'- cmdline:.*glances.*\n' +
|
||||
'- username:nicolargo\n' +
|
||||
'- username:^root ',
|
||||
is_input=True,
|
||||
popup_type='input',
|
||||
input_value=glances_processes.process_filter_input)
|
||||
glances_processes.process_filter = new_filter
|
||||
elif self.edit_filter and cs_status is not None:
|
||||
self.display_popup('Process filter only available in standalone mode')
|
||||
self.edit_filter = False
|
||||
|
||||
# Display kill process confirmation popup
|
||||
# Only in standalone mode (cs_status is None)
|
||||
if self.kill_process and cs_status is None:
|
||||
selected_process_raw = stats.get_plugin('processlist').get_raw()[
|
||||
self.args.cursor_position]
|
||||
confirm = self.display_popup(
|
||||
'Kill process: {} (pid: {}) ?\n\nConfirm ([y]es/[n]o): '.format(
|
||||
selected_process_raw['name'],
|
||||
selected_process_raw['pid']),
|
||||
popup_type='yesno')
|
||||
if confirm.lower().startswith('y'):
|
||||
try:
|
||||
ret_kill = glances_processes.kill(selected_process_raw['pid'])
|
||||
except Exception as e:
|
||||
logger.error('Can not kill process {} ({})'.format(
|
||||
selected_process_raw['name'], e))
|
||||
else:
|
||||
logger.info('Kill signal has been sent to process {} (return code: {})'.format(
|
||||
selected_process_raw['name'], ret_kill))
|
||||
|
||||
elif self.kill_process and cs_status is not None:
|
||||
self.display_popup(
|
||||
'Kill process only available in standalone mode')
|
||||
self.kill_process = False
|
||||
|
||||
|
||||
# Display graph generation popup
|
||||
if self.args.generate_graph:
|
||||
self.display_popup('Generate graph in {}'.format(self.args.export_graph_path))
|
||||
@ -756,30 +823,37 @@ class _GlancesCurses(object):
|
||||
def display_popup(self, message,
|
||||
size_x=None, size_y=None,
|
||||
duration=3,
|
||||
is_input=False,
|
||||
popup_type='info',
|
||||
input_size=30,
|
||||
input_value=None):
|
||||
"""
|
||||
Display a centered popup.
|
||||
|
||||
If is_input is False:
|
||||
popup_type='info'
|
||||
Just an infotmation popup, no user interaction
|
||||
Display a centered popup with the given message during duration seconds
|
||||
If size_x and size_y: set the popup size
|
||||
else set it automatically
|
||||
Return True if the popup could be displayed
|
||||
|
||||
If is_input is True:
|
||||
popup_type='input'
|
||||
Display a centered popup with the given message and a input field
|
||||
If size_x and size_y: set the popup size
|
||||
else set it automatically
|
||||
Return the input string or None if the field is empty
|
||||
|
||||
popup_type='yesno'
|
||||
Display a centered popup with the given message
|
||||
If size_x and size_y: set the popup size
|
||||
else set it automatically
|
||||
Return True (yes) or False (no)
|
||||
"""
|
||||
# Center the popup
|
||||
sentence_list = message.split('\n')
|
||||
if size_x is None:
|
||||
size_x = len(max(sentence_list, key=len)) + 4
|
||||
# Add space for the input field
|
||||
if is_input:
|
||||
if popup_type == 'input':
|
||||
size_x += input_size
|
||||
if size_y is None:
|
||||
size_y = len(sentence_list) + 4
|
||||
@ -798,10 +872,15 @@ class _GlancesCurses(object):
|
||||
popup.border()
|
||||
|
||||
# Add the message
|
||||
for y, m in enumerate(message.split('\n')):
|
||||
for y, m in enumerate(sentence_list):
|
||||
popup.addnstr(2 + y, 2, m, len(m))
|
||||
|
||||
if is_input:
|
||||
if popup_type == 'info':
|
||||
# Display the popup
|
||||
popup.refresh()
|
||||
self.wait(duration * 1000)
|
||||
return True
|
||||
elif popup_type == 'input':
|
||||
# Create a subwindow for the text field
|
||||
subpop = popup.derwin(1, input_size, 2, 2 + len(m))
|
||||
subpop.attron(self.colors_list['FILTER'])
|
||||
@ -817,7 +896,7 @@ class _GlancesCurses(object):
|
||||
textbox = GlancesTextbox(subpop, insert_mode=False)
|
||||
textbox.edit()
|
||||
self.set_cursor(0)
|
||||
self.term_window.keypad(0)
|
||||
# self.term_window.keypad(0)
|
||||
if textbox.gather() != '':
|
||||
logger.debug(
|
||||
"User enters the following string: %s" % textbox.gather())
|
||||
@ -825,11 +904,23 @@ class _GlancesCurses(object):
|
||||
else:
|
||||
logger.debug("User centers an empty string")
|
||||
return None
|
||||
else:
|
||||
elif popup_type == 'yesno':
|
||||
# # Create a subwindow for the text field
|
||||
subpop = popup.derwin(1, 2, len(sentence_list) + 1, len(m) + 2)
|
||||
subpop.attron(self.colors_list['FILTER'])
|
||||
# Init the field with the current value
|
||||
subpop.addnstr(0, 0, '', 0)
|
||||
# Display the popup
|
||||
popup.refresh()
|
||||
self.wait(duration * 1000)
|
||||
return True
|
||||
subpop.refresh()
|
||||
# Create the textbox inside the subwindows
|
||||
self.set_cursor(2)
|
||||
self.term_window.keypad(1)
|
||||
textbox = GlancesTextboxYesNo(subpop, insert_mode=False)
|
||||
textbox.edit()
|
||||
self.set_cursor(0)
|
||||
# self.term_window.keypad(0)
|
||||
return textbox.gather()
|
||||
|
||||
def display_plugin(self, plugin_stats,
|
||||
display_optional=True,
|
||||
@ -1055,3 +1146,12 @@ class GlancesTextbox(Textbox, object):
|
||||
if ch == 127: # Back
|
||||
return 8
|
||||
return super(GlancesTextbox, self).do_command(ch)
|
||||
|
||||
|
||||
class GlancesTextboxYesNo(Textbox, object):
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
super(GlancesTextboxYesNo, self).__init__(*args, **kwargs)
|
||||
|
||||
def do_command(self, ch):
|
||||
return super(GlancesTextboxYesNo, self).do_command(ch)
|
||||
|
@ -70,12 +70,13 @@ class Plugin(GlancesPlugin):
|
||||
'status': '{:>1} ',
|
||||
'ior': '{:>4} ',
|
||||
'iow': '{:<4} ',
|
||||
'command': '{}',
|
||||
'command': '{} {}',
|
||||
}
|
||||
|
||||
# Define the stat layout of the processes list columns
|
||||
layout_stat = {
|
||||
'cpu': '{:<6.1f} ',
|
||||
'cpu': '{:<6.1f}',
|
||||
'cpu_no_digit': '{:<6.0f}',
|
||||
'mem': '{:<5.1f} ',
|
||||
'virt': '{:<5} ',
|
||||
'res': '{:<5} ',
|
||||
@ -172,19 +173,26 @@ class Plugin(GlancesPlugin):
|
||||
pass
|
||||
return 'DEFAULT'
|
||||
|
||||
def get_process_curses_data(self, p, first, args):
|
||||
def get_process_curses_data(self, p, selected, args):
|
||||
"""Get curses data to display for a process.
|
||||
|
||||
- p is the process to display
|
||||
- first is a tag=True if the process is the first on the list
|
||||
- selected is a tag=True if the selected process
|
||||
"""
|
||||
ret = [self.curse_new_line()]
|
||||
# When a process is selected:
|
||||
# * display a special caracter at the beginning of the line
|
||||
# * underline the command name
|
||||
if args.is_standalone:
|
||||
ret.append(self.curse_add_line('>' if selected else ' ', 'SELECTED'))
|
||||
# CPU
|
||||
if 'cpu_percent' in p and p['cpu_percent'] is not None and p['cpu_percent'] != '':
|
||||
cpu_layout = self.layout_stat['cpu'] if p['cpu_percent'] < 100 else self.layout_stat['cpu_no_digit']
|
||||
if args.disable_irix and self.nb_log_core != 0:
|
||||
msg = self.layout_stat['cpu'].format(p['cpu_percent'] / float(self.nb_log_core))
|
||||
msg = cpu_layout.format(
|
||||
p['cpu_percent'] / float(self.nb_log_core))
|
||||
else:
|
||||
msg = self.layout_stat['cpu'].format(p['cpu_percent'])
|
||||
msg = cpu_layout.format(p['cpu_percent'])
|
||||
alert = self.get_alert(p['cpu_percent'],
|
||||
highlight_zero=False,
|
||||
is_max=(p['cpu_percent'] == self.max_values['cpu_percent']),
|
||||
@ -321,28 +329,31 @@ class Plugin(GlancesPlugin):
|
||||
else:
|
||||
cmdline = '?'
|
||||
try:
|
||||
process_decoration = 'PROCESS_SELECTED' if (selected and args.is_standalone) else 'PROCESS'
|
||||
if cmdline:
|
||||
path, cmd, arguments = split_cmdline(cmdline)
|
||||
if os.path.isdir(path) and not args.process_short_name:
|
||||
msg = self.layout_stat['command'].format(path) + os.sep
|
||||
ret.append(self.curse_add_line(msg, splittable=True))
|
||||
ret.append(self.curse_add_line(cmd, decoration='PROCESS', splittable=True))
|
||||
ret.append(self.curse_add_line(
|
||||
cmd, decoration=process_decoration, splittable=True))
|
||||
else:
|
||||
msg = self.layout_stat['command'].format(cmd)
|
||||
ret.append(self.curse_add_line(msg, decoration='PROCESS', splittable=True))
|
||||
ret.append(self.curse_add_line(
|
||||
msg, decoration=process_decoration, splittable=True))
|
||||
if arguments:
|
||||
msg = ' ' + self.layout_stat['command'].format(arguments)
|
||||
ret.append(self.curse_add_line(msg, splittable=True))
|
||||
else:
|
||||
msg = self.layout_stat['name'].format(p['name'])
|
||||
ret.append(self.curse_add_line(msg, splittable=True))
|
||||
ret.append(self.curse_add_line(msg, decoration=process_decoration, splittable=True))
|
||||
except (TypeError, UnicodeEncodeError) as e:
|
||||
# Avoid crach after running fine for several hours #1335
|
||||
logger.debug("Can not decode command line '{}' ({})".format(cmdline, e))
|
||||
ret.append(self.curse_add_line('', splittable=True))
|
||||
|
||||
# Add extended stats but only for the top processes
|
||||
if first and 'extended_stats' in p and args.enable_process_extended:
|
||||
if args.cursor_position == 0 and 'extended_stats' in p and args.enable_process_extended:
|
||||
# Left padding
|
||||
xpad = ' ' * 13
|
||||
# First line is CPU affinity
|
||||
@ -429,11 +440,13 @@ class Plugin(GlancesPlugin):
|
||||
|
||||
# Process list
|
||||
# Loop over processes (sorted by the sort key previously compute)
|
||||
first = True
|
||||
i = 0
|
||||
for p in self.__sort_stats(process_sort_key):
|
||||
ret.extend(self.get_process_curses_data(p, first, args))
|
||||
# End of extended stats
|
||||
first = False
|
||||
ret.extend(self.get_process_curses_data(
|
||||
p, i == args.cursor_position, args))
|
||||
i += 1
|
||||
|
||||
# A filter is set Display the stats summaries
|
||||
if glances_processes.process_filter is not None:
|
||||
if args.reset_minmax_tag:
|
||||
args.reset_minmax_tag = not args.reset_minmax_tag
|
||||
@ -478,7 +491,8 @@ class Plugin(GlancesPlugin):
|
||||
ret.append(self.curse_add_line(msg, sort_style if process_sort_key == 'io_counters' else 'DEFAULT', optional=True, additional=True))
|
||||
msg = self.layout_header['iow'].format('W/s')
|
||||
ret.append(self.curse_add_line(msg, sort_style if process_sort_key == 'io_counters' else 'DEFAULT', optional=True, additional=True))
|
||||
msg = self.layout_header['command'].format('Command')
|
||||
msg = self.layout_header['command'].format('Command',
|
||||
"('k' to kill)" if args.is_standalone else "")
|
||||
ret.append(self.curse_add_line(msg, sort_style if process_sort_key == 'name' else 'DEFAULT'))
|
||||
|
||||
def __msg_curse_sum(self, ret, sep_char='_', mmm=None, args=None):
|
||||
|
@ -176,6 +176,11 @@ class GlancesProcesses(object):
|
||||
else:
|
||||
return None
|
||||
|
||||
@property
|
||||
def processes_count(self):
|
||||
"""Get the current number of processes showed in the UI."""
|
||||
return min(self._max_processes - 2, glances_processes.processcount['total'] - 1)
|
||||
|
||||
@property
|
||||
def max_processes(self):
|
||||
"""Get the maximum number of processes showed in the UI."""
|
||||
@ -398,6 +403,14 @@ class GlancesProcesses(object):
|
||||
else:
|
||||
self.auto_sort = auto
|
||||
self._sort_key = key
|
||||
|
||||
def kill(self, pid, timeout=3):
|
||||
"""Kill process with pid"""
|
||||
assert pid != os.getpid(), "Glances can kill itself..."
|
||||
p = psutil.Process(pid)
|
||||
logger.debug('Send kill signal to process: {}'.format(p))
|
||||
p.kill()
|
||||
return p.wait(timeout)
|
||||
|
||||
|
||||
def weighted(value):
|
||||
|
Loading…
Reference in New Issue
Block a user