mirror of
https://github.com/nicolargo/glances.git
synced 2024-11-23 20:45:33 +03:00
Feature request: make the central client UI configurable (example: GPU status) #1289
This commit is contained in:
parent
6e485a2bad
commit
56d7801afb
@ -518,10 +518,14 @@ disable=False
|
||||
;min_interval=6
|
||||
|
||||
##############################################################################
|
||||
# Client/server
|
||||
# Browser mode - Static servers definition
|
||||
##############################################################################
|
||||
|
||||
[serverlist]
|
||||
# Define columns (comma separated list of <plugin>:<field>:(<key>)) to grab/display
|
||||
# Default is: system:hr_name,load:min5,cpu:total,mem:percent
|
||||
# You can also add stats with key, like sensors:value:Ambient (key is case sensitive)
|
||||
columns=system:hr_name,load:min5,cpu:total,mem:percent,memswap:percent
|
||||
# Define the static servers list
|
||||
#server_1_name=localhost
|
||||
#server_1_alias=My local PC
|
||||
|
@ -518,10 +518,14 @@ disable=False
|
||||
;min_interval=6
|
||||
|
||||
##############################################################################
|
||||
# Client/server
|
||||
# Browser mode - Static servers definition
|
||||
##############################################################################
|
||||
|
||||
[serverlist]
|
||||
# Define columns (comma separated list of <plugin>:<field>:(<key>)) to grab/display
|
||||
# Default is: system:hr_name,load:min5,cpu:total,mem:percent
|
||||
# You can also add stats with key, like sensors:value:Ambient (key is case sensitive)
|
||||
columns=system:hr_name,load:min5,cpu:total,mem:percent,memswap:percent
|
||||
# Define the static servers list
|
||||
#server_1_name=localhost
|
||||
#server_1_alias=My local PC
|
||||
|
@ -102,6 +102,10 @@ Example:
|
||||
.. code-block:: ini
|
||||
|
||||
[serverlist]
|
||||
# Define columns (comma separated list of <plugin>:<field>:(<key>)) to grab/display
|
||||
# Default is: system:hr_name,load:min5,cpu:total,mem:percent
|
||||
# You can also add stats with key, like sensors:value:Ambient (key is case sensitive)
|
||||
columns=system:hr_name,load:min5,cpu:total,mem:percent,memswap:percent
|
||||
# Define the static servers list
|
||||
server_1_name=xps
|
||||
server_1_alias=xps
|
||||
|
@ -84,26 +84,30 @@ class GlancesClientBrowser:
|
||||
t = GlancesClientTransport()
|
||||
t.set_timeout(3)
|
||||
|
||||
# Get common stats
|
||||
# Get common stats from Glances server
|
||||
try:
|
||||
s = ServerProxy(uri, transport=t)
|
||||
except Exception as e:
|
||||
logger.warning(f"Client browser couldn't create socket ({e})")
|
||||
else:
|
||||
# Mandatory stats
|
||||
return server
|
||||
|
||||
# Get the stats
|
||||
for column in self.static_server.get_columns():
|
||||
server_key = column['plugin'] + '_' + column['field']
|
||||
try:
|
||||
# CPU%
|
||||
# logger.info(f"CPU stats {s.getPlugin('cpu')}")
|
||||
# logger.info(f"CPU views {s.getPluginView('cpu')}")
|
||||
server['cpu_percent'] = json_loads(s.getPlugin('cpu'))['total']
|
||||
server['cpu_percent_decoration'] = json_loads(s.getPluginView('cpu'))['total']['decoration']
|
||||
# MEM%
|
||||
server['mem_percent'] = json_loads(s.getPlugin('mem'))['percent']
|
||||
server['mem_percent_decoration'] = json_loads(s.getPluginView('mem'))['percent']['decoration']
|
||||
# OS (Human Readable name)
|
||||
server['hr_name'] = json_loads(s.getPlugin('system'))['hr_name']
|
||||
server['hr_name_decoration'] = 'DEFAULT'
|
||||
except (OSError, Fault, KeyError) as e:
|
||||
# Value
|
||||
v_json = json_loads(s.getPlugin(column['plugin']))
|
||||
if 'key' in column:
|
||||
v_json = [i for i in v_json if i[i['key']].lower() == column['key'].lower()][0]
|
||||
server[server_key] = v_json[column['field']]
|
||||
# Decoration
|
||||
d_json = json_loads(s.getPluginView(column['plugin']))
|
||||
if 'key' in column:
|
||||
d_json = d_json.get(column['key'])
|
||||
server[server_key + '_decoration'] = d_json[column['field']]['decoration']
|
||||
except (KeyError, IndexError, Fault) as e:
|
||||
logger.debug(f"Error while grabbing stats form server ({e})")
|
||||
except OSError as e:
|
||||
logger.debug(f"Error while grabbing stats form server ({e})")
|
||||
server['status'] = 'OFFLINE'
|
||||
except ProtocolError as e:
|
||||
@ -119,14 +123,6 @@ class GlancesClientBrowser:
|
||||
# Status
|
||||
server['status'] = 'ONLINE'
|
||||
|
||||
# Optional stats (load is not available on Windows OS)
|
||||
try:
|
||||
# LOAD
|
||||
server['load_min5'] = round(json_loads(s.getPlugin('load'))['min5'], 1)
|
||||
server['load_min5_decoration'] = json_loads(s.getPluginView('load'))['min5']['decoration']
|
||||
except Exception as e:
|
||||
logger.warning(f"Error while grabbing stats form server ({e})")
|
||||
|
||||
return server
|
||||
|
||||
def __display_server(self, server):
|
||||
|
@ -288,32 +288,36 @@ class GlancesCursesBrowser(_GlancesCurses):
|
||||
|
||||
return x, y
|
||||
|
||||
def __build_column_def(self, current_page):
|
||||
"""Define the column and it size to display in the browser"""
|
||||
column_def = {'name': 16, 'ip': 15, 'status': 9}
|
||||
|
||||
# Add dynamic columns
|
||||
for server_stat in current_page:
|
||||
for k, v in server_stat.items():
|
||||
if k.endswith('_decoration'):
|
||||
column_def[k.split('_decoration')[0]] = 6
|
||||
return column_def
|
||||
|
||||
def __display_server_list(self, stats, x, y, screen_x, screen_y):
|
||||
if len(stats) == 0:
|
||||
# No server to display
|
||||
return False
|
||||
|
||||
stats_max = screen_y - 3
|
||||
|
||||
# Table of table
|
||||
# Item description: [stats_id, column name, column size]
|
||||
column_def = [
|
||||
['name', 'Name', 16],
|
||||
['load_min5', 'LOAD', 6],
|
||||
['cpu_percent', 'CPU%', 5],
|
||||
['mem_percent', 'MEM%', 5],
|
||||
['status', 'STATUS', 9],
|
||||
['ip', 'IP', 15],
|
||||
['hr_name', 'OS', 16],
|
||||
]
|
||||
y = 2
|
||||
stats_list = self._get_stats(stats)
|
||||
start_line = self._page_max_lines * self._current_page
|
||||
end_line = start_line + self.get_pagelines(stats_list)
|
||||
current_page = stats_list[start_line:end_line]
|
||||
column_def = self.__build_column_def(current_page)
|
||||
|
||||
# Display table header
|
||||
stats_max = screen_y - 3
|
||||
y = 2
|
||||
xc = x + 2
|
||||
for cpt, c in enumerate(column_def):
|
||||
if xc < screen_x and y < screen_y and c[1] is not None:
|
||||
self.term_window.addnstr(y, xc, c[1], screen_x - x, self.colors_list['BOLD'])
|
||||
xc += c[2] + self.space_between_column
|
||||
for k, v in column_def.items():
|
||||
if xc < screen_x and y < screen_y and v is not None:
|
||||
self.term_window.addnstr(y, xc, k.split('_')[0].upper(), screen_x - x, self.colors_list['BOLD'])
|
||||
xc += v + self.space_between_column
|
||||
y += 1
|
||||
|
||||
# If a servers has been deleted from the list...
|
||||
@ -322,11 +326,6 @@ class GlancesCursesBrowser(_GlancesCurses):
|
||||
# Set the cursor position to the latest item
|
||||
self.cursor = len(stats) - 1
|
||||
|
||||
stats_list = self._get_stats(stats)
|
||||
start_line = self._page_max_lines * self._current_page
|
||||
end_line = start_line + self.get_pagelines(stats_list)
|
||||
current_page = stats_list[start_line:end_line]
|
||||
|
||||
# Display table
|
||||
line = 0
|
||||
for server_stat in current_page:
|
||||
@ -345,22 +344,24 @@ class GlancesCursesBrowser(_GlancesCurses):
|
||||
|
||||
# Display the line
|
||||
xc += 2
|
||||
for c in column_def:
|
||||
for k, v in column_def.items():
|
||||
if xc < screen_x and y < screen_y:
|
||||
# Display server stats
|
||||
value = server_stat.get(c[0], '?')
|
||||
if c[0] == 'name' and 'alias' in server_stat and server_stat['alias'] is not None:
|
||||
value = server_stat.get(k, '?')
|
||||
if isinstance(value, float):
|
||||
value = round(value, 1)
|
||||
if k == 'name' and 'alias' in server_stat and server_stat['alias'] is not None:
|
||||
value = server_stat['alias']
|
||||
decoration = self.colors_list.get(
|
||||
server_stat[c[0] + '_decoration'].replace('_LOG', '')
|
||||
if c[0] + '_decoration' in server_stat
|
||||
server_stat[k + '_decoration'].replace('_LOG', '')
|
||||
if k + '_decoration' in server_stat
|
||||
else self.colors_list[server_stat['status']],
|
||||
self.colors_list['DEFAULT'],
|
||||
)
|
||||
if c[0] == 'status':
|
||||
if k == 'status':
|
||||
decoration = self.colors_list[server_stat['status']]
|
||||
self.term_window.addnstr(y, xc, format(value), c[2], decoration)
|
||||
xc += c[2] + self.space_between_column
|
||||
self.term_window.addnstr(y, xc, format(value), v, decoration)
|
||||
xc += v + self.space_between_column
|
||||
cpt += 1
|
||||
# Next line, next server...
|
||||
y += 1
|
||||
|
@ -12,6 +12,8 @@ from socket import gaierror, gethostbyname
|
||||
|
||||
from glances.logger import logger
|
||||
|
||||
DEFAULT_COLUMNS = "system:hr_name,load:min5,cpu:total,mem:percent"
|
||||
|
||||
|
||||
class GlancesStaticServer:
|
||||
"""Manage the static servers list for the client browser."""
|
||||
@ -21,10 +23,12 @@ class GlancesStaticServer:
|
||||
def __init__(self, config=None, args=None):
|
||||
# server_list is a list of dict (JSON compliant)
|
||||
# [ {'key': 'zeroconf name', ip': '172.1.2.3', 'port': 61209, 'cpu': 3, 'mem': 34 ...} ... ]
|
||||
# Load the configuration file
|
||||
self._server_list = self.load(config)
|
||||
# Load server list from the Glances configuration file
|
||||
self._server_list = self.load_server_list(config)
|
||||
# Load columns to grab/display in the browser mode
|
||||
self._columns = self.load_columns(config)
|
||||
|
||||
def load(self, config):
|
||||
def load_server_list(self, config):
|
||||
"""Load the server list from the configuration file."""
|
||||
server_list = []
|
||||
|
||||
@ -70,6 +74,28 @@ class GlancesStaticServer:
|
||||
|
||||
return server_list
|
||||
|
||||
def load_columns(self, config):
|
||||
"""Load columns definition from the configuration file.
|
||||
Read: 'system:hr_name,load:min5,cpu:total,mem:percent,sensors:value:Ambient'
|
||||
Return: [{'plugin': 'system', 'field': 'hr_name'},
|
||||
{'plugin': 'load', 'field': 'min5'},
|
||||
{'plugin': 'cpu', 'field': 'total'},
|
||||
{'plugin': 'mem', 'field': 'percent'},
|
||||
{'plugin': 'sensors', 'field': 'value', 'key': 'Ambient'}]
|
||||
"""
|
||||
if config is None:
|
||||
logger.debug("No configuration file available. Cannot load columns definition.")
|
||||
elif not config.has_section(self._section):
|
||||
logger.warning(f"No [{self._section}] section in the configuration file. Cannot load columns definition.")
|
||||
|
||||
columns_def = (
|
||||
config.get_value(self._section, 'columns')
|
||||
if config.get_value(self._section, 'columns')
|
||||
else DEFAULT_COLUMNS
|
||||
)
|
||||
|
||||
return [dict(zip(['plugin', 'field', 'key'], i.split(':'))) for i in columns_def.split(',')]
|
||||
|
||||
def get_servers_list(self):
|
||||
"""Return the current server list (list of dict)."""
|
||||
return self._server_list
|
||||
@ -77,3 +103,7 @@ class GlancesStaticServer:
|
||||
def set_server(self, server_pos, key, value):
|
||||
"""Set the key to the value for the server_pos (position in the list)."""
|
||||
self._server_list[server_pos][key] = value
|
||||
|
||||
def get_columns(self):
|
||||
"""Return the columns definitions"""
|
||||
return self._columns
|
||||
|
Loading…
Reference in New Issue
Block a user