mirror of
https://github.com/nicolargo/glances.git
synced 2024-12-22 16:51:35 +03:00
Merge branch 'refs/heads/develop' into 2637-docker-memory-usage-is-incorrect
# Conflicts: # glances/outputs/static/public/glances.js
This commit is contained in:
commit
5b54ef9baf
49
.github/workflows/test.yml
vendored
49
.github/workflows/test.yml
vendored
@ -47,33 +47,38 @@ jobs:
|
||||
run: |
|
||||
python ./unitest.py
|
||||
|
||||
test-windows:
|
||||
# Error appear with h11, not related to Glances
|
||||
# Should be tested if correction is done
|
||||
# Installed c:\hostedtoolcache\windows\python\3.9.13\x64\lib\site-packages\exceptiongroup-1.2.1-py3.9.egg
|
||||
# error: h11 0.14.0 is installed but h11<0.13,>=0.11 is required by {'httpcore'}
|
||||
# Error: Process completed with exit code 1.
|
||||
# test-windows:
|
||||
|
||||
# https://github.com/actions/runner-images?tab=readme-ov-file#available-images
|
||||
runs-on: windows-latest
|
||||
strategy:
|
||||
matrix:
|
||||
# Python version "3.12" introduce this issue:
|
||||
# https://github.com/nicolargo/glances/actions/runs/6439648370/job/17487567454
|
||||
python-version: ["3.8", "3.9", "3.10", "3.11"]
|
||||
steps:
|
||||
# # https://github.com/actions/runner-images?tab=readme-ov-file#available-images
|
||||
# runs-on: windows-latest
|
||||
# strategy:
|
||||
# matrix:
|
||||
# # Python version "3.12" introduce this issue:
|
||||
# # https://github.com/nicolargo/glances/actions/runs/6439648370/job/17487567454
|
||||
# python-version: ["3.8", "3.9", "3.10", "3.11"]
|
||||
# steps:
|
||||
|
||||
- uses: actions/checkout@v4
|
||||
# - uses: actions/checkout@v4
|
||||
|
||||
- name: Set up Python ${{ matrix.python-version }}
|
||||
uses: actions/setup-python@v4
|
||||
with:
|
||||
python-version: ${{ matrix.python-version }}
|
||||
# - name: Set up Python ${{ matrix.python-version }}
|
||||
# uses: actions/setup-python@v4
|
||||
# with:
|
||||
# python-version: ${{ matrix.python-version }}
|
||||
|
||||
- name: Install dependencies
|
||||
run: |
|
||||
python -m pip install --upgrade pip
|
||||
if (Test-Path -PathType Leaf "requirements.txt") { python -m pip install -r requirements.txt }
|
||||
python setup.py install
|
||||
# - name: Install dependencies
|
||||
# run: |
|
||||
# python -m pip install --upgrade pip
|
||||
# if (Test-Path -PathType Leaf "requirements.txt") { python -m pip install -r requirements.txt }
|
||||
# python setup.py install
|
||||
|
||||
- name: Unitary tests
|
||||
run: |
|
||||
python ./unitest.py
|
||||
# - name: Unitary tests
|
||||
# run: |
|
||||
# python ./unitest.py
|
||||
|
||||
test-macos:
|
||||
|
||||
|
42
README.rst
42
README.rst
@ -87,7 +87,6 @@ Requirements
|
||||
- ``defusedxml`` (in order to monkey patch xmlrpc)
|
||||
- ``packaging`` (for the version comparison)
|
||||
- ``ujson`` (an optimized alternative to the standard json module)
|
||||
- ``pytz`` (for the timezone support)
|
||||
- ``pydantic`` (for the data validation support)
|
||||
|
||||
*Note for Python 2 users*
|
||||
@ -122,7 +121,7 @@ Optional dependencies:
|
||||
- ``pygal`` (for the graph export module)
|
||||
- ``pymdstat`` (for RAID support) [Linux-only]
|
||||
- ``pymongo`` (for the MongoDB export module)
|
||||
- ``pysnmp`` (for SNMP support)
|
||||
- ``pysnmp-lextudio`` (for SNMP support)
|
||||
- ``pySMART.smartx`` (for HDD Smart support) [Linux-only]
|
||||
- ``pyzmq`` (for the ZeroMQ export module)
|
||||
- ``requests`` (for the Ports, Cloud plugins and RESTful export module)
|
||||
@ -136,26 +135,27 @@ Installation
|
||||
|
||||
There are several methods to test/install Glances on your system. Choose your weapon!
|
||||
|
||||
PyPI: The standard way
|
||||
----------------------
|
||||
PyPI: Pip, the standard way
|
||||
---------------------------
|
||||
|
||||
Glances is on ``PyPI``. By using PyPI, you will be using the latest
|
||||
stable version.
|
||||
|
||||
To install Glances, simply use ``pip``:
|
||||
To install Glances, simply use the ``pip`` command line.
|
||||
|
||||
Warning: on modern Linux operating systems, you may have an externally-managed-environment
|
||||
error message when you try to use ``pip``. In this case, go to the the PipX section bellow.
|
||||
|
||||
.. code-block:: console
|
||||
|
||||
pip install --user glances
|
||||
|
||||
*Note*: Python headers are required to install `psutil`_, a Glances
|
||||
dependency. For example, on Debian/Ubuntu **the simplest** is ``apt install python3-psutil`` or alternatively need to install first
|
||||
dependency. For example, on Debian/Ubuntu **the simplest** is
|
||||
``apt install python3-psutil`` or alternatively need to install first
|
||||
the *python-dev* package and gcc (*python-devel* on Fedora/CentOS/RHEL).
|
||||
For Windows, just install psutil from the binary installation file.
|
||||
|
||||
*Note 2 (for the Wifi plugin)*: If you want to use the Wifi plugin, you need
|
||||
to install the *wireless-tools* package on your system.
|
||||
|
||||
By default, Glances is installed without the Web interface dependencies.
|
||||
To install it, use the following command:
|
||||
|
||||
@ -182,24 +182,18 @@ If you want to test the develop version (could be instable), enter:
|
||||
|
||||
pip install --user -i https://test.pypi.org/simple/ Glances
|
||||
|
||||
Glances Auto Install script: the easy way
|
||||
-----------------------------------------
|
||||
PyPI: PipX, the alternative way
|
||||
-------------------------------
|
||||
|
||||
To install both dependencies and the latest Glances production ready version
|
||||
(aka *master* branch), just enter the following command line:
|
||||
Install PipX on your system (apt install pipx on Ubuntu).
|
||||
|
||||
Install Glances (with all features):
|
||||
|
||||
.. code-block:: console
|
||||
|
||||
curl -L https://bit.ly/glances | /bin/bash
|
||||
pipx install 'glances[all]'
|
||||
|
||||
or
|
||||
|
||||
.. code-block:: console
|
||||
|
||||
wget -O- https://bit.ly/glances | /bin/bash
|
||||
|
||||
*Note*: This is only supported on some GNU/Linux distributions and Mac OS X.
|
||||
If you want to support other distributions, please contribute to `glancesautoinstall`_.
|
||||
The glances script will be installed in the ~/.local/bin folder.
|
||||
|
||||
Docker: the cloudy way
|
||||
----------------------
|
||||
@ -257,8 +251,8 @@ Run the container in *Web server mode*:
|
||||
|
||||
For a full list of options, see the Glances `Docker`_ documentation page.
|
||||
|
||||
GNU/Linux
|
||||
---------
|
||||
GNU/Linux package
|
||||
-----------------
|
||||
|
||||
`Glances` is available on many Linux distributions, so you should be
|
||||
able to install it using your favorite package manager. Be aware that
|
||||
|
@ -239,7 +239,7 @@ public_template={continent_name}/{country_name}/{city_name}
|
||||
|
||||
[connections]
|
||||
# Display additional information about TCP connections
|
||||
# This plugin is disabled by default
|
||||
# This plugin is disabled by default because it consumes lots of CPU
|
||||
disable=True
|
||||
# nf_conntrack thresholds in %
|
||||
nf_conntrack_percent_careful=70
|
||||
@ -333,8 +333,9 @@ port=7634
|
||||
[sensors]
|
||||
# Documentation: https://glances.readthedocs.io/en/latest/aoa/sensors.html
|
||||
disable=False
|
||||
# By default refresh every refresh time * 2
|
||||
#refresh=6
|
||||
# Set the refresh multiplicator for the sensors
|
||||
# By default refresh every Glances refresh * 3 (increase to reduce CPU consumption)
|
||||
#refresh=3
|
||||
# Hide some sensors (comma separated list of regexp)
|
||||
hide=unknown.*
|
||||
# Show only the following sensors (comma separated list of regexp)
|
||||
|
@ -239,7 +239,7 @@ public_template={continent_name}/{country_name}/{city_name}
|
||||
|
||||
[connections]
|
||||
# Display additional information about TCP connections
|
||||
# This plugin is disabled by default
|
||||
# This plugin is disabled by default because it consumes lots of CPU
|
||||
disable=True
|
||||
# nf_conntrack thresholds in %
|
||||
nf_conntrack_percent_careful=70
|
||||
@ -333,8 +333,9 @@ port=7634
|
||||
[sensors]
|
||||
# Documentation: https://glances.readthedocs.io/en/latest/aoa/sensors.html
|
||||
disable=False
|
||||
# By default refresh every refresh time * 2
|
||||
#refresh=6
|
||||
# Set the refresh multiplicator for the sensors
|
||||
# By default refresh every Glances refresh * 3 (increase to reduce CPU consumption)
|
||||
#refresh=3
|
||||
# Hide some sensors (comma separated list of regexp)
|
||||
hide=unknown.*
|
||||
# Show only the following sensors (comma separated list of regexp)
|
||||
|
@ -1130,6 +1130,10 @@ class _GlancesCurses(object):
|
||||
update the terminal."""
|
||||
self.term_window.erase()
|
||||
|
||||
def refresh(self):
|
||||
"""Refresh the windows"""
|
||||
self.term_window.refresh()
|
||||
|
||||
def flush(self, stats, cs_status=None):
|
||||
"""Erase and update the screen.
|
||||
|
||||
@ -1139,8 +1143,10 @@ class _GlancesCurses(object):
|
||||
"Connected": Client is connected to the server
|
||||
"Disconnected": Client is disconnected from the server
|
||||
"""
|
||||
# See https://stackoverflow.com/a/43486979/1919431
|
||||
self.erase()
|
||||
self.display(stats, cs_status=cs_status)
|
||||
self.refresh()
|
||||
|
||||
def update(self, stats, duration=3, cs_status=None, return_to_browser=False):
|
||||
"""Update the screen.
|
||||
|
@ -29,7 +29,7 @@
|
||||
>
|
||||
MEM
|
||||
</div>
|
||||
<div class="table-cell">/MAX</div>
|
||||
<div class="table-cell text-left">/MAX</div>
|
||||
<div class="table-cell">IOR/s</div>
|
||||
<div class="table-cell">IOW/s</div>
|
||||
<div class="table-cell">RX/s</div>
|
||||
@ -56,8 +56,8 @@
|
||||
<div class="table-cell">
|
||||
{{ $filters.bytes(container.memory_usage) }}
|
||||
</div>
|
||||
<div class="table-cell">
|
||||
{{ $filters.bytes(container.limit) }}
|
||||
<div class="table-cell text-left">
|
||||
/{{ $filters.bytes(container.limit) }}
|
||||
</div>
|
||||
<div class="table-cell">
|
||||
{{ $filters.bytes(container.io_rx) }}
|
||||
|
@ -106,30 +106,46 @@ class PluginModel(GlancesPluginModel):
|
||||
('toggle_linux_percentage', msg_col.format('0', 'Load, Linux/percentage')),
|
||||
('toggle_cpu_individual_combined', msg_col.format('1', 'CPU, individual/combined')),
|
||||
('toggle_gpu_individual_combined', msg_col.format('6', 'GPU, individual/combined')),
|
||||
('toggle_short_full',
|
||||
msg_col.format('S',
|
||||
'Process names, short/full') if self.args.webserver else msg_col.format('/', 'Process names, short/full')),
|
||||
(
|
||||
'toggle_short_full',
|
||||
(
|
||||
msg_col.format('S', 'Process names, short/full')
|
||||
if self.args and self.args.webserver
|
||||
else msg_col.format('/', 'Process names, short/full')
|
||||
),
|
||||
),
|
||||
('header_miscellaneous', msg_header.format('MISCELLANEOUS:')),
|
||||
('misc_erase_process_filter',
|
||||
'' if self.args.webserver else msg_col.format('E', 'Erase process filter')),
|
||||
('misc_generate_history_graphs',
|
||||
'' if self.args.webserver else msg_col.format('g', 'Generate history graphs')),
|
||||
(
|
||||
'misc_erase_process_filter',
|
||||
'' if self.args and self.args.webserver else msg_col.format('E', 'Erase process filter'),
|
||||
),
|
||||
(
|
||||
'misc_generate_history_graphs',
|
||||
'' if self.args and self.args.webserver else msg_col.format('g', 'Generate history graphs'),
|
||||
),
|
||||
('misc_help', msg_col.format('h', 'HELP')),
|
||||
('misc_accumulate_processes_by_program',
|
||||
'' if self.args.webserver else msg_col.format('j', 'Display threads or programs')),
|
||||
(
|
||||
'misc_accumulate_processes_by_program',
|
||||
'' if self.args and self.args.webserver else msg_col.format('j', 'Display threads or programs'),
|
||||
),
|
||||
('misc_increase_nice_process', msg_col.format('+', 'Increase nice process')),
|
||||
('misc_decrease_nice_process', msg_col.format('-', 'Decrease nice process (need admin rights)')),
|
||||
('misc_kill_process',
|
||||
'' if self.args.webserver else msg_col.format('k', 'Kill process')),
|
||||
('misc_reset_processes_summary_min_max',
|
||||
'' if self.args.webserver else msg_col.format('M', 'Reset processes summary min/max')),
|
||||
('misc_quit',
|
||||
'' if self.args.webserver else msg_col.format('q', 'QUIT (or Esc or Ctrl-C)')),
|
||||
('misc_kill_process', '' if self.args and self.args.webserver else msg_col.format('k', 'Kill process')),
|
||||
(
|
||||
'misc_reset_processes_summary_min_max',
|
||||
'' if self.args and self.args.webserver else msg_col.format('M', 'Reset processes summary min/max'),
|
||||
),
|
||||
(
|
||||
'misc_quit',
|
||||
'' if self.args and self.args.webserver else msg_col.format('q', 'QUIT (or Esc or Ctrl-C)'),
|
||||
),
|
||||
('misc_reset_history', msg_col.format('r', 'Reset history')),
|
||||
('misc_delete_warning_alerts', msg_col.format('w', 'Delete warning alerts')),
|
||||
('misc_delete_warning_and_critical_alerts', msg_col.format('x', 'Delete warning & critical alerts')),
|
||||
('misc_edit_process_filter_pattern',
|
||||
'' if self.args.webserver else ' ENTER: Edit process filter pattern'),
|
||||
(
|
||||
'misc_edit_process_filter_pattern',
|
||||
'' if self.args and self.args.webserver else ' ENTER: Edit process filter pattern',
|
||||
),
|
||||
]
|
||||
)
|
||||
|
||||
|
@ -204,12 +204,8 @@ class PluginModel(GlancesPluginModel):
|
||||
self.reset()
|
||||
return self.stats
|
||||
|
||||
for key in iterkeys(stats):
|
||||
if stats[key] != '':
|
||||
stats[key] = float(stats[key]) * 1024
|
||||
|
||||
# Use the 'free'/htop calculation
|
||||
stats['free'] = stats['free'] - stats['total'] + (stats['buffers'] + stats['cached'])
|
||||
for k in stats:
|
||||
stats[k] = int(stats[k]) * 1024
|
||||
|
||||
# used=total-free
|
||||
stats['used'] = stats['total'] - stats['free']
|
||||
|
@ -53,9 +53,9 @@ class PluginModel(GlancesPluginModel):
|
||||
# Set the message position
|
||||
self.align = 'bottom'
|
||||
|
||||
if args.strftime_format:
|
||||
if args and args.strftime_format:
|
||||
self.strftime = args.strftime_format
|
||||
elif config is not None:
|
||||
elif config:
|
||||
if 'global' in config.as_dict():
|
||||
self.strftime = config.as_dict()['global']['strftime_format']
|
||||
|
||||
|
@ -108,7 +108,10 @@ class PluginModel(GlancesPluginModel):
|
||||
self.display_curse = True
|
||||
|
||||
# Manage the maximum number of CPU to display (related to enhancement request #2734)
|
||||
if config:
|
||||
self.max_cpu_display = config.get_int_value('percpu', 'max_cpu_display', 4)
|
||||
else:
|
||||
self.max_cpu_display = 4
|
||||
|
||||
def get_key(self):
|
||||
"""Return the key of the list."""
|
||||
|
@ -350,8 +350,10 @@ class GlancesPluginModel(object):
|
||||
ret = {}
|
||||
if bulk:
|
||||
# Bulk request
|
||||
snmp_result = snmp_client.getbulk_by_oid(0, 10, itervalues(*snmp_oid))
|
||||
|
||||
snmp_result = snmp_client.getbulk_by_oid(0,
|
||||
10,
|
||||
*list(itervalues(snmp_oid)))
|
||||
logger.info(snmp_result)
|
||||
if len(snmp_oid) == 1:
|
||||
# Bulk command for only one OID
|
||||
# Note: key is the item indexed but the OID result
|
||||
@ -379,7 +381,7 @@ class GlancesPluginModel(object):
|
||||
index += 1
|
||||
else:
|
||||
# Simple get request
|
||||
snmp_result = snmp_client.get_by_oid(itervalues(*snmp_oid))
|
||||
snmp_result = snmp_client.get_by_oid(*list(itervalues(snmp_oid)))
|
||||
|
||||
# Build the internal dict with the SNMP result
|
||||
for key in iterkeys(snmp_oid):
|
||||
@ -623,7 +625,7 @@ class GlancesPluginModel(object):
|
||||
"""Return the plugin refresh time"""
|
||||
ret = self.get_limits(item='refresh')
|
||||
if ret is None:
|
||||
ret = self.args.time
|
||||
ret = self.args.time if hasattr(self.args, 'time') else 2
|
||||
return ret
|
||||
|
||||
def get_refresh_time(self):
|
||||
|
@ -194,7 +194,7 @@ class PluginModel(GlancesPluginModel):
|
||||
config.as_dict()['processlist']['export']))
|
||||
|
||||
# The default sort key could also be overwrite by command line (see #1903)
|
||||
if args.sort_processes_key is not None:
|
||||
if args and args.sort_processes_key is not None:
|
||||
glances_processes.set_sort_key(args.sort_processes_key, False)
|
||||
|
||||
# Note: 'glances_processes' is already init in the processes.py script
|
||||
|
@ -92,7 +92,7 @@ class PluginModel(GlancesPluginModel):
|
||||
self.display_curse = True
|
||||
|
||||
# Manage the maximum number of CPU to display (related to enhancement request #2734)
|
||||
self.max_cpu_display = config.get_int_value('percpu', 'max_cpu_display', 4)
|
||||
self.max_cpu_display = config.get_int_value('percpu', 'max_cpu_display', 4) if config else 4
|
||||
|
||||
# Define the stats list
|
||||
self.stats_list = self.get_conf_value('list', default=self.DEFAULT_STATS_LIST)
|
||||
|
@ -26,6 +26,11 @@ SENSOR_TEMP_UNIT = 'C'
|
||||
SENSOR_FAN_TYPE = 'fan_speed'
|
||||
SENSOR_FAN_UNIT = 'R'
|
||||
|
||||
# Define the default refresh multiplicator
|
||||
# Default value is 3 * Glances refresh time
|
||||
# Can be overwritten by the refresh option in the sensors section of the glances.conf file
|
||||
DEFAULT_REFRESH = 3
|
||||
|
||||
# Fields description
|
||||
# description: human readable description
|
||||
# short_name: shortname to use un UI
|
||||
@ -96,9 +101,8 @@ class PluginModel(GlancesPluginModel):
|
||||
self.display_curse = True
|
||||
|
||||
# Not necessary to refresh every refresh time
|
||||
# By default set to refresh * 2
|
||||
if self.get_refresh() == args.time:
|
||||
self.set_refresh(self.get_refresh() * 2)
|
||||
if args and self.get_refresh() == args.time:
|
||||
self.set_refresh(self.get_refresh() * DEFAULT_REFRESH)
|
||||
|
||||
def get_key(self):
|
||||
"""Return the key of the list."""
|
||||
|
@ -125,7 +125,7 @@ class PluginModel(GlancesPluginModel):
|
||||
def __init__(self, args=None, config=None, stats_init_value=[]):
|
||||
"""Init the plugin."""
|
||||
# check if user is admin
|
||||
if not is_admin():
|
||||
if not is_admin() and args:
|
||||
disable(args, "smart")
|
||||
logger.debug("Current user is not admin, HDD SMART plugin disabled.")
|
||||
|
||||
|
@ -132,7 +132,7 @@ class PluginModel(GlancesPluginModel):
|
||||
self.set_refresh(60)
|
||||
|
||||
# Get the default message (if defined)
|
||||
self.system_info_msg = config.get_value('system', 'system_info_msg')
|
||||
self.system_info_msg = config.get_value('system', 'system_info_msg') if config else None
|
||||
|
||||
@GlancesPluginModel._check_decorator
|
||||
@GlancesPluginModel._log_result_decorator
|
||||
|
@ -41,12 +41,9 @@ class GlancesSNMPClient(object):
|
||||
ret = {}
|
||||
for name, val in varBinds:
|
||||
if str(val) == '':
|
||||
ret[name.prettyPrint()] = ''
|
||||
ret[str(name)] = ''
|
||||
else:
|
||||
ret[name.prettyPrint()] = val.prettyPrint()
|
||||
# In Python 3, prettyPrint() return 'b'linux'' instead of 'linux'
|
||||
if ret[name.prettyPrint()].startswith('b\''):
|
||||
ret[name.prettyPrint()] = ret[name.prettyPrint()][2:-1]
|
||||
ret[str(name)] = val.prettyPrint()
|
||||
return ret
|
||||
|
||||
def __get_result__(self, errorIndication, errorStatus, errorIndex, varBinds):
|
||||
|
@ -148,15 +148,16 @@ class GlancesStandalone(object):
|
||||
logger.debug('Stats updated duration: {} seconds'.format(counter.get()))
|
||||
|
||||
# Patch for issue1326 to avoid < 0 refresh
|
||||
adapted_refresh = self.refresh_time - counter.get()
|
||||
adapted_refresh = adapted_refresh if adapted_refresh > 0 else 0
|
||||
adapted_refresh = (self.refresh_time - counter.get()) if (self.refresh_time - counter.get()) > 0 else 0
|
||||
|
||||
# Display stats
|
||||
# and wait refresh_time - counter
|
||||
if not self.quiet:
|
||||
# The update function return True if an exit key 'q' or 'ESC'
|
||||
# has been pressed.
|
||||
counter_display = Counter()
|
||||
ret = not self.screen.update(self.stats, duration=adapted_refresh)
|
||||
logger.debug('Stats display duration: {} seconds'.format(counter_display.get() - adapted_refresh))
|
||||
else:
|
||||
# Nothing is displayed
|
||||
# Break should be done via a signal (CTRL-C)
|
||||
|
@ -27,7 +27,7 @@ pygal
|
||||
pymdstat
|
||||
pymongo; python_version >= "3.7"
|
||||
nvidia-ml-py; python_version >= "3.5"
|
||||
pysnmp
|
||||
pysnmp-lextudio; python_version >= "3.7"
|
||||
pySMART.smartx
|
||||
python-dateutil
|
||||
pyzmq
|
||||
|
@ -2,5 +2,4 @@ psutil>=5.6.7
|
||||
defusedxml
|
||||
packaging
|
||||
ujson>=5.4.0
|
||||
pytz
|
||||
pydantic
|
||||
|
Loading…
Reference in New Issue
Block a user