mirror of https://github.com/nicolargo/glances.git
Top almost completed
This commit is contained in:
parent
30ab859244
commit
698c81d7f7
|
|
@ -409,6 +409,68 @@ def dictlist_first_key_value(data: list[dict], key, value) -> Optional[dict]:
|
|||
return ret
|
||||
|
||||
|
||||
def auto_number(number, low_precision=False, min_symbol='K', none_symbol='-', strip_zero=True):
|
||||
"""Make a nice human-readable string out of number.
|
||||
|
||||
Number of decimal places increases as quantity approaches 1.
|
||||
CASE: 613421788 RESULT: 585M low_precision: 585M
|
||||
CASE: 5307033647 RESULT: 4.94G low_precision: 4.9G
|
||||
CASE: 44968414685 RESULT: 41.9G low_precision: 41.9G
|
||||
CASE: 838471403472 RESULT: 781G low_precision: 781G
|
||||
CASE: 9683209690677 RESULT: 8.81T low_precision: 8.8T
|
||||
CASE: 1073741824 RESULT: 1024M low_precision: 1024M
|
||||
CASE: 1181116006 RESULT: 1.10G low_precision: 1.1G
|
||||
|
||||
:low_precision: returns less decimal places potentially (default is False)
|
||||
sacrificing precision for more readability.
|
||||
:min_symbol: Do not approach if number < min_symbol (default is K)
|
||||
:decimal_count: if set, force the number of decimal number (default is None)
|
||||
"""
|
||||
if number is None:
|
||||
return none_symbol
|
||||
|
||||
if number == 0.0:
|
||||
return '0'
|
||||
|
||||
prefix = {
|
||||
'Y': 1208925819614629174706176,
|
||||
'Z': 1180591620717411303424,
|
||||
'E': 1152921504606846976,
|
||||
'P': 1125899906842624,
|
||||
'T': 1099511627776,
|
||||
'G': 1073741824,
|
||||
'M': 1048576,
|
||||
'K': 1024,
|
||||
}
|
||||
symbols = list(reversed(prefix.keys()))
|
||||
if min_symbol in symbols:
|
||||
symbols = symbols[symbols.index(min_symbol) :]
|
||||
|
||||
for symbol in reversed(symbols):
|
||||
value = float(number) / prefix[symbol]
|
||||
if value > 1:
|
||||
decimal_precision = 0
|
||||
if value < 10:
|
||||
decimal_precision = 2
|
||||
elif value < 100:
|
||||
decimal_precision = 1
|
||||
if low_precision:
|
||||
if symbol in 'MK':
|
||||
decimal_precision = 0
|
||||
else:
|
||||
decimal_precision = min(1, decimal_precision)
|
||||
elif symbol in 'K':
|
||||
decimal_precision = 0
|
||||
ret = '{:.{decimal}f}{symbol}'.format(value, decimal=decimal_precision, symbol=symbol)
|
||||
if strip_zero:
|
||||
return ret.replace('.0', '')
|
||||
return ret
|
||||
|
||||
if strip_zero:
|
||||
return f'{number!s}'.replace('.0', '')
|
||||
return f'{number!s}'
|
||||
|
||||
|
||||
def string_value_to_float(s):
|
||||
"""Convert a string with a value and an unit to a float.
|
||||
Example:
|
||||
|
|
|
|||
|
|
@ -16,6 +16,7 @@ from textual.containers import Container, Grid, VerticalScroll
|
|||
from textual.reactive import reactive
|
||||
from textual.widgets import Footer, Label, Placeholder
|
||||
|
||||
from glances.globals import auto_number
|
||||
from glances.plugins.plugin.model import fields_unit_short
|
||||
|
||||
|
||||
|
|
@ -40,8 +41,13 @@ class GlancesTuiApp(App):
|
|||
self.stats = stats
|
||||
|
||||
# Init plugins
|
||||
self.plugins_description = self.stats.getAllFieldsDescriptionAsDict()
|
||||
# TODO: to be replaced by a loop
|
||||
self.plugins = {}
|
||||
self.plugins["cpu"] = GlancesPlugin("cpu", stats=stats, config=config, args=args)
|
||||
self.plugins["mem"] = GlancesPlugin("mem", stats=stats, config=config, args=args)
|
||||
self.plugins["memswap"] = GlancesPlugin("memswap", stats=stats, config=config, args=args)
|
||||
self.plugins["load"] = GlancesPlugin("load", stats=stats, config=config, args=args)
|
||||
|
||||
def compose(self) -> ComposeResult:
|
||||
# yield Header(id="header", show_clock=True)
|
||||
|
|
@ -56,9 +62,9 @@ class GlancesTuiApp(App):
|
|||
Placeholder(id="quicklook"),
|
||||
self.plugins["cpu"],
|
||||
Placeholder(id="gpu", classes="remove"),
|
||||
Placeholder(id="mem"),
|
||||
Placeholder(id="memswap"),
|
||||
Placeholder(id="load"),
|
||||
self.plugins["mem"],
|
||||
self.plugins["memswap"],
|
||||
self.plugins["load"],
|
||||
id="top",
|
||||
),
|
||||
Grid(
|
||||
|
|
@ -99,12 +105,32 @@ class GlancesTuiApp(App):
|
|||
"""Called when the time attribute changes."""
|
||||
# Start by updating Glances stats
|
||||
self.stats.update()
|
||||
# logger.info(self.stats.getAllAsDict()['cpu'])
|
||||
|
||||
# Solution 1: make the update in the GlancesTuiApp class
|
||||
self.query_one("#cpu").query_one("#total").update(str(self.stats.getAllAsDict()["cpu"]["total"]))
|
||||
self.query_one("#cpu").query_one("#system").update(str(self.stats.getAllAsDict()["cpu"]["system"]))
|
||||
# Solution 2: implement the update method in the CpuTextualPlugin class
|
||||
# ... (TODO)
|
||||
# Get stats views
|
||||
views = self.stats.getAllViewsAsDict()
|
||||
# logger.info(views['cpu'])
|
||||
|
||||
# Update the stats using Textual query
|
||||
for plugin in self.plugins.keys():
|
||||
stats = self.stats.getAllAsDict()[plugin]
|
||||
for field in self.query_one(f"#{plugin}").query('.value'):
|
||||
# Ignore field not available in the stats
|
||||
if field.id not in self.stats.getAllAsDict()[plugin]:
|
||||
continue
|
||||
# Update value
|
||||
if (
|
||||
field.id in self.plugins_description[plugin]
|
||||
and 'rate' in self.plugins_description[plugin][field.id]
|
||||
and self.plugins_description[plugin][field.id]['rate']
|
||||
):
|
||||
field_stat = field.id + "_rate_per_sec"
|
||||
else:
|
||||
field_stat = field.id
|
||||
field.update(auto_number(stats.get(field_stat, None)))
|
||||
# Update style
|
||||
style = views[plugin][field.id].get('decoration', 'DEFAULT')
|
||||
field.classes = f"value {style.lower()}"
|
||||
|
||||
|
||||
class GlancesPlugin(Container):
|
||||
|
|
@ -138,20 +164,24 @@ class GlancesPlugin(Container):
|
|||
# Will generate a NoMatches exception when stats are updated
|
||||
# TODO: catch it in the main update loop
|
||||
yield Label(f'{self.plugin.upper()} stats not available', id=f"{self.plugin}-not-available")
|
||||
return
|
||||
|
||||
with Grid(id=f"{self.plugin}"):
|
||||
for field in self.stats.getAllAsDict()[f"{self.plugin}"].keys():
|
||||
for field in self.plugin_description.keys():
|
||||
# Ignore field if the display=False option is defined in the description
|
||||
if not self.plugin_description[field].get('display', True):
|
||||
continue
|
||||
# Get the field short name
|
||||
if field in self.plugin_description and 'short_name' in self.plugin_description[field]:
|
||||
if 'short_name' in self.plugin_description[field]:
|
||||
field_name = self.plugin_description[field]['short_name']
|
||||
else:
|
||||
field_name = field
|
||||
yield Label(field_name, classes="name")
|
||||
# Display value
|
||||
yield Label('', id=field, classes="value ok")
|
||||
# Display value (with decoration classes)
|
||||
yield Label('', id=field, classes="value default")
|
||||
# Display unit
|
||||
if field in self.plugin_description and 'unit' in self.plugin_description[field]:
|
||||
field_unit = fields_unit_short.get(self.plugin_description[field]['unit'], '')
|
||||
else:
|
||||
field_unit = ''
|
||||
yield Label(field_unit, classes="unit ok")
|
||||
yield Label(field_unit, classes="unit")
|
||||
|
|
|
|||
|
|
@ -28,6 +28,7 @@ Placeholder.remove {
|
|||
.unit {
|
||||
text-align: right;
|
||||
padding-right: 1;
|
||||
color: grey;
|
||||
}
|
||||
|
||||
.default {
|
||||
|
|
@ -37,19 +38,39 @@ Placeholder.remove {
|
|||
color: lime;
|
||||
}
|
||||
|
||||
.ok_log {
|
||||
color: black;
|
||||
background: lime;
|
||||
}
|
||||
|
||||
.careful {
|
||||
color: cornflowerblue;
|
||||
}
|
||||
|
||||
.careful_log {
|
||||
color: black;
|
||||
background: cornflowerblue;
|
||||
}
|
||||
|
||||
.warning {
|
||||
color: orangered;
|
||||
color: purple;
|
||||
background: $background;
|
||||
}
|
||||
|
||||
.warning_log {
|
||||
color: $foreground;
|
||||
background: purple;
|
||||
}
|
||||
|
||||
.critical {
|
||||
color: red;
|
||||
}
|
||||
|
||||
.critical_log {
|
||||
color: white;
|
||||
background: red;
|
||||
}
|
||||
|
||||
# Glances layout
|
||||
# ##############
|
||||
|
||||
|
|
@ -90,14 +111,36 @@ Placeholder.remove {
|
|||
# Glances plugins
|
||||
# ###############
|
||||
|
||||
#cpu {
|
||||
grid-size: 9 4;
|
||||
grid-columns: 7 5 2;
|
||||
* > Label {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
#cpu > Label {
|
||||
#cpu {
|
||||
grid-size: 9 4;
|
||||
grid-columns: 6 6 2;
|
||||
width: 100%;
|
||||
align: center top;
|
||||
}
|
||||
|
||||
#mem {
|
||||
grid-size: 6 4;
|
||||
grid-columns: 7 7 2;
|
||||
width: 100%;
|
||||
align: center top;
|
||||
}
|
||||
|
||||
#memswap {
|
||||
grid-size: 3 4;
|
||||
grid-columns: 6 7 2;
|
||||
width: 100%;
|
||||
align: center top;
|
||||
}
|
||||
|
||||
#load {
|
||||
grid-size: 3 4;
|
||||
grid-columns: 5 7 2;
|
||||
width: 100%;
|
||||
align: right top;
|
||||
}
|
||||
|
||||
#network {
|
||||
|
|
|
|||
|
|
@ -18,12 +18,28 @@ from glances.plugins.plugin.model import GlancesPluginModel
|
|||
# Fields description
|
||||
# https://github.com/nicolargo/glances/wiki/How-to-create-a-new-plugin-%3F#create-the-plugin-script
|
||||
fields_description = {
|
||||
'total': {'description': 'Sum of all CPU percentages (except idle).', 'unit': 'percent', 'log': True},
|
||||
'system': {
|
||||
'description': 'Percent time spent in kernel space. System CPU time is the \
|
||||
time spent running code in the Operating System kernel.',
|
||||
'total': {
|
||||
'description': 'Sum of all CPU percentages (except idle).',
|
||||
'unit': 'percent',
|
||||
'log': True,
|
||||
'short_name': 'CPU',
|
||||
},
|
||||
'idle': {
|
||||
'description': 'percent of CPU used by any program. Every program or task \
|
||||
that runs on a computer system occupies a certain amount of processing \
|
||||
time on the CPU. If the CPU has completed all tasks it is idle.',
|
||||
'unit': 'percent',
|
||||
'optional': True,
|
||||
},
|
||||
'ctx_switches': {
|
||||
'description': 'number of context switches (voluntary + involuntary) per \
|
||||
second. A context switch is a procedure that a computer\'s CPU (central \
|
||||
processing unit) follows to change from one task (or process) to \
|
||||
another while ensuring that the tasks do not conflict.',
|
||||
'unit': 'number',
|
||||
'rate': True,
|
||||
'short_name': 'ctx_sw',
|
||||
'optional': True,
|
||||
},
|
||||
'user': {
|
||||
'description': 'CPU percent time spent in user space. \
|
||||
|
|
@ -31,6 +47,41 @@ User CPU time is the time spent on the processor running your program\'s code (o
|
|||
'unit': 'percent',
|
||||
'log': True,
|
||||
},
|
||||
'irq': {
|
||||
'description': '*(Linux and BSD)*: percent time spent servicing/handling \
|
||||
hardware/software interrupts. Time servicing interrupts (hardware + \
|
||||
software).',
|
||||
'unit': 'percent',
|
||||
'optional': True,
|
||||
},
|
||||
'interrupts': {
|
||||
'description': 'number of interrupts per second.',
|
||||
'unit': 'number',
|
||||
'rate': True,
|
||||
'short_name': 'inter',
|
||||
'optional': True,
|
||||
},
|
||||
'system': {
|
||||
'description': 'Percent time spent in kernel space. System CPU time is the \
|
||||
time spent running code in the Operating System kernel.',
|
||||
'unit': 'percent',
|
||||
'log': True,
|
||||
},
|
||||
'nice': {
|
||||
'description': '*(Unix)*: percent time occupied by user level processes with \
|
||||
a positive nice value. The time the CPU has spent running users\' \
|
||||
processes that have been *niced*.',
|
||||
'unit': 'percent',
|
||||
'optional': True,
|
||||
},
|
||||
'soft_interrupts': {
|
||||
'description': 'number of software interrupts per second. Always set to \
|
||||
0 on Windows and SunOS.',
|
||||
'unit': 'number',
|
||||
'rate': True,
|
||||
'short_name': 'sw_int',
|
||||
'optional': True,
|
||||
},
|
||||
'iowait': {
|
||||
'description': '*(Linux)*: percent time spent by the CPU waiting for I/O \
|
||||
operations to complete.',
|
||||
|
|
@ -42,27 +93,6 @@ operations to complete.',
|
|||
'unit': 'percent',
|
||||
'log': True,
|
||||
},
|
||||
'idle': {
|
||||
'description': 'percent of CPU used by any program. Every program or task \
|
||||
that runs on a computer system occupies a certain amount of processing \
|
||||
time on the CPU. If the CPU has completed all tasks it is idle.',
|
||||
'unit': 'percent',
|
||||
'optional': True,
|
||||
},
|
||||
'irq': {
|
||||
'description': '*(Linux and BSD)*: percent time spent servicing/handling \
|
||||
hardware/software interrupts. Time servicing interrupts (hardware + \
|
||||
software).',
|
||||
'unit': 'percent',
|
||||
'optional': True,
|
||||
},
|
||||
'nice': {
|
||||
'description': '*(Unix)*: percent time occupied by user level processes with \
|
||||
a positive nice value. The time the CPU has spent running users\' \
|
||||
processes that have been *niced*.',
|
||||
'unit': 'percent',
|
||||
'optional': True,
|
||||
},
|
||||
'steal': {
|
||||
'description': '*(Linux)*: percentage of time a virtual CPU waits for a real \
|
||||
CPU while the hypervisor is servicing another virtual processor.',
|
||||
|
|
@ -76,44 +106,23 @@ systems under the control of the Linux kernel.',
|
|||
'unit': 'percent',
|
||||
'optional': True,
|
||||
},
|
||||
'ctx_switches': {
|
||||
'description': 'number of context switches (voluntary + involuntary) per \
|
||||
second. A context switch is a procedure that a computer\'s CPU (central \
|
||||
processing unit) follows to change from one task (or process) to \
|
||||
another while ensuring that the tasks do not conflict.',
|
||||
'unit': 'number',
|
||||
'rate': True,
|
||||
'min_symbol': 'K',
|
||||
'short_name': 'ctx_sw',
|
||||
'optional': True,
|
||||
},
|
||||
'interrupts': {
|
||||
'description': 'number of interrupts per second.',
|
||||
'unit': 'number',
|
||||
'rate': True,
|
||||
'min_symbol': 'K',
|
||||
'short_name': 'inter',
|
||||
'optional': True,
|
||||
},
|
||||
'soft_interrupts': {
|
||||
'description': 'number of software interrupts per second. Always set to \
|
||||
0 on Windows and SunOS.',
|
||||
'unit': 'number',
|
||||
'rate': True,
|
||||
'min_symbol': 'K',
|
||||
'short_name': 'sw_int',
|
||||
'optional': True,
|
||||
},
|
||||
'syscalls': {
|
||||
'description': 'number of system calls per second. Always 0 on Linux OS.',
|
||||
'unit': 'number',
|
||||
'rate': True,
|
||||
'min_symbol': 'K',
|
||||
'short_name': 'sys_call',
|
||||
'optional': True,
|
||||
},
|
||||
'cpucore': {'description': 'Total number of CPU core.', 'unit': 'number'},
|
||||
'time_since_update': {'description': 'Number of seconds since last update.', 'unit': 'seconds'},
|
||||
'cpucore': {
|
||||
'description': 'Total number of CPU core.',
|
||||
'unit': 'number',
|
||||
'display': False,
|
||||
},
|
||||
'time_since_update': {
|
||||
'description': 'Number of seconds since last update.',
|
||||
'unit': 'seconds',
|
||||
'display': False,
|
||||
},
|
||||
}
|
||||
|
||||
# SNMP OID
|
||||
|
|
|
|||
|
|
@ -19,6 +19,7 @@ from glances.plugins.plugin.model import GlancesPluginModel
|
|||
|
||||
# Fields description
|
||||
fields_description = {
|
||||
'cpucore': {'description': 'Total number of CPU core.', 'unit': 'core', 'short_name': 'LOAD'},
|
||||
'min1': {
|
||||
'description': 'Average sum of the number of processes \
|
||||
waiting in the run-queue plus the number currently executing \
|
||||
|
|
@ -37,7 +38,6 @@ waiting in the run-queue plus the number currently executing \
|
|||
over 15 minutes.',
|
||||
'unit': 'float',
|
||||
},
|
||||
'cpucore': {'description': 'Total number of CPU core.', 'unit': 'number'},
|
||||
}
|
||||
|
||||
# SNMP OID
|
||||
|
|
@ -204,4 +204,8 @@ def get_load_average(percent: bool = False):
|
|||
|
||||
if load_average and percent:
|
||||
return tuple([round(i / get_nb_log_core() * 100, 1) for i in load_average])
|
||||
if load_average:
|
||||
return tuple(float(f"{x:.2f}") for x in load_average)
|
||||
|
||||
# Return None if load average is not available
|
||||
return load_average
|
||||
|
|
|
|||
|
|
@ -14,66 +14,65 @@ from glances.plugins.plugin.model import GlancesPluginModel
|
|||
|
||||
# Fields description
|
||||
fields_description = {
|
||||
'total': {'description': 'Total physical memory available.', 'unit': 'bytes', 'min_symbol': 'K'},
|
||||
'percent': {
|
||||
'description': 'The percentage usage calculated as (total - available) / total * 100.',
|
||||
'unit': 'percent',
|
||||
'short_name': 'MEM',
|
||||
},
|
||||
'active': {
|
||||
'description': '*(UNIX)*: memory currently in use or very recently used, and so it is in RAM.',
|
||||
'unit': 'bytes',
|
||||
'optional': True,
|
||||
},
|
||||
'total': {
|
||||
'description': 'Total physical memory available.',
|
||||
'unit': 'bytes',
|
||||
},
|
||||
'inactive': {
|
||||
'description': '*(UNIX)*: memory that is marked as not used.',
|
||||
'unit': 'bytes',
|
||||
'short_name': 'inacti',
|
||||
'optional': True,
|
||||
},
|
||||
'used': {
|
||||
'description': 'Memory used, calculated differently depending on the platform and \
|
||||
designed for informational purposes only.',
|
||||
'unit': 'bytes',
|
||||
},
|
||||
'buffers': {
|
||||
'description': '*(Linux, BSD)*: cache for things like file system metadata.',
|
||||
'unit': 'bytes',
|
||||
'short_name': 'buffer',
|
||||
'optional': True,
|
||||
},
|
||||
'free': {
|
||||
'description': 'Memory not being used at all (zeroed) that is readily available; \
|
||||
note that this doesn\'t reflect the actual memory available (use \'available\' instead).',
|
||||
'unit': 'bytes',
|
||||
},
|
||||
'cached': {
|
||||
'description': '*(Linux, BSD)*: cache for various things.',
|
||||
'unit': 'bytes',
|
||||
'optional': True,
|
||||
},
|
||||
'available': {
|
||||
'description': 'The actual amount of available memory that can be given instantly \
|
||||
to processes that request more memory in bytes; this is calculated by summing \
|
||||
different memory values depending on the platform (e.g. free + buffers + cached on Linux) \
|
||||
and it is supposed to be used to monitor actual memory usage in a cross platform fashion.',
|
||||
'unit': 'bytes',
|
||||
'min_symbol': 'K',
|
||||
},
|
||||
'percent': {
|
||||
'description': 'The percentage usage calculated as (total - available) / total * 100.',
|
||||
'unit': 'percent',
|
||||
},
|
||||
'used': {
|
||||
'description': 'Memory used, calculated differently depending on the platform and \
|
||||
designed for informational purposes only.',
|
||||
'unit': 'bytes',
|
||||
'min_symbol': 'K',
|
||||
},
|
||||
'free': {
|
||||
'description': 'Memory not being used at all (zeroed) that is readily available; \
|
||||
note that this doesn\'t reflect the actual memory available (use \'available\' instead).',
|
||||
'unit': 'bytes',
|
||||
'min_symbol': 'K',
|
||||
},
|
||||
'active': {
|
||||
'description': '*(UNIX)*: memory currently in use or very recently used, and so it is in RAM.',
|
||||
'unit': 'bytes',
|
||||
'min_symbol': 'K',
|
||||
'optional': True,
|
||||
},
|
||||
'inactive': {
|
||||
'description': '*(UNIX)*: memory that is marked as not used.',
|
||||
'unit': 'bytes',
|
||||
'min_symbol': 'K',
|
||||
'short_name': 'inacti',
|
||||
'optional': True,
|
||||
},
|
||||
'buffers': {
|
||||
'description': '*(Linux, BSD)*: cache for things like file system metadata.',
|
||||
'unit': 'bytes',
|
||||
'min_symbol': 'K',
|
||||
'short_name': 'buffer',
|
||||
'optional': True,
|
||||
},
|
||||
'cached': {
|
||||
'description': '*(Linux, BSD)*: cache for various things.',
|
||||
'unit': 'bytes',
|
||||
'min_symbol': 'K',
|
||||
'optional': True,
|
||||
'short_name': 'availa',
|
||||
'display': False,
|
||||
},
|
||||
'wired': {
|
||||
'description': '*(BSD, macOS)*: memory that is marked to always stay in RAM. It is never moved to disk.',
|
||||
'unit': 'bytes',
|
||||
'min_symbol': 'K',
|
||||
'display': False,
|
||||
},
|
||||
'shared': {
|
||||
'description': '*(BSD)*: memory that may be simultaneously accessed by multiple processes.',
|
||||
'unit': 'bytes',
|
||||
'min_symbol': 'K',
|
||||
'display': False,
|
||||
},
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -16,21 +16,25 @@ from glances.timer import getTimeSinceLastUpdate
|
|||
|
||||
# Fields description
|
||||
fields_description = {
|
||||
'total': {'description': 'Total swap memory.', 'unit': 'bytes', 'min_symbol': 'K'},
|
||||
'used': {'description': 'Used swap memory.', 'unit': 'bytes', 'min_symbol': 'K'},
|
||||
'free': {'description': 'Free swap memory.', 'unit': 'bytes', 'min_symbol': 'K'},
|
||||
'percent': {'description': 'Used swap memory in percentage.', 'unit': 'percent'},
|
||||
'percent': {'description': 'Used swap memory in percentage.', 'unit': 'percent', 'short_name': 'SWAP'},
|
||||
'total': {'description': 'Total swap memory.', 'unit': 'bytes'},
|
||||
'used': {'description': 'Used swap memory.', 'unit': 'bytes'},
|
||||
'free': {'description': 'Free swap memory.', 'unit': 'bytes'},
|
||||
'sin': {
|
||||
'description': 'The number of bytes the system has swapped in from disk (cumulative).',
|
||||
'unit': 'bytes',
|
||||
'min_symbol': 'K',
|
||||
'display': False,
|
||||
},
|
||||
'sout': {
|
||||
'description': 'The number of bytes the system has swapped out from disk (cumulative).',
|
||||
'unit': 'bytes',
|
||||
'min_symbol': 'K',
|
||||
'display': False,
|
||||
},
|
||||
'time_since_update': {
|
||||
'description': 'Number of seconds since last update.',
|
||||
'unit': 'seconds',
|
||||
'display': False,
|
||||
},
|
||||
'time_since_update': {'description': 'Number of seconds since last update.', 'unit': 'seconds'},
|
||||
}
|
||||
|
||||
# SNMP OID
|
||||
|
|
|
|||
|
|
@ -17,14 +17,27 @@ import re
|
|||
|
||||
from glances.actions import GlancesActions
|
||||
from glances.events_list import glances_events
|
||||
from glances.globals import dictlist, dictlist_json_dumps, iterkeys, itervalues, json_dumps, listkeys, mean, nativestr
|
||||
from glances.globals import (
|
||||
auto_number,
|
||||
dictlist,
|
||||
dictlist_json_dumps,
|
||||
iterkeys,
|
||||
itervalues,
|
||||
json_dumps,
|
||||
listkeys,
|
||||
mean,
|
||||
nativestr,
|
||||
)
|
||||
from glances.history import GlancesHistory
|
||||
from glances.logger import logger
|
||||
from glances.outputs.glances_unicode import unicode_message
|
||||
from glances.thresholds import glances_thresholds
|
||||
from glances.timer import Counter, Timer, getTimeSinceLastUpdate
|
||||
|
||||
fields_unit_short = {'percent': '%'}
|
||||
fields_unit_short = {
|
||||
'percent': '%',
|
||||
'core': 'C',
|
||||
}
|
||||
|
||||
fields_unit_type = {
|
||||
'percent': 'float',
|
||||
|
|
@ -39,6 +52,7 @@ fields_unit_type = {
|
|||
'seconds': 'int',
|
||||
'byte': 'int',
|
||||
'bytes': 'int',
|
||||
'core': 'int',
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -1057,60 +1071,10 @@ class GlancesPluginModel:
|
|||
"""
|
||||
self._align = value
|
||||
|
||||
def auto_unit(self, number, low_precision=False, min_symbol='K', none_symbol='-'):
|
||||
"""Make a nice human-readable string out of number.
|
||||
|
||||
Number of decimal places increases as quantity approaches 1.
|
||||
CASE: 613421788 RESULT: 585M low_precision: 585M
|
||||
CASE: 5307033647 RESULT: 4.94G low_precision: 4.9G
|
||||
CASE: 44968414685 RESULT: 41.9G low_precision: 41.9G
|
||||
CASE: 838471403472 RESULT: 781G low_precision: 781G
|
||||
CASE: 9683209690677 RESULT: 8.81T low_precision: 8.8T
|
||||
CASE: 1073741824 RESULT: 1024M low_precision: 1024M
|
||||
CASE: 1181116006 RESULT: 1.10G low_precision: 1.1G
|
||||
|
||||
:low_precision: returns less decimal places potentially (default is False)
|
||||
sacrificing precision for more readability.
|
||||
:min_symbol: Do not approach if number < min_symbol (default is K)
|
||||
:decimal_count: if set, force the number of decimal number (default is None)
|
||||
"""
|
||||
if number is None:
|
||||
return none_symbol
|
||||
symbols = ('K', 'M', 'G', 'T', 'P', 'E', 'Z', 'Y')
|
||||
if min_symbol in symbols:
|
||||
symbols = symbols[symbols.index(min_symbol) :]
|
||||
prefix = {
|
||||
'Y': 1208925819614629174706176,
|
||||
'Z': 1180591620717411303424,
|
||||
'E': 1152921504606846976,
|
||||
'P': 1125899906842624,
|
||||
'T': 1099511627776,
|
||||
'G': 1073741824,
|
||||
'M': 1048576,
|
||||
'K': 1024,
|
||||
}
|
||||
|
||||
if number == 0:
|
||||
# Avoid 0.0
|
||||
return '0'
|
||||
|
||||
for symbol in reversed(symbols):
|
||||
value = float(number) / prefix[symbol]
|
||||
if value > 1:
|
||||
decimal_precision = 0
|
||||
if value < 10:
|
||||
decimal_precision = 2
|
||||
elif value < 100:
|
||||
decimal_precision = 1
|
||||
if low_precision:
|
||||
if symbol in 'MK':
|
||||
decimal_precision = 0
|
||||
else:
|
||||
decimal_precision = min(1, decimal_precision)
|
||||
elif symbol in 'K':
|
||||
decimal_precision = 0
|
||||
return '{:.{decimal}f}{symbol}'.format(value, decimal=decimal_precision, symbol=symbol)
|
||||
return f'{number!s}'
|
||||
def auto_unit(self, number, low_precision=False, min_symbol='K', none_symbol='-', strip_zero=True):
|
||||
return auto_number(
|
||||
number, low_precision=low_precision, min_symbol=min_symbol, none_symbol=none_symbol, strip_zero=strip_zero
|
||||
)
|
||||
|
||||
def trend_msg(self, trend, significant=1):
|
||||
"""Return the trend message.
|
||||
|
|
|
|||
|
|
@ -18,7 +18,7 @@ from datetime import datetime
|
|||
from glances import __version__
|
||||
from glances.events_list import GlancesEventsList
|
||||
from glances.filter import GlancesFilter, GlancesFilterList
|
||||
from glances.globals import LINUX, WINDOWS, pretty_date, string_value_to_float, subsample
|
||||
from glances.globals import LINUX, WINDOWS, auto_number, pretty_date, string_value_to_float, subsample
|
||||
from glances.main import GlancesMain
|
||||
from glances.outputs.glances_bars import Bar
|
||||
from glances.plugins.plugin.model import GlancesPluginModel
|
||||
|
|
@ -505,6 +505,32 @@ class TestGlances(unittest.TestCase):
|
|||
self.assertEqual(pretty_date(datetime(2023, 1, 1, 0, 0), datetime(2024, 1, 1, 12, 0)), 'an year')
|
||||
self.assertEqual(pretty_date(datetime(2020, 1, 1, 0, 0), datetime(2024, 1, 1, 12, 0)), '4 years')
|
||||
|
||||
def test_022_auto_number(self):
|
||||
"""Test auto_number"""
|
||||
print('INFO: [TEST_022] auto_number')
|
||||
self.assertEqual(auto_number(None), '-')
|
||||
self.assertEqual(auto_number(0), '0')
|
||||
self.assertEqual(auto_number(25), '25')
|
||||
self.assertEqual(auto_number(25.0), '25')
|
||||
self.assertEqual(auto_number(25.3), '25.3')
|
||||
self.assertEqual(auto_number(100), '100')
|
||||
self.assertEqual(auto_number(100.0), '100')
|
||||
self.assertEqual(auto_number(1025.0), '1K')
|
||||
self.assertEqual(auto_number(613421788), '585M')
|
||||
self.assertEqual(auto_number(613421788, low_precision=True), '585M')
|
||||
self.assertEqual(auto_number(5307033647), '4.94G')
|
||||
self.assertEqual(auto_number(5307033647, low_precision=True), '4.9G')
|
||||
self.assertEqual(auto_number(44968414685), '41.9G')
|
||||
self.assertEqual(auto_number(44968414685, low_precision=True), '41.9G')
|
||||
self.assertEqual(auto_number(838471403472), '781G')
|
||||
self.assertEqual(auto_number(838471403472, low_precision=True), '781G')
|
||||
self.assertEqual(auto_number(9683209690677), '8.81T')
|
||||
self.assertEqual(auto_number(9683209690677, low_precision=True), '8.8T')
|
||||
self.assertEqual(auto_number(1073741824), '1024M')
|
||||
self.assertEqual(auto_number(1073741824, low_precision=True), '1024M')
|
||||
self.assertEqual(auto_number(1181116006), '1.10G')
|
||||
self.assertEqual(auto_number(1181116006, low_precision=True), '1.1G')
|
||||
|
||||
def test_094_thresholds(self):
|
||||
"""Test thresholds classes"""
|
||||
print('INFO: [TEST_094] Thresholds')
|
||||
|
|
|
|||
Loading…
Reference in New Issue