Merge branch 'develop' of https://github.com/nicolargo/glances into develop

This commit is contained in:
Drakarah 2026-01-03 07:33:53 +00:00
commit 862ac41b58
34 changed files with 1129 additions and 1898 deletions

View File

@ -11,10 +11,7 @@ repos:
- id: ruff-check
name: "🐍 python · Linter with Ruff"
types_or: [ python, pyi ]
args: [ --fix, --exit-non-zero-on-fix ]
- id: ruff-format
name: "🐍 python · Format with Ruff"
types_or: [ python, pyi ]
args: [ --fix, --exit-non-zero-on-fix, --config, './pyproject.toml' ]
# - repo: https://github.com/RobertCraigie/pyright-python
# rev: v1.1.391
@ -48,11 +45,11 @@ repos:
name: "🐚 shell · Check shell script code style"
entry: bashate --error . --ignore=E006
- repo: https://github.com/mrtazz/checkmake.git
rev: 0.2.2
hooks:
- id: checkmake
name: "🐮 Makefile · Lint Makefile"
# - repo: https://github.com/mrtazz/checkmake.git
# rev: 0.2.2
# hooks:
# - id: checkmake
# name: "🐮 Makefile · Lint Makefile"
- repo: https://github.com/pre-commit/pre-commit-hooks
rev: v6.0.0

View File

@ -20,7 +20,7 @@ UV_RUN := .venv-uv/bin/uv
# if the command is only `make`, the default tasks will be the printing of the help.
.DEFAULT_GOAL := help
.PHONY: help test docs docs-server venv requirements profiling docker all clean
.PHONY: help test docs docs-server venv requirements profiling docker all clean all test
help: ## List all make commands available
@grep -E '^[\.a-zA-Z_%-]+:.*?## .*$$' $(MAKEFILE_LIST) | \
@ -134,7 +134,10 @@ test-export-influxdb-v3: ## Run interface tests with InfluxDB version 3 (Core)
test-export-timescaledb: ## Run interface tests with TimescaleDB
/bin/bash ./tests/test_export_timescaledb.sh
test-exports: test-export-csv test-export-json test-export-influxdb-v1 test-export-influxdb-v3 test-export-timescaledb ## Tests all exports
test-export-nats: ## Run interface tests with NATS
/bin/bash ./tests/test_export_nats.sh
test-exports: test-export-csv test-export-json test-export-influxdb-v1 test-export-influxdb-v3 test-export-timescaledb test-export-nats ## Tests all exports
# ===================================================================
# Linters, profilers and cyber security

View File

@ -242,7 +242,7 @@ Glances can export stats to:
- files: ``CSV`` and ``JSON``
- databases: ``InfluxDB``, ``ElasticSearch``, ``PostgreSQL/TimeScale``, ``Cassandra``, ``CouchDB``, ``OpenTSDB``, ``Prometheus``, ``StatsD``, ``Riemann`` and ``Graphite``
- brokers: ``RabbitMQ/ActiveMQ``, ``ZeroMQ`` and ``Kafka``
- brokers: ``RabbitMQ/ActiveMQ``, ``NATS``, ``ZeroMQ`` and ``Kafka``
- others: ``RESTful`` endpoint
Installation 🚀
@ -255,14 +255,14 @@ 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 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 below.
To install Glances, simply use the ``pip`` command line in an virtual environment.
.. code-block:: console
pip install --user glances
cd ~
python3 -m venv ~/.venv
source ~/.venv/bin/activate
pip install glances
*Note*: Python headers are required to install `psutil`_, a Glances
dependency. For example, on Debian/Ubuntu **the simplest** is
@ -271,17 +271,18 @@ the *python-dev* package and gcc (*python-devel* on Fedora/CentOS/RHEL).
For Windows, just install psutil from the binary installation file.
By default, Glances is installed **without** the Web interface dependencies.
To install it, use the following command:
.. code-block:: console
pip install --user 'glances[web]'
pip install 'glances[web]'
For a full installation (with all features, see features list bellow):
.. code-block:: console
pip install --user 'glances[all]'
pip install 'glances[all]'
Features list:
@ -306,21 +307,18 @@ To upgrade Glances to the latest version:
.. code-block:: console
pip install --user --upgrade glances
The current develop branch is published to the test.pypi.org package index.
If you want to test the develop version (could be instable), enter:
.. code-block:: console
pip install --user -i https://test.pypi.org/simple/ Glances
pip install --upgrade glances
PyPI: PipX, the alternative way
-------------------------------
Install PipX on your system (apt install pipx on Ubuntu).
Install PipX on your system. For example on Ubuntu/Debian:
Install Glances (with all features):
.. code-block:: console
sudo apt install pipx
Then install Glances (with all features):
.. code-block:: console
@ -328,14 +326,11 @@ Install Glances (with all features):
The glances script will be installed in the ~/.local/bin folder.
Brew: The missing package manager
---------------------------------
For Linux and Mac OS, it is also possible to install Glances with `Brew`_:
To upgrade Glances to the latest version:
.. code-block:: console
brew install glances
pipx upgrade glances
Docker: the cloudy way
----------------------
@ -343,12 +338,6 @@ Docker: the cloudy way
Glances Docker images are available. You can use it to monitor your
server and all your containers !
Get the Glances container:
.. code-block:: console
docker pull nicolargo/glances:latest-full
The following tags are available:
- *latest-full* for a full Alpine Glances image (latest release) with all dependencies
@ -393,13 +382,32 @@ Run the container in *Web server mode*:
For a full list of options, see the Glances `Docker`_ documentation page.
It is also possible to use a simple Docker compose file (see in ./docker-compose/docker-compose.yml):
.. code-block:: console
cd ./docker-compose
docker-compose up
It will start a Glances server with WebUI.
Brew: The missing package manager
---------------------------------
For Linux and Mac OS, it is also possible to install Glances with `Brew`_:
.. code-block:: console
brew install glances
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
when you use this method the operating system `package`_ for `Glances`
may not be the latest version and only basics plugins are enabled.
able to install it using your favorite package manager. Nevetheless,
i do not recommend it. Be aware that when you use this method the operating
system `package`_ for `Glances`may not be the latest version and only basics
plugins are enabled.
Note: The Debian package (and all other Debian-based distributions) do
not include anymore the JS statics files used by the Web interface
@ -418,7 +426,6 @@ Check for Python version:
# python --version
Install the Glances package:
.. code-block:: console
@ -464,11 +471,7 @@ Windows
-------
Install `Python`_ for Windows (Python 3.4+ ship with pip) and
then run the following command:
.. code-block:: console
$ pip install glances
follow the Glances Pip install procedure.
Android
-------
@ -571,6 +574,7 @@ Extra dependencies:
- ``influxdb`` (for the InfluxDB version 1 export module)
- ``influxdb-client`` (for the InfluxDB version 2 export module)
- ``kafka-python`` (for the Kafka export module)
- ``nats-py`` (for the NATS export module)
- ``netifaces2`` (for the IP plugin)
- ``nvidia-ml-py`` (for the GPU plugin)
- ``pycouchdb`` (for the CouchDB export module)

View File

@ -40,23 +40,17 @@ cryptography==46.0.3
# via pysnmpcrypto
defusedxml==0.7.1
# via glances
dnspython==2.7.0 ; python_full_version < '3.10'
# via pymongo
dnspython==2.8.0 ; python_full_version >= '3.10'
dnspython==2.8.0
# via pymongo
docker==7.1.0
# via glances
elastic-transport==9.1.0 ; python_full_version < '3.10'
elastic-transport==9.2.1
# via elasticsearch
elastic-transport==9.2.0 ; python_full_version >= '3.10'
# via elasticsearch
elasticsearch==9.1.2 ; python_full_version < '3.10'
# via glances
elasticsearch==9.2.0 ; python_full_version >= '3.10'
elasticsearch==9.2.1
# via glances
exceptiongroup==1.2.2 ; python_full_version < '3.11'
# via anyio
fastapi==0.125.0
fastapi==0.128.0
# via glances
geomet==1.1.0
# via cassandra-driver
@ -68,9 +62,7 @@ humanfriendly==10.0
# via pysmart
ibm-cloud-sdk-core==3.24.2
# via ibmcloudant
ibmcloudant==0.11.0 ; python_full_version < '3.10'
# via glances
ibmcloudant==0.11.2 ; python_full_version >= '3.10'
ibmcloudant==0.11.2
# via glances
idna==3.11
# via
@ -78,9 +70,7 @@ idna==3.11
# requests
ifaddr==0.2.0
# via zeroconf
importlib-metadata==7.1.0 ; python_full_version < '3.10'
# via pygal
importlib-metadata==8.7.0 ; python_full_version >= '3.10'
importlib-metadata==8.7.1
# via pygal
influxdb==5.3.2
# via glances
@ -98,6 +88,8 @@ markupsafe==3.0.3
# via jinja2
msgpack==1.1.2
# via influxdb
nats-py==2.12.0
# via glances
netifaces2==0.0.22
# via glances
nvidia-ml-py==13.590.44
@ -118,23 +110,15 @@ potsdb==1.0.3
# via glances
prometheus-client==0.23.1
# via glances
protobuf==4.25.8 ; python_full_version < '3.10'
protobuf==6.33.2
# via bernhard
protobuf==6.33.2 ; python_full_version >= '3.10'
# via bernhard
psutil==7.1.3
psutil==7.2.1
# via glances
psycopg==3.2.13 ; python_full_version < '3.10'
psycopg==3.3.2
# via glances
psycopg==3.3.2 ; python_full_version >= '3.10'
# via glances
psycopg-binary==3.2.13 ; python_full_version < '3.10' and implementation_name != 'pypy'
psycopg-binary==3.3.2 ; implementation_name != 'pypy'
# via psycopg
psycopg-binary==3.3.2 ; python_full_version >= '3.10' and implementation_name != 'pypy'
# via psycopg
pyarrow==21.0.0 ; python_full_version < '3.10'
# via influxdb3-python
pyarrow==22.0.0 ; python_full_version >= '3.10'
pyarrow==22.0.0
# via influxdb3-python
pyasn1==0.6.1
# via pysnmp-lextudio
@ -203,21 +187,17 @@ six==1.17.0
# glances
# influxdb
# python-dateutil
sniffio==1.3.1 ; python_full_version >= '3.10'
sniffio==1.3.1
# via
# elastic-transport
# elasticsearch
sparklines==0.7.0
# via glances
starlette==0.49.3 ; python_full_version < '3.10'
# via fastapi
starlette==0.50.0 ; python_full_version >= '3.10'
starlette==0.50.0
# via fastapi
statsd==4.0.1
# via glances
termcolor==3.1.0 ; python_full_version < '3.10'
# via sparklines
termcolor==3.2.0 ; python_full_version >= '3.10'
termcolor==3.3.0
# via sparklines
tomli==2.0.2 ; python_full_version < '3.11'
# via podman
@ -247,7 +227,7 @@ urllib3==2.6.2
# influxdb3-python
# podman
# requests
uvicorn==0.38.0
uvicorn==0.40.0
# via glances
wifi==0.3.8
# via glances

View File

@ -892,6 +892,14 @@ password=password
# Most of the time, you should not overwrite this value
#hostname=mycomputer
[nats]
# Configuration for the --export nats option
# https://nats.io/
# Host is a separated list of NATS nodes
host=nats://localhost:4222
# Prefix for the subjects (default is 'glances')
prefix=glances
##############################################################################
# AMPS
# * enable: Enable (true) or disable (false) the AMP

View File

@ -1,12 +1,10 @@
# This file was autogenerated by uv via the following command:
# uv export --no-hashes --only-dev --output-file dev-requirements.txt
alabaster==0.7.16 ; python_full_version < '3.10'
# via sphinx
alabaster==1.0.0 ; python_full_version >= '3.10'
alabaster==1.0.0
# via sphinx
annotated-types==0.7.0
# via pydantic
anyio==4.12.0 ; python_full_version >= '3.10'
anyio==4.12.0
# via
# httpx
# mcp
@ -23,17 +21,13 @@ attrs==25.4.0
# trio
babel==2.17.0
# via sphinx
binaryornot==0.4.4 ; python_full_version < '3.10'
# via reuse
boltons==21.0.0
# via
# face
# glom
# semgrep
boolean-py==5.0
# via
# license-expression
# reuse
# via license-expression
bracex==2.6
# via wcmatch
certifi==2025.11.12
@ -42,16 +36,12 @@ certifi==2025.11.12
# httpx
# requests
# selenium
cffi==2.0.0 ; (python_full_version >= '3.10' and implementation_name == 'pypy' and platform_python_implementation != 'PyPy') or (python_full_version >= '3.10' and os_name != 'nt' and platform_python_implementation != 'PyPy') or (implementation_name != 'pypy' and os_name == 'nt')
cffi==2.0.0 ; (implementation_name != 'pypy' and os_name == 'nt') or platform_python_implementation != 'PyPy'
# via
# cryptography
# trio
cfgv==3.4.0 ; python_full_version < '3.10'
cfgv==3.5.0
# via pre-commit
cfgv==3.5.0 ; python_full_version >= '3.10'
# via pre-commit
chardet==5.2.0 ; python_full_version < '3.10'
# via binaryornot
charset-normalizer==3.4.4
# via
# python-debian
@ -72,22 +62,14 @@ colorama==0.4.6
# pytest
# semgrep
# sphinx
contourpy==1.3.0 ; python_full_version < '3.10'
# via matplotlib
contourpy==1.3.2 ; python_full_version == '3.10.*'
contourpy==1.3.2 ; python_full_version < '3.11'
# via matplotlib
contourpy==1.3.3 ; python_full_version >= '3.11'
# via matplotlib
cryptography==46.0.3 ; python_full_version >= '3.10'
cryptography==46.0.3
# via pyjwt
cycler==0.12.1
# via matplotlib
defusedxml==0.7.1 ; python_full_version < '3.10'
# via semgrep
deprecated==1.3.1 ; python_full_version < '3.10'
# via
# opentelemetry-api
# opentelemetry-exporter-otlp-proto-http
distlib==0.4.0
# via virtualenv
docutils==0.21.2
@ -104,13 +86,9 @@ exceptiongroup==1.2.2
# trio-websocket
face==24.0.0
# via glom
filelock==3.19.1 ; python_full_version < '3.10'
filelock==3.20.2
# via virtualenv
filelock==3.20.1 ; python_full_version >= '3.10'
# via virtualenv
fonttools==4.60.2 ; python_full_version < '3.10'
# via matplotlib
fonttools==4.61.1 ; python_full_version >= '3.10'
fonttools==4.61.1
# via matplotlib
glom==22.1.0
# via semgrep
@ -122,11 +100,11 @@ h11==0.16.0
# httpcore
# uvicorn
# wsproto
httpcore==1.0.9 ; python_full_version >= '3.10'
httpcore==1.0.9
# via httpx
httpx==0.28.1 ; python_full_version >= '3.10'
httpx==0.28.1
# via mcp
httpx-sse==0.4.3 ; python_full_version >= '3.10'
httpx-sse==0.4.3
# via mcp
identify==2.6.15
# via pre-commit
@ -138,17 +116,9 @@ idna==3.11
# trio
imagesize==1.4.1
# via sphinx
importlib-metadata==7.1.0 ; python_full_version < '3.10'
# via
# opentelemetry-api
# sphinx
importlib-metadata==8.7.0 ; python_full_version >= '3.10'
importlib-metadata==8.7.1
# via opentelemetry-api
importlib-resources==6.5.2 ; python_full_version < '3.10'
# via matplotlib
iniconfig==2.1.0 ; python_full_version < '3.10'
# via pytest
iniconfig==2.3.0 ; python_full_version >= '3.10'
iniconfig==2.3.0
# via pytest
jinja2==3.1.6
# via
@ -160,42 +130,33 @@ jsonschema==4.25.1
# semgrep
jsonschema-specifications==2025.9.1
# via jsonschema
kiwisolver==1.4.7 ; python_full_version < '3.10'
# via matplotlib
kiwisolver==1.4.9 ; python_full_version >= '3.10'
kiwisolver==1.4.9
# via matplotlib
license-expression==30.4.4
# via reuse
markdown-it-py==3.0.0 ; python_full_version < '3.10'
# via rich
markdown-it-py==4.0.0 ; python_full_version >= '3.10'
markdown-it-py==4.0.0
# via rich
markupsafe==3.0.3
# via jinja2
matplotlib==3.9.4 ; python_full_version < '3.10'
matplotlib==3.10.8 ; python_full_version >= '3.10'
mcp==1.23.3 ; python_full_version >= '3.10'
matplotlib==3.10.8
mcp==1.23.3
# via semgrep
mdurl==0.1.2
# via markdown-it-py
memory-profiler==0.61.0
nodeenv==1.9.1
nodeenv==1.10.0
# via
# pre-commit
# pyright
numpy==2.0.2 ; python_full_version < '3.10'
numpy==2.2.6 ; python_full_version < '3.11'
# via
# contourpy
# matplotlib
numpy==2.2.6 ; python_full_version == '3.10.*'
numpy==2.4.0 ; python_full_version >= '3.11'
# via
# contourpy
# matplotlib
numpy==2.3.5 ; python_full_version >= '3.11'
# via
# contourpy
# matplotlib
opentelemetry-api==1.25.0 ; python_full_version < '3.10'
opentelemetry-api==1.37.0
# via
# opentelemetry-exporter-otlp-proto-http
# opentelemetry-instrumentation
@ -203,58 +164,28 @@ opentelemetry-api==1.25.0 ; python_full_version < '3.10'
# opentelemetry-sdk
# opentelemetry-semantic-conventions
# semgrep
opentelemetry-api==1.37.0 ; python_full_version >= '3.10'
# via
# opentelemetry-exporter-otlp-proto-http
# opentelemetry-instrumentation
# opentelemetry-instrumentation-requests
# opentelemetry-sdk
# opentelemetry-semantic-conventions
# semgrep
opentelemetry-exporter-otlp-proto-common==1.25.0 ; python_full_version < '3.10'
opentelemetry-exporter-otlp-proto-common==1.37.0
# via opentelemetry-exporter-otlp-proto-http
opentelemetry-exporter-otlp-proto-common==1.37.0 ; python_full_version >= '3.10'
# via opentelemetry-exporter-otlp-proto-http
opentelemetry-exporter-otlp-proto-http==1.25.0 ; python_full_version < '3.10'
opentelemetry-exporter-otlp-proto-http==1.37.0
# via semgrep
opentelemetry-exporter-otlp-proto-http==1.37.0 ; python_full_version >= '3.10'
# via semgrep
opentelemetry-instrumentation==0.46b0 ; python_full_version < '3.10'
opentelemetry-instrumentation==0.58b0
# via opentelemetry-instrumentation-requests
opentelemetry-instrumentation==0.58b0 ; python_full_version >= '3.10'
# via opentelemetry-instrumentation-requests
opentelemetry-instrumentation-requests==0.46b0 ; python_full_version < '3.10'
opentelemetry-instrumentation-requests==0.58b0
# via semgrep
opentelemetry-instrumentation-requests==0.58b0 ; python_full_version >= '3.10'
# via semgrep
opentelemetry-proto==1.25.0 ; python_full_version < '3.10'
opentelemetry-proto==1.37.0
# via
# opentelemetry-exporter-otlp-proto-common
# opentelemetry-exporter-otlp-proto-http
opentelemetry-proto==1.37.0 ; python_full_version >= '3.10'
# via
# opentelemetry-exporter-otlp-proto-common
# opentelemetry-exporter-otlp-proto-http
opentelemetry-sdk==1.25.0 ; python_full_version < '3.10'
opentelemetry-sdk==1.37.0
# via
# opentelemetry-exporter-otlp-proto-http
# semgrep
opentelemetry-sdk==1.37.0 ; python_full_version >= '3.10'
# via
# opentelemetry-exporter-otlp-proto-http
# semgrep
opentelemetry-semantic-conventions==0.46b0 ; python_full_version < '3.10'
# via
# opentelemetry-instrumentation-requests
# opentelemetry-sdk
opentelemetry-semantic-conventions==0.58b0 ; python_full_version >= '3.10'
opentelemetry-semantic-conventions==0.58b0
# via
# opentelemetry-instrumentation
# opentelemetry-instrumentation-requests
# opentelemetry-sdk
opentelemetry-util-http==0.46b0 ; python_full_version < '3.10'
# via opentelemetry-instrumentation-requests
opentelemetry-util-http==0.58b0 ; python_full_version >= '3.10'
opentelemetry-util-http==0.58b0
# via opentelemetry-instrumentation-requests
outcome==1.3.0.post0
# via
@ -271,30 +202,21 @@ packaging==25.0
# webdriver-manager
peewee==3.18.3
# via semgrep
pillow==11.3.0 ; python_full_version < '3.10'
pillow==12.1.0
# via matplotlib
pillow==12.0.0 ; python_full_version >= '3.10'
# via matplotlib
platformdirs==4.4.0 ; python_full_version < '3.10'
# via virtualenv
platformdirs==4.5.1 ; python_full_version >= '3.10'
platformdirs==4.5.1
# via virtualenv
pluggy==1.6.0
# via pytest
pre-commit==4.3.0 ; python_full_version < '3.10'
pre-commit==4.5.1 ; python_full_version >= '3.10'
pre-commit==4.5.1
protobuf==6.33.2
# via
# googleapis-common-protos
# opentelemetry-proto
protobuf==6.33.2 ; python_full_version >= '3.10'
protobuf==4.25.8 ; python_full_version < '3.10'
# via
# googleapis-common-protos
# opentelemetry-proto
psutil==7.1.3
psutil==7.2.1
# via memory-profiler
py-spy==0.4.1
pycparser==2.23 ; (python_full_version >= '3.10' and implementation_name != 'PyPy' and os_name != 'nt' and platform_python_implementation != 'PyPy') or (python_full_version >= '3.10' and implementation_name == 'pypy' and os_name == 'nt' and platform_python_implementation != 'PyPy') or (implementation_name != 'PyPy' and implementation_name != 'pypy' and os_name == 'nt')
pycparser==2.23 ; (implementation_name != 'PyPy' and implementation_name != 'pypy' and os_name == 'nt') or (implementation_name != 'PyPy' and platform_python_implementation != 'PyPy')
# via cffi
pydantic==2.12.5
# via
@ -303,7 +225,7 @@ pydantic==2.12.5
# rstcheck-core
pydantic-core==2.41.5
# via pydantic
pydantic-settings==2.12.0 ; python_full_version >= '3.10'
pydantic-settings==2.12.0
# via mcp
pygments==2.19.2
# via
@ -311,15 +233,14 @@ pygments==2.19.2
# rich
# sphinx
pyinstrument==5.1.1
pyjwt==2.10.1 ; python_full_version >= '3.10'
pyjwt==2.10.1
# via mcp
pyparsing==3.2.5
pyparsing==3.3.1
# via matplotlib
pyright==1.1.407
pysocks==1.7.1
# via urllib3
pytest==8.4.2 ; python_full_version < '3.10'
pytest==9.0.2 ; python_full_version >= '3.10'
pytest==9.0.2
python-dateutil==2.9.0.post0
# via matplotlib
python-debian==1.0.1
@ -328,21 +249,17 @@ python-dotenv==1.2.1
# via
# pydantic-settings
# webdriver-manager
python-magic==0.4.27 ; python_full_version >= '3.10'
python-magic==0.4.27
# via reuse
python-multipart==0.0.21 ; python_full_version >= '3.10'
python-multipart==0.0.21
# via mcp
pywin32==311 ; python_full_version >= '3.10' and sys_platform == 'win32'
pywin32==311 ; sys_platform == 'win32'
# via
# mcp
# semgrep
pyyaml==6.0.3
# via pre-commit
referencing==0.36.2 ; python_full_version < '3.10'
# via
# jsonschema
# jsonschema-specifications
referencing==0.37.0 ; python_full_version >= '3.10'
referencing==0.37.0
# via
# jsonschema
# jsonschema-specifications
@ -353,8 +270,7 @@ requests==2.32.5
# sphinx
# webdriver-manager
requirements-parser==0.13.0
reuse==5.1.1 ; python_full_version < '3.10'
reuse==6.2.0 ; python_full_version >= '3.10'
reuse==6.2.0
rich==13.5.3
# via
# semgrep
@ -363,30 +279,21 @@ roman-numerals==4.1.0 ; python_full_version >= '3.11'
# via roman-numerals-py
roman-numerals-py==4.1.0 ; python_full_version >= '3.11'
# via sphinx
rpds-py==0.27.1 ; python_full_version < '3.10'
# via
# jsonschema
# referencing
rpds-py==0.30.0 ; python_full_version >= '3.10'
rpds-py==0.30.0
# via
# jsonschema
# referencing
rstcheck==6.2.5
rstcheck-core==1.2.2
# via rstcheck
ruamel-yaml==0.18.16
ruamel-yaml==0.19.1
# via semgrep
ruamel-yaml-clib==0.2.14
# via semgrep
ruamel-yaml-clib==0.2.14 ; python_full_version >= '3.10' or platform_python_implementation == 'CPython'
# via
# ruamel-yaml
# semgrep
ruff==0.14.10
selenium==4.36.0 ; python_full_version < '3.10'
selenium==4.39.0 ; python_full_version >= '3.10'
semgrep==1.136.0 ; python_full_version < '3.10'
semgrep==1.146.0 ; python_full_version >= '3.10'
selenium==4.39.0
semgrep==1.146.0
setuptools==80.9.0
# via opentelemetry-instrumentation
shellingham==1.5.4
# via typer
six==1.17.0
@ -397,11 +304,7 @@ snowballstemmer==3.0.1
# via sphinx
sortedcontainers==2.4.0
# via trio
sphinx==7.4.7 ; python_full_version < '3.10'
# via
# sphinx-rtd-theme
# sphinxcontrib-jquery
sphinx==8.1.3 ; python_full_version == '3.10.*'
sphinx==8.1.3 ; python_full_version < '3.11'
# via
# sphinx-rtd-theme
# sphinxcontrib-jquery
@ -424,9 +327,9 @@ sphinxcontrib-qthelp==2.0.0
# via sphinx
sphinxcontrib-serializinghtml==2.0.0
# via sphinx
sse-starlette==3.0.4 ; python_full_version >= '3.10'
sse-starlette==3.1.2
# via mcp
starlette==0.50.0 ; python_full_version >= '3.10'
starlette==0.50.0
# via
# mcp
# sse-starlette
@ -437,17 +340,13 @@ tomli==2.0.2
# sphinx
tomlkit==0.13.3
# via reuse
trio==0.31.0 ; python_full_version < '3.10'
# via
# selenium
# trio-websocket
trio==0.32.0 ; python_full_version >= '3.10'
trio==0.32.0
# via
# selenium
# trio-websocket
trio-websocket==0.12.2
# via selenium
typer==0.20.1
typer==0.21.0
# via rstcheck
typing-extensions==4.15.0
# via
@ -479,7 +378,7 @@ urllib3==2.6.2
# requests
# selenium
# semgrep
uvicorn==0.38.0 ; python_full_version >= '3.10' and sys_platform != 'emscripten'
uvicorn==0.40.0 ; sys_platform != 'emscripten'
# via mcp
virtualenv==20.35.4
# via pre-commit
@ -489,14 +388,8 @@ webdriver-manager==4.0.2
websocket-client==1.9.0
# via selenium
wrapt==1.17.3
# via
# deprecated
# opentelemetry-instrumentation
wsproto==1.2.0 ; python_full_version < '3.10'
# via trio-websocket
wsproto==1.3.2 ; python_full_version >= '3.10'
# via opentelemetry-instrumentation
wsproto==1.3.2
# via trio-websocket
zipp==3.23.0
# via
# importlib-metadata
# importlib-resources
# via importlib-metadata

View File

@ -1,3 +0,0 @@
FROM glances:local-alpine-minimal as glancesminimal
COPY glances.conf /glances/conf/glances.conf
CMD python -m glances -C /glances/conf/glances.conf $GLANCES_OPT

View File

@ -1,40 +0,0 @@
version: "3.9"
services:
reverse-proxy:
image: traefik
command: --api --docker
ports:
- "80:80"
- "8080:8080"
volumes:
- /var/run/docker.sock:/var/run/docker.sock
whoami:
image: emilevauge/whoami
labels:
- "traefik.frontend.rule=Host:whoami.docker.localhost"
monitoring:
image: nicolargo/glances:dev
restart: unless-stopped
pid: host
privileged: true
network_mode: "host"
volumes:
- "/var/run/docker.sock:/var/run/docker.sock:ro"
- "/run/user/1000/podman/podman.sock:/run/user/1000/podman/podman.sock:ro"
- "./glances.conf:/glances/conf/glances.conf"
environment:
- TZ=${TZ}
- "GLANCES_OPT=-C /glances/conf/glances.conf -w"
# Uncomment for GPU compatibility (Nvidia) inside the container
# deploy:
# resources:
# reservations:
# devices:
# - driver: nvidia
# count: 1
# capabilities: [gpu]
labels:
- "traefik.port=61208"
- "traefik.frontend.rule=Host:glances.docker.localhost"

View File

@ -1,23 +1,41 @@
version: '3.9'
services:
glances:
build:
context: ./
dockerfile: Dockerfile
# See all images tags here: https://hub.docker.com/r/nicolargo/glances/tags
image: nicolargo/glances:latest-full
restart: always
pid: "host"
privileged: true
network_mode: "host"
read_only: true
privileged: false
# Uncomment next line for SATA or NVME smartctl monitoring
# cap_add:
# Uncomment next line for SATA smartctl monitoring
# - SYS_RAWIO
# Uncomment next line for NVME smartctl monitoring
# - SYS_ADMIN
# devices:
# - "/dev/nvme0"
volumes:
- "/:/rootfs:ro"
- "/var/run/docker.sock:/var/run/docker.sock:ro"
- "/run/user/1000/podman/podman.sock:/run/user/1000/podman/podman.sock:ro"
- "./glances.conf:/glances/conf/glances.conf"
# # Uncomment for proper distro information in upper panel.
# Uncomment for proper distro information in upper panel.
# # Works only for distros that do have this file (most of distros do).
# - "/etc/os-release:/etc/os-release:ro"
tmpfs:
- /tmp
environment:
- TZ=${TZ}
- GLANCES_OPT=-C /glances/conf/glances.conf -w
# Please set to your local timezone (or use local ${TZ} environment variable if set on your host)
- TZ=Europe/Paris
- GLANCES_OPT=-C /glances/conf/glances.conf -w --enable-plugin smart
- PYTHONPYCACHEPREFIX=/tmp/py_caches
# # Uncomment for GPU compatibility (Nvidia) inside the container
# deploy:
# resources:
@ -26,10 +44,11 @@ services:
# - driver: nvidia
# count: 1
# capabilities: [gpu]
# # Uncomment to protect Glances WebUI by a login/password (add --password to GLANCES_OPT)
# secrets:
# - source: glances_password
# target: /root/.config/glances/<login>.pwd
# Uncomment to protect Glances WebUI by a login/password (add --password to GLANCES_OPT)
# secrets:
# - source: glances_password
# target: /root/.config/glances/<login>.pwd
# secrets:
# glances_password:

0
docker-compose/glances.conf Executable file → Normal file
View File

View File

@ -9,7 +9,7 @@
# WARNING: the Alpine image version and Python version should be set.
# Alpine 3.18 tag is a link to the latest 3.18.x version.
# Be aware that if you change the Alpine version, you may have to change the Python version.
ARG IMAGE_VERSION=3.22
ARG IMAGE_VERSION=3.23
ARG PYTHON_VERSION=3.12
##############################################################################
@ -61,9 +61,6 @@ RUN apk add --no-cache \
RUN python${PYTHON_VERSION} -m venv venv-build
RUN /venv-build/bin/python${PYTHON_VERSION} -m pip install --upgrade pip
RUN python${PYTHON_VERSION} -m venv venv-build
RUN /venv-build/bin/python${PYTHON_VERSION} -m pip install --upgrade pip
RUN python${PYTHON_VERSION} -m venv --without-pip venv
COPY pyproject.toml docker-requirements.txt all-requirements.txt ./
@ -105,17 +102,18 @@ COPY docker-bin.sh /usr/local/bin/glances
RUN chmod a+x /usr/local/bin/glances
ENV PATH="/venv/bin:$PATH"
# Copy binary and update PATH
COPY docker-bin.sh /usr/local/bin/glances
RUN chmod a+x /usr/local/bin/glances
ENV PATH="/venv/bin:$PATH"
# EXPOSE PORT (XMLRPC / WebUI)
EXPOSE 61209 61208
# Add glances user
# RUN addgroup -g 1000 glances && \
# adduser -D -u 1000 -G glances glances && \
# chown -R glances:glances /app
# Define default command.
WORKDIR /app
CMD ["/bin/sh", "-c", "/venv/bin/python3 -m glances ${GLANCES_OPT}"]
ENV PYTHON_VERSION=${PYTHON_VERSION}
CMD ["/bin/sh", "-c", "/venv/bin/python${PYTHON_VERSION} -m glances ${GLANCES_OPT}"]
################################################################################
# RELEASE: minimal
@ -123,6 +121,8 @@ FROM release AS minimal
COPY --from=buildminimal /venv /venv
# USER glances
################################################################################
# RELEASE: full
FROM release AS full
@ -131,6 +131,8 @@ RUN apk add --no-cache libzmq
COPY --from=buildfull /venv /venv
# USER glances
################################################################################
# RELEASE: dev - to be compatible with CI
FROM full AS dev
@ -140,5 +142,8 @@ FROM full AS dev
COPY ./docker-files/docker-logger.json /app
ENV LOG_CFG=/app/docker-logger.json
# USER glances
WORKDIR /app
CMD ["/bin/sh", "-c", "/venv/bin/python3 -m glances ${GLANCES_OPT}"]
ENV PYTHON_VERSION=${PYTHON_VERSION}
CMD ["/bin/sh", "-c", "/venv/bin/python${PYTHON_VERSION} -m glances ${GLANCES_OPT}"]

View File

@ -89,17 +89,21 @@ COPY docker-bin.sh /usr/local/bin/glances
RUN chmod a+x /usr/local/bin/glances
ENV PATH="/venv/bin:$PATH"
# Copy binary and update PATH
COPY docker-bin.sh /usr/local/bin/glances
RUN chmod a+x /usr/local/bin/glances
ENV PATH="/venv/bin:$PATH"
# EXPOSE PORT (XMLRPC / WebUI)
EXPOSE 61209 61208
# Add glances user
# NOTE: If used, the Glances Docker plugin do not work...
# UID and GUID 1000 are already configured for the ubuntu user
# Create anew one with UID and GUID 1001
# RUN groupadd -g 1001 glances && \
# useradd -u 1001 -g glances glances && \
# chown -R glances:glances /app
# Define default command.
WORKDIR /app
CMD ["/bin/sh", "-c", "/venv/bin/python3 -m glances ${GLANCES_OPT}"]
ENV PYTHON_VERSION=${PYTHON_VERSION}
CMD ["/bin/sh", "-c", "/venv/bin/python${PYTHON_VERSION} -m glances ${GLANCES_OPT}"]
################################################################################
# RELEASE: minimal
@ -108,6 +112,8 @@ ARG PYTHON_VERSION
COPY --from=buildMinimal /venv /venv
# USER glances
################################################################################
# RELEASE: full
FROM release AS full
@ -120,6 +126,8 @@ RUN apt-get update \
COPY --from=buildfull /venv /venv
# USER glances
################################################################################
# RELEASE: dev - to be compatible with CI
FROM full AS dev
@ -130,5 +138,8 @@ ARG PYTHON_VERSION
COPY ./docker-files/docker-logger.json /app
ENV LOG_CFG=/app/docker-logger.json
# USER glances
WORKDIR /app
CMD ["/bin/sh", "-c", "/venv/bin/python3 -m glances ${GLANCES_OPT}"]
ENV PYTHON_VERSION=${PYTHON_VERSION}
CMD ["/bin/sh", "-c", "/venv/bin/python${PYTHON_VERSION} -m glances ${GLANCES_OPT}"]

View File

@ -20,7 +20,7 @@ docker==7.1.0
# via glances
exceptiongroup==1.2.2 ; python_full_version < '3.11'
# via anyio
fastapi==0.125.0
fastapi==0.128.0
# via glances
h11==0.16.0
# via uvicorn
@ -36,7 +36,7 @@ packaging==25.0
# via glances
podman==5.6.0
# via glances
psutil==7.1.3
psutil==7.2.1
# via glances
pydantic==2.12.5
# via fastapi
@ -57,9 +57,7 @@ six==1.17.0
# via
# glances
# python-dateutil
starlette==0.49.3 ; python_full_version < '3.10'
# via fastapi
starlette==0.50.0 ; python_full_version >= '3.10'
starlette==0.50.0
# via fastapi
tomli==2.0.2 ; python_full_version < '3.11'
# via podman
@ -79,7 +77,7 @@ urllib3==2.6.2
# docker
# podman
# requests
uvicorn==0.38.0
uvicorn==0.40.0
# via glances
windows-curses==2.4.1 ; sys_platform == 'win32'
# via glances

File diff suppressed because one or more lines are too long

View File

@ -22,25 +22,25 @@ use the following code:
>>> gl = api.GlancesAPI()
>>> gl.cpu
{'cpucore': 16,
'ctx_switches': 9270037,
'ctx_switches': 392968698,
'guest': 0.0,
'idle': 92.9,
'interrupts': 6399251,
'iowait': 0.2,
'idle': 93.4,
'interrupts': 347279201,
'iowait': 0.5,
'irq': 0.0,
'nice': 0.0,
'soft_interrupts': 2465459,
'soft_interrupts': 146726416,
'steal': 0.0,
'syscalls': 0,
'system': 4.5,
'total': 6.6,
'user': 2.3}
'system': 4.4,
'total': 5.9,
'user': 1.7}
>>> gl.cpu.get("total")
6.6
5.9
>>> gl.mem.get("used")
9278827984
12044965912
>>> gl.auto_unit(gl.mem.get("used"))
8.64G
11.2G
If the stats return a list of items (like network interfaces or processes), you can
access them by their name:
@ -51,19 +51,19 @@ access them by their name:
['wlp0s20f3']
>>> gl.network["wlp0s20f3"]
{'alias': None,
'bytes_all': 2046,
'bytes_all_gauge': 1072158728,
'bytes_all_rate_per_sec': 11750.0,
'bytes_recv': 1424,
'bytes_recv_gauge': 1055691424,
'bytes_recv_rate_per_sec': 8178.0,
'bytes_sent': 622,
'bytes_sent_gauge': 16467304,
'bytes_sent_rate_per_sec': 3572.0,
'bytes_all': 1149,
'bytes_all_gauge': 14756012143,
'bytes_all_rate_per_sec': 7603.0,
'bytes_recv': 608,
'bytes_recv_gauge': 13741392863,
'bytes_recv_rate_per_sec': 4023.0,
'bytes_sent': 541,
'bytes_sent_gauge': 1014619280,
'bytes_sent_rate_per_sec': 3580.0,
'interface_name': 'wlp0s20f3',
'key': 'interface_name',
'speed': 0,
'time_since_update': 0.1741182804107666}
'time_since_update': 0.15111541748046875}
Init Glances Python API
-----------------------
@ -95,7 +95,32 @@ Alert stats:
>>> type(gl.alert)
<class 'glances.plugins.alert.AlertPlugin'>
>>> gl.alert
[]
[{'avg': 96.85105977159478,
'begin': 1767373692,
'count': 2,
'desc': '',
'end': -1,
'global_msg': 'High swap (paging) usage',
'max': 96.85105977159478,
'min': 96.85105977159478,
'sort': 'memory_percent',
'state': 'CRITICAL',
'sum': 193.70211954318955,
'top': ['code', 'firefox', 'code'],
'type': 'MEMSWAP'},
{'avg': 73.31673281888682,
'begin': 1767373692,
'count': 2,
'desc': '',
'end': -1,
'global_msg': 'High swap (paging) usage',
'max': 73.34283346687624,
'min': 73.2906321708974,
'sort': 'memory_percent',
'state': 'WARNING',
'sum': 146.63346563777364,
'top': [],
'type': 'MEM'}]
Alert fields description:
@ -131,12 +156,12 @@ Ports stats:
<class 'glances.plugins.ports.PortsPlugin'>
>>> gl.ports
[{'description': 'DefaultGateway',
'host': '192.168.1.1',
'host': '192.168.0.254',
'indice': 'port_0',
'port': 0,
'refresh': 30,
'rtt_warning': None,
'status': 0.005353,
'status': 0.002841,
'timeout': 3}]
Ports fields description:
@ -177,14 +202,14 @@ Diskio stats:
>>> gl.diskio.get("nvme0n1")
{'disk_name': 'nvme0n1',
'key': 'disk_name',
'read_bytes': 6307091968,
'read_count': 212136,
'read_bytes': 26400656896,
'read_count': 995162,
'read_latency': 0,
'read_time': 25497,
'write_bytes': 5472228352,
'write_count': 237246,
'read_time': 249396,
'write_bytes': 39424275456,
'write_count': 2633670,
'write_latency': 0,
'write_time': 197091}
'write_time': 2045785}
Diskio fields description:
@ -269,11 +294,11 @@ Processcount stats:
>>> type(gl.processcount)
<class 'glances.plugins.processcount.ProcesscountPlugin'>
>>> gl.processcount
{'pid_max': 0, 'running': 1, 'sleeping': 406, 'thread': 1964, 'total': 559}
{'pid_max': 0, 'running': 1, 'sleeping': 444, 'thread': 2451, 'total': 593}
>>> gl.processcount.keys()
['total', 'running', 'sleeping', 'thread', 'pid_max']
>>> gl.processcount.get("total")
559
593
Processcount fields description:
@ -346,7 +371,7 @@ Percpu stats:
'dpc': None,
'guest': 0.0,
'guest_nice': 0.0,
'idle': 28.0,
'idle': 27.0,
'interrupt': None,
'iowait': 0.0,
'irq': 0.0,
@ -354,8 +379,8 @@ Percpu stats:
'nice': 0.0,
'softirq': 0.0,
'steal': 0.0,
'system': 4.0,
'total': 72.0,
'system': 8.0,
'total': 73.0,
'user': 0.0}
Percpu fields description:
@ -404,10 +429,10 @@ System stats:
<class 'glances.plugins.system.SystemPlugin'>
>>> gl.system
{'hostname': 'nicolargo-xps15',
'hr_name': 'Ubuntu 24.04 64bit / Linux 6.14.0-35-generic',
'hr_name': 'Ubuntu 24.04 64bit / Linux 6.14.0-37-generic',
'linux_distro': 'Ubuntu 24.04',
'os_name': 'Linux',
'os_version': '6.14.0-35-generic',
'os_version': '6.14.0-37-generic',
'platform': '64bit'}
>>> gl.system.keys()
['os_name', 'hostname', 'platform', 'os_version', 'linux_distro', 'hr_name']
@ -446,18 +471,18 @@ Network stats:
>>> gl.network.get("wlp0s20f3")
{'alias': None,
'bytes_all': 0,
'bytes_all_gauge': 1072158728,
'bytes_all_gauge': 14756012143,
'bytes_all_rate_per_sec': 0.0,
'bytes_recv': 0,
'bytes_recv_gauge': 1055691424,
'bytes_recv_gauge': 13741392863,
'bytes_recv_rate_per_sec': 0.0,
'bytes_sent': 0,
'bytes_sent_gauge': 16467304,
'bytes_sent_gauge': 1014619280,
'bytes_sent_rate_per_sec': 0.0,
'interface_name': 'wlp0s20f3',
'key': 'interface_name',
'speed': 0,
'time_since_update': 0.0031774044036865234}
'time_since_update': 0.0019180774688720703}
Network fields description:
@ -498,23 +523,23 @@ Cpu stats:
<class 'glances.plugins.cpu.CpuPlugin'>
>>> gl.cpu
{'cpucore': 16,
'ctx_switches': 9270037,
'ctx_switches': 392968698,
'guest': 0.0,
'idle': 92.9,
'interrupts': 6399251,
'iowait': 0.2,
'idle': 93.4,
'interrupts': 347279201,
'iowait': 0.5,
'irq': 0.0,
'nice': 0.0,
'soft_interrupts': 2465459,
'soft_interrupts': 146726416,
'steal': 0.0,
'syscalls': 0,
'system': 4.5,
'total': 6.6,
'user': 2.3}
'system': 4.4,
'total': 5.9,
'user': 1.7}
>>> gl.cpu.keys()
['total', 'user', 'nice', 'system', 'idle', 'iowait', 'irq', 'steal', 'guest', 'ctx_switches', 'interrupts', 'soft_interrupts', 'syscalls', 'cpucore']
>>> gl.cpu.get("total")
6.6
5.9
Cpu fields description:
@ -586,7 +611,7 @@ Amps stats:
'refresh': 3.0,
'regex': True,
'result': None,
'timer': 0.1661975383758545}
'timer': 0.18659353256225586}
Amps fields description:
@ -617,38 +642,33 @@ Processlist stats:
>>> gl.processlist
Return a dict of dict with key=<pid>
>>> gl.processlist.keys()
[30532, 129, 7722, 6446, 8756, 8852, 6423, 8840, 9543, 7548, 10383, 5247, 10239, 6971, 7838, 7562, 7550, 10672, 7715, 8639, 6711, 10143, 29150, 8081, 8853, 9153, 8794, 3018, 6207, 9171, 9629, 3613, 9374, 8333, 6244, 6219, 8711, 30172, 28756, 29409, 5453, 29262, 5991, 5363, 9409, 9408, 7371, 9406, 9407, 9402, 5677, 8641, 8642, 3031, 2669, 29063, 5812, 6722, 5815, 30529, 6689, 5605, 6684, 8156, 6124, 5724, 5575, 5375, 5826, 5878, 6763, 3025, 6242, 5409, 5412, 5355, 4271, 3609, 5386, 5437, 2776, 5394, 5189, 749, 4946, 2700, 5087, 2641, 1, 2704, 2703, 5627, 5803, 3087, 4924, 4943, 4948, 3495, 2509, 2649, 5388, 5381, 3621, 5429, 3004, 5418, 2858, 5479, 6050, 3596, 2797, 4904, 4950, 5435, 2974, 3685, 5634, 3496, 5783, 2688, 5432, 5462, 808, 5389, 5678, 2684, 2510, 2864, 2690, 2645, 5175, 2508, 5009, 5661, 5574, 5738, 5336, 5230, 2636, 5653, 5584, 5643, 5186, 5383, 5157, 8342, 2685, 4961, 5427, 5690, 2655, 5013, 5073, 2635, 5428, 5367, 8469, 4944, 2746, 9198, 9154, 5161, 2710, 5243, 2634, 2507, 4931, 2640, 3778, 6250, 8656, 6540, 30525, 2979, 2981, 3626, 3634, 3234, 3650, 5020, 3633, 3629, 3501, 30528, 2980, 2769, 3016, 3017, 3235, 3500, 2, 3, 4, 5, 6, 7, 8, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 35, 36, 37, 38, 39, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 83, 84, 85, 86, 87, 89, 90, 91, 92, 93, 95, 96, 97, 98, 99, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 157, 164, 165, 166, 168, 169, 171, 176, 186, 188, 203, 212, 216, 218, 264, 270, 271, 272, 273, 274, 275, 276, 277, 278, 352, 355, 357, 358, 359, 360, 361, 362, 363, 364, 367, 369, 370, 447, 448, 450, 611, 616, 617, 618, 624, 651, 652, 653, 654, 657, 658, 659, 660, 661, 662, 683, 684, 738, 780, 781, 817, 1000, 1001, 1013, 1014, 1015, 1016, 1017, 1018, 1019, 1020, 1021, 1022, 1023, 1024, 1025, 1026, 1027, 1028, 1255, 1303, 1366, 1369, 1370, 1371, 1387, 1388, 1389, 1390, 1439, 1440, 1443, 1444, 1525, 1529, 1896, 1897, 1898, 1899, 1900, 1901, 1902, 1903, 1904, 1905, 1906, 1907, 1908, 1909, 1938, 1939, 1941, 1942, 1943, 1944, 1945, 1946, 1947, 1978, 1979, 1980, 1981, 1982, 1983, 1984, 1985, 1986, 1987, 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018, 2019, 2020, 2021, 2022, 2023, 2024, 2025, 2026, 2027, 2028, 2029, 2030, 2031, 2032, 2044, 2045, 2050, 2051, 2052, 2053, 2054, 2055, 2056, 2057, 2058, 2059, 2061, 2063, 2064, 2066, 2068, 2071, 2072, 2075, 2322, 2323, 2326, 3558, 3559, 3560, 3561, 3562, 3660, 3706, 3707, 3708, 3709, 3710, 3711, 3712, 3713, 3949, 3956, 4080, 4725, 4859, 4877, 7686, 13970, 14398, 14514, 15908, 16227, 16410, 16721, 28674, 28676, 28726, 29096, 30133]
>>> gl.processlist.get("30532")
{'cmdline': ['/home/nicolargo/dev/glances/.venv/bin/python3',
'-m',
'glances',
'-C',
'conf/glances.conf',
'--api-doc'],
'cpu_percent': 75.1,
'cpu_times': {'children_system': 0.03,
'children_user': 0.01,
[1, 2, 3, 4, 5, 6, 7, 8, 10, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 29, 30, 31, 32, 33, 35, 36, 37, 38, 39, 41, 42, 43, 44, 45, 47, 48, 49, 50, 51, 53, 54, 55, 56, 57, 59, 60, 61, 62, 63, 65, 66, 67, 68, 69, 71, 72, 73, 74, 75, 77, 78, 79, 80, 81, 83, 84, 85, 86, 87, 89, 90, 91, 92, 93, 95, 96, 97, 98, 99, 101, 102, 103, 104, 105, 107, 108, 109, 110, 111, 113, 114, 115, 116, 117, 118, 121, 122, 123, 124, 125, 126, 127, 128, 133, 135, 136, 137, 138, 139, 140, 142, 143, 144, 145, 146, 147, 148, 150, 154, 156, 157, 158, 166, 179, 188, 189, 218, 219, 239, 240, 258, 267, 268, 269, 270, 271, 273, 279, 280, 364, 367, 369, 370, 371, 372, 373, 450, 452, 613, 618, 619, 620, 627, 659, 660, 726, 757, 758, 787, 795, 970, 971, 986, 1037, 1040, 1042, 1043, 1045, 1046, 1047, 1048, 1049, 1050, 1051, 1052, 1056, 1058, 1059, 1064, 1065, 1218, 1219, 1223, 1275, 1277, 1278, 1279, 1320, 1327, 1534, 1537, 1965, 1966, 1967, 1968, 1969, 1970, 1971, 1972, 1973, 1974, 1975, 1976, 1977, 1978, 2007, 2008, 2009, 2010, 2011, 2013, 2014, 2016, 2017, 2018, 2019, 2020, 2021, 2023, 2052, 2053, 2054, 2055, 2056, 2057, 2058, 2059, 2060, 2061, 2062, 2063, 2064, 2065, 2066, 2067, 2068, 2069, 2070, 2071, 2072, 2073, 2074, 2075, 2078, 2079, 2080, 2081, 2082, 2083, 2084, 2085, 2086, 2087, 2088, 2089, 2090, 2091, 2092, 2093, 2094, 2095, 2096, 2097, 2098, 2099, 2100, 2101, 2102, 2103, 2104, 2105, 2117, 2122, 2123, 2124, 2125, 2126, 2127, 2128, 2129, 2130, 2133, 2134, 2135, 2136, 2137, 2138, 2139, 2140, 2141, 2142, 2143, 2144, 2145, 2149, 2603, 2604, 2605, 2606, 2613, 2615, 2744, 2745, 2746, 2750, 2751, 2755, 2762, 2774, 2781, 2788, 2791, 2796, 2799, 2802, 2813, 2820, 2823, 2887, 2904, 2905, 2916, 3031, 3038, 3081, 3181, 3182, 3186, 3191, 3192, 3240, 3382, 3383, 3670, 3671, 3695, 3698, 3807, 3817, 3818, 3822, 3827, 3828, 3846, 3853, 3874, 3901, 3902, 3903, 3904, 3905, 3906, 3907, 3908, 3982, 4194, 4596, 5146, 5166, 5172, 5179, 5189, 5190, 5193, 5195, 5197, 5207, 5263, 5267, 5274, 5318, 5333, 5421, 5425, 5441, 5453, 5457, 5492, 5505, 5509, 5593, 5612, 5620, 5621, 5634, 5657, 5658, 5661, 5664, 5665, 5667, 5669, 5672, 5675, 5678, 5680, 5685, 5687, 5693, 5695, 5700, 5708, 5726, 5734, 5829, 5832, 5833, 5844, 5861, 5871, 5914, 5921, 5931, 5941, 5954, 5957, 6017, 6063, 6087, 6093, 6094, 6123, 6154, 6206, 6244, 6475, 6505, 6552, 6559, 6562, 7227, 8412, 8526, 9631, 9649, 9661, 9731, 9734, 11010, 12121, 12123, 12124, 12138, 12192, 12239, 12278, 12321, 12335, 12336, 12417, 12686, 12726, 12735, 12929, 12931, 12932, 12933, 12934, 13048, 13115, 13536, 13665, 36430, 40117, 53755, 53764, 62488, 62637, 72064, 72065, 72120, 72139, 102070, 340569, 358046, 388396, 413445, 444052, 444061, 471623, 471714, 471892, 471899, 471919, 471929, 471954, 472557, 472566, 472570, 472785, 472854, 472861, 473314, 481055, 498113, 513901, 514243, 514681, 515455, 518033, 520070, 524431, 524432, 524447, 524457, 524551, 530020, 531982, 531983, 532003, 532019, 532126, 532187, 532625, 542169, 542928, 545701, 546233, 546254, 547205, 547220, 547714, 547732, 548091, 548102, 548622, 550414, 555282, 557645, 557646, 557648, 561234, 564559, 567573, 572276, 572387, 572901, 574078, 581119, 581221, 581222, 582989, 583097, 583966, 585509, 585867, 586640, 586660, 586676, 586686, 588116, 588144, 588161, 588690, 589569, 589794, 591548, 591550, 591551, 591712, 591853, 592272, 593020, 593126, 594465, 595041, 595152, 596658, 596663, 596890, 597033, 598027, 598303, 598538, 598539, 598540, 598541, 598598, 598756, 599183, 599214, 599225, 600160, 600310, 601882, 601885, 601886, 601889]
>>> gl.processlist.get("1")
{'cmdline': ['/sbin/init', 'splash'],
'cpu_percent': 0.0,
'cpu_times': {'children_system': 287.89,
'children_user': 5146.36,
'iowait': 0.0,
'system': 0.4,
'user': 0.4},
'gids': {'effective': 1000, 'real': 1000, 'saved': 1000},
'io_counters': [20688896, 86016, 8990720, 86016, 1],
'system': 7.96,
'user': 11.06},
'gids': {'effective': 0, 'real': 0, 'saved': 0},
'io_counters': [0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
'key': 'pid',
'memory_info': {'data': 100184064,
'memory_info': {'data': 7282688,
'dirty': 0,
'lib': 0,
'rss': 81117184,
'shared': 18477056,
'text': 31211520,
'vms': 415424512},
'memory_percent': 0.49392852502078194,
'name': 'python3',
'rss': 14622720,
'shared': 8175616,
'text': 45056,
'vms': 26632192},
'memory_percent': 0.0890389998301525,
'name': 'systemd',
'nice': 0,
'num_threads': 3,
'pid': 30532,
'status': 'R',
'time_since_update': 0.45221495628356934,
'username': 'nicolargo'}
'num_threads': 1,
'pid': 1,
'status': 'S',
'time_since_update': 0.39455604553222656,
'username': 'root'}
Processlist fields description:
@ -732,13 +752,13 @@ Load stats:
<class 'glances.plugins.load.LoadPlugin'>
>>> gl.load
{'cpucore': 16,
'min1': 1.77197265625,
'min15': 0.69287109375,
'min5': 1.29052734375}
'min1': 0.52685546875,
'min15': 0.517578125,
'min5': 0.5439453125}
>>> gl.load.keys()
['min1', 'min5', 'min15', 'cpucore']
>>> gl.load.get("min1")
1.77197265625
0.52685546875
Load fields description:
@ -770,14 +790,14 @@ Sensors stats:
>>> gl.sensors
Return a dict of dict with key=<label>
>>> gl.sensors.keys()
['Ambient', 'Ambient 3', 'Ambient 5', 'Ambient 6', 'CPU', 'Composite', 'Core 0', 'Core 4', 'Core 8', 'Core 12', 'Core 16', 'Core 20', 'Core 28', 'Core 29', 'Core 30', 'Core 31', 'HDD', 'Package id 0', 'SODIMM', 'Sensor 1', 'Sensor 2', 'dell_smm 0', 'dell_smm 1', 'dell_smm 2', 'dell_smm 3', 'dell_smm 4', 'dell_smm 5', 'dell_smm 6', 'dell_smm 7', 'dell_smm 8', 'dell_smm 9', 'i915 0', 'iwlwifi_1 0', 'spd5118 0', 'CPU Fan', 'Video Fan', 'BAT BAT0']
['Ambient', 'Ambient 3', 'Ambient 5', 'Ambient 6', 'CPU', 'Composite', 'Core 0', 'Core 4', 'Core 8', 'Core 12', 'Core 16', 'Core 20', 'Core 28', 'Core 29', 'Core 30', 'Core 31', 'HDD', 'Package id 0', 'SODIMM', 'Sensor 1', 'Sensor 2', 'dell_smm 0', 'dell_smm 1', 'dell_smm 2', 'dell_smm 3', 'dell_smm 4', 'dell_smm 5', 'dell_smm 6', 'dell_smm 7', 'dell_smm 8', 'dell_smm 9', 'i915 0', 'iwlwifi_1 0', 'CPU Fan', 'Video Fan', 'BAT BAT0']
>>> gl.sensors.get("Ambient")
{'critical': None,
'key': 'label',
'label': 'Ambient',
'type': 'temperature_core',
'unit': 'C',
'value': 33,
'value': 39,
'warning': 0}
Sensors fields description:
@ -815,7 +835,7 @@ Uptime stats:
>>> type(gl.uptime)
<class 'glances.plugins.uptime.UptimePlugin'>
>>> gl.uptime
'0:09:45'
'6 days, 1:42:29'
Uptime limits:
@ -834,11 +854,11 @@ Now stats:
>>> type(gl.now)
<class 'glances.plugins.now.NowPlugin'>
>>> gl.now
{'custom': '2025-11-21 18:02:29 CET', 'iso': '2025-11-21T18:02:29+01:00'}
{'custom': '2026-01-02 18:08:13 CET', 'iso': '2026-01-02T18:08:13+01:00'}
>>> gl.now.keys()
['iso', 'custom']
>>> gl.now.get("iso")
'2025-11-21T18:02:29+01:00'
'2026-01-02T18:08:13+01:00'
Now fields description:
@ -868,14 +888,14 @@ Fs stats:
>>> gl.fs.get("/")
{'alias': 'Root',
'device_name': '/dev/mapper/ubuntu--vg-ubuntu--lv',
'free': 705957326848,
'free': 582637228032,
'fs_type': 'ext4',
'key': 'mnt_point',
'mnt_point': '/',
'options': 'rw,relatime',
'percent': 25.9,
'percent': 38.8,
'size': 1003736440832,
'used': 246716608512}
'used': 370036707328}
Fs fields description:
@ -916,8 +936,8 @@ Wifi stats:
['wlp0s20f3']
>>> gl.wifi.get("wlp0s20f3")
{'key': 'ssid',
'quality_level': -61.0,
'quality_link': 49.0,
'quality_level': -63.0,
'quality_link': 47.0,
'ssid': 'wlp0s20f3'}
Wifi limits:
@ -941,7 +961,7 @@ Ip stats:
>>> type(gl.ip)
<class 'glances.plugins.ip.IpPlugin'>
>>> gl.ip
{'address': '192.168.1.26',
{'address': '192.168.0.26',
'mask': '255.255.255.0',
'mask_cidr': 24,
'public_address': '',
@ -949,7 +969,7 @@ Ip stats:
>>> gl.ip.keys()
['address', 'mask', 'mask_cidr', 'public_address', 'public_info_human']
>>> gl.ip.get("address")
'192.168.1.26'
'192.168.0.26'
Ip fields description:
@ -1002,7 +1022,7 @@ Psutilversion stats:
>>> type(gl.psutilversion)
<class 'glances.plugins.psutilversion.PsutilversionPlugin'>
>>> gl.psutilversion
'7.1.3'
'7.2.1'
Psutilversion limits:
@ -1049,20 +1069,20 @@ Mem stats:
>>> type(gl.mem)
<class 'glances.plugins.mem.MemPlugin'>
>>> gl.mem
{'active': 8012464128,
'available': 7144030768,
'buffers': 324308992,
'cached': 6972434864,
'free': 806096896,
'inactive': 5787877376,
'percent': 56.5,
'shared': 803672064,
'total': 16422858752,
'used': 9278827984}
{'active': 5357809664,
'available': 4377860072,
'buffers': 106696704,
'cached': 4016909160,
'free': 846315520,
'inactive': 7907250176,
'percent': 73.3,
'shared': 812941312,
'total': 16422825984,
'used': 12044965912}
>>> gl.mem.keys()
['total', 'available', 'percent', 'used', 'free', 'active', 'inactive', 'buffers', 'cached', 'shared']
>>> gl.mem.get("total")
16422858752
16422825984
Mem fields description:
@ -1128,19 +1148,19 @@ Quicklook stats:
>>> type(gl.quicklook)
<class 'glances.plugins.quicklook.QuicklookPlugin'>
>>> gl.quicklook
{'cpu': 6.6,
{'cpu': 5.9,
'cpu_hz': 4475000000.0,
'cpu_hz_current': 785612625.0000001,
'cpu_hz_current': 736325000.0000001,
'cpu_log_core': 16,
'cpu_name': '13th Gen Intel(R) Core(TM) i7-13620H',
'cpu_phys_core': 10,
'load': 4.3,
'mem': 56.5,
'load': 3.2,
'mem': 73.3,
'percpu': [{'cpu_number': 0,
'dpc': None,
'guest': 0.0,
'guest_nice': 0.0,
'idle': 28.0,
'idle': 27.0,
'interrupt': None,
'iowait': 0.0,
'irq': 0.0,
@ -1148,8 +1168,8 @@ Quicklook stats:
'nice': 0.0,
'softirq': 0.0,
'steal': 0.0,
'system': 4.0,
'total': 72.0,
'system': 8.0,
'total': 73.0,
'user': 0.0},
{'cpu_number': 1,
'dpc': None,
@ -1165,7 +1185,7 @@ Quicklook stats:
'steal': 0.0,
'system': 0.0,
'total': 66.0,
'user': 0.0},
'user': 1.0},
{'cpu_number': 2,
'dpc': None,
'guest': 0.0,
@ -1180,7 +1200,7 @@ Quicklook stats:
'steal': 0.0,
'system': 0.0,
'total': 66.0,
'user': 0.0},
'user': 1.0},
{'cpu_number': 3,
'dpc': None,
'guest': 0.0,
@ -1200,7 +1220,22 @@ Quicklook stats:
'dpc': None,
'guest': 0.0,
'guest_nice': 0.0,
'idle': 26.0,
'idle': 20.0,
'interrupt': None,
'iowait': 1.0,
'irq': 0.0,
'key': 'cpu_number',
'nice': 0.0,
'softirq': 0.0,
'steal': 0.0,
'system': 6.0,
'total': 80.0,
'user': 7.0},
{'cpu_number': 5,
'dpc': None,
'guest': 0.0,
'guest_nice': 0.0,
'idle': 25.0,
'interrupt': None,
'iowait': 0.0,
'irq': 0.0,
@ -1208,10 +1243,25 @@ Quicklook stats:
'nice': 0.0,
'softirq': 0.0,
'steal': 0.0,
'system': 3.0,
'total': 74.0,
'user': 7.0},
{'cpu_number': 5,
'system': 7.0,
'total': 75.0,
'user': 1.0},
{'cpu_number': 6,
'dpc': None,
'guest': 0.0,
'guest_nice': 0.0,
'idle': 34.0,
'interrupt': None,
'iowait': 0.0,
'irq': 0.0,
'key': 'cpu_number',
'nice': 0.0,
'softirq': 0.0,
'steal': 0.0,
'system': 0.0,
'total': 66.0,
'user': 1.0},
{'cpu_number': 7,
'dpc': None,
'guest': 0.0,
'guest_nice': 0.0,
@ -1226,41 +1276,11 @@ Quicklook stats:
'system': 0.0,
'total': 65.0,
'user': 0.0},
{'cpu_number': 6,
'dpc': None,
'guest': 0.0,
'guest_nice': 0.0,
'idle': 26.0,
'interrupt': None,
'iowait': 1.0,
'irq': 0.0,
'key': 'cpu_number',
'nice': 0.0,
'softirq': 0.0,
'steal': 0.0,
'system': 8.0,
'total': 74.0,
'user': 2.0},
{'cpu_number': 7,
'dpc': None,
'guest': 0.0,
'guest_nice': 0.0,
'idle': 28.0,
'interrupt': None,
'iowait': 1.0,
'irq': 0.0,
'key': 'cpu_number',
'nice': 0.0,
'softirq': 0.0,
'steal': 0.0,
'system': 6.0,
'total': 72.0,
'user': 0.0},
{'cpu_number': 8,
'dpc': None,
'guest': 0.0,
'guest_nice': 0.0,
'idle': 31.0,
'idle': 35.0,
'interrupt': None,
'iowait': 0.0,
'irq': 0.0,
@ -1268,9 +1288,9 @@ Quicklook stats:
'nice': 0.0,
'softirq': 0.0,
'steal': 0.0,
'system': 1.0,
'total': 69.0,
'user': 3.0},
'system': 0.0,
'total': 65.0,
'user': 0.0},
{'cpu_number': 9,
'dpc': None,
'guest': 0.0,
@ -1290,7 +1310,7 @@ Quicklook stats:
'dpc': None,
'guest': 0.0,
'guest_nice': 0.0,
'idle': 34.0,
'idle': 35.0,
'interrupt': None,
'iowait': 0.0,
'irq': 0.0,
@ -1299,8 +1319,8 @@ Quicklook stats:
'softirq': 0.0,
'steal': 0.0,
'system': 0.0,
'total': 66.0,
'user': 1.0},
'total': 65.0,
'user': 0.0},
{'cpu_number': 11,
'dpc': None,
'guest': 0.0,
@ -1317,21 +1337,6 @@ Quicklook stats:
'total': 65.0,
'user': 0.0},
{'cpu_number': 12,
'dpc': None,
'guest': 0.0,
'guest_nice': 0.0,
'idle': 35.0,
'interrupt': None,
'iowait': 0.0,
'irq': 0.0,
'key': 'cpu_number',
'nice': 0.0,
'softirq': 0.0,
'steal': 0.0,
'system': 0.0,
'total': 65.0,
'user': 0.0},
{'cpu_number': 13,
'dpc': None,
'guest': 0.0,
'guest_nice': 0.0,
@ -1345,8 +1350,8 @@ Quicklook stats:
'steal': 0.0,
'system': 0.0,
'total': 66.0,
'user': 0.0},
{'cpu_number': 14,
'user': 1.0},
{'cpu_number': 13,
'dpc': None,
'guest': 0.0,
'guest_nice': 0.0,
@ -1361,6 +1366,21 @@ Quicklook stats:
'system': 0.0,
'total': 65.0,
'user': 1.0},
{'cpu_number': 14,
'dpc': None,
'guest': 0.0,
'guest_nice': 0.0,
'idle': 34.0,
'interrupt': None,
'iowait': 0.0,
'irq': 0.0,
'key': 'cpu_number',
'nice': 0.0,
'softirq': 0.0,
'steal': 0.0,
'system': 0.0,
'total': 66.0,
'user': 1.0},
{'cpu_number': 15,
'dpc': None,
'guest': 0.0,
@ -1373,10 +1393,10 @@ Quicklook stats:
'nice': 0.0,
'softirq': 0.0,
'steal': 0.0,
'system': 1.0,
'system': 0.0,
'total': 66.0,
'user': 1.0}],
'swap': 0.0}
'user': 0.0}],
'swap': 96.9}
>>> gl.quicklook.keys()
['cpu_name', 'cpu_hz_current', 'cpu_hz', 'cpu', 'percpu', 'mem', 'swap', 'cpu_log_core', 'cpu_phys_core', 'load']
>>> gl.quicklook.get("cpu_name")
@ -1426,13 +1446,13 @@ Memswap stats:
>>> type(gl.memswap)
<class 'glances.plugins.memswap.MemswapPlugin'>
>>> gl.memswap
{'free': 4293918720,
'percent': 0.0,
'sin': 0,
'sout': 155648,
'time_since_update': 0.3645017147064209,
{'free': 135245824,
'percent': 96.9,
'sin': 1637122048,
'sout': 6747344896,
'time_since_update': 0.3689241409301758,
'total': 4294963200,
'used': 1044480}
'used': 4159717376}
>>> gl.memswap.keys()
['total', 'used', 'free', 'percent', 'sin', 'sout', 'time_since_update']
>>> gl.memswap.get("total")
@ -1467,10 +1487,10 @@ Use auto_unit() function to generate a human-readable string with the unit:
.. code-block:: python
>>> gl.mem.get("used")
9278827984
12044965912
>>> gl.auto_unit(gl.mem.get("used"))
8.64G
11.2G
Args:
@ -1496,7 +1516,7 @@ Use bar() function to generate a bar:
.. code-block:: python
>>> gl.bar(gl.mem["percent"])
■■■■■■■■■■□□□□□□□□
■■■■■■■■■■■■■□□□□□
Args:
@ -1526,7 +1546,7 @@ Use top_process() function to generate a list of top processes sorted by CPU or
.. code-block:: python
>>> gl.top_process()
[{'nice': 0, 'cpu_percent': 7.0, 'memory_percent': 3.672140600530691, 'pid': 7722, 'gids': {'real': 1000, 'effective': 1000, 'saved': 1000}, 'name': 'Isolated Web Co', 'cpu_times': {'user': 38.35, 'system': 2.43, 'children_user': 0.0, 'children_system': 0.0, 'iowait': 0.0}, 'num_threads': 30, 'status': 'S', 'io_counters': [205824, 0, 205824, 0, 1, 3581952, 0, 3581952, 0, 1, 5797888, 0, 5797888, 0, 1, 530432, 0, 530432, 0, 1, 2024448, 0, 2024448, 0, 1, 709632, 32768, 709632, 32768, 1, 11264, 0, 11264, 0, 1], 'memory_info': {'rss': 603070464, 'vms': 3160858624, 'shared': 111169536, 'text': 610304, 'lib': 0, 'data': 573337600, 'dirty': 0}, 'key': 'pid', 'time_since_update': 0.45221495628356934, 'cmdline': ['/snap/firefox/7177/usr/lib/firefox/firefox', '-contentproc', '-isForBrowser', '-prefsHandle', '0:46665', '-prefMapHandle', '1:278392', '-jsInitHandle', '2:224660', '-parentBuildID', '20251028100515', '-sandboxReporter', '3', '-chrootClient', '4', '-ipcHandle', '5', '-initialChannelId', '{63519720-ce7d-4af7-98af-78404f81d457}', '-parentPid', '6446', '-crashReporter', '6', '-crashHelper', '7', '-greomni', '/snap/firefox/7177/usr/lib/firefox/omni.ja', '-appomni', '/snap/firefox/7177/usr/lib/firefox/browser/omni.ja', '-appDir', '/snap/firefox/7177/usr/lib/firefox/browser', '11', 'tab'], 'username': 'nicolargo'}, {'nice': 0, 'cpu_percent': 4.7, 'memory_percent': 4.352427130952164, 'pid': 6446, 'gids': {'real': 1000, 'effective': 1000, 'saved': 1000}, 'name': 'firefox', 'cpu_times': {'user': 48.21, 'system': 12.77, 'children_user': 0.09, 'children_system': 0.28, 'iowait': 0.0}, 'num_threads': 148, 'status': 'S', 'io_counters': [499519488, 568045568, 499519488, 568045568, 1], 'memory_info': {'rss': 714792960, 'vms': 4454141952, 'shared': 265625600, 'text': 610304, 'lib': 0, 'data': 1026625536, 'dirty': 0}, 'key': 'pid', 'time_since_update': 0.45221495628356934, 'cmdline': ['/snap/firefox/7177/usr/lib/firefox/firefox'], 'username': 'nicolargo'}, {'nice': 0, 'cpu_percent': 2.3, 'memory_percent': 2.7413232665425777, 'pid': 8756, 'gids': {'real': 1000, 'effective': 1000, 'saved': 1000}, 'name': 'code', 'cpu_times': {'user': 90.96, 'system': 7.52, 'children_user': 0.0, 'children_system': 0.0, 'iowait': 0.0}, 'num_threads': 25, 'status': 'S', 'io_counters': [22750208, 126976, 22750208, 126976, 1, 28655616, 957018112, 28655616, 957018112, 1, 769914880, 121479168, 769914880, 121479168, 1, 50319360, 225280, 50319360, 225280, 1, 75313152, 0, 75313152, 0, 1, 68087808, 10162176, 68087808, 10162176, 1, 17530880, 4096, 17530880, 4096, 1, 35771392, 0, 35771392, 0, 1, 9899008, 0, 9899008, 0, 1, 2501632, 0, 2501632, 0, 1, 629760, 0, 629760, 0, 1, 4743168, 0, 4743168, 0, 1, 110592, 0, 110592, 0, 1, 3406848, 1003520, 3406848, 1003520, 1, 1456128, 0, 1456128, 0, 1, 1014784, 0, 1014784, 0, 1], 'memory_info': {'rss': 450203648, 'vms': 1517464080384, 'shared': 142995456, 'text': 148733952, 'lib': 0, 'data': 1207480320, 'dirty': 0}, 'key': 'pid', 'time_since_update': 0.45221495628356934, 'cmdline': ['/snap/code/211/usr/share/code/code', '--type=zygote', '--no-sandbox'], 'username': 'nicolargo'}]
[{'name': 'Isolated Web Co', 'io_counters': [7396352, 0, 7396352, 0, 1], 'pid': 472861, 'num_threads': 34, 'cpu_times': {'user': 618.31, 'system': 60.68, 'children_user': 0.0, 'children_system': 0.0, 'iowait': 0.0}, 'nice': 0, 'memory_percent': 3.11668922570738, 'status': 'S', 'memory_info': {'rss': 511848448, 'vms': 4369629184, 'shared': 74829824, 'text': 708608, 'lib': 0, 'data': 702328832, 'dirty': 0}, 'gids': {'real': 1000, 'effective': 1000, 'saved': 1000}, 'cpu_percent': 2.6, 'key': 'pid', 'time_since_update': 0.39455604553222656, 'cmdline': ['/snap/firefox/7559/usr/lib/firefox/firefox', '-contentproc', '-isForBrowser', '-prefsHandle', '0:45904', '-prefMapHandle', '1:280269', '-jsInitHandle', '2:223356', '-parentBuildID', '20251217233610', '-sandboxReporter', '3', '-chrootClient', '4', '-ipcHandle', '5', '-initialChannelId', '{b750b1b5-b51f-4cbd-8493-9c918fb23a11}', '-parentPid', '471623', '-crashReporter', '6', '-crashHelper', '7', '-greomni', '/snap/firefox/7559/usr/lib/firefox/omni.ja', '-appomni', '/snap/firefox/7559/usr/lib/firefox/browser/omni.ja', '-appDir', '/snap/firefox/7559/usr/lib/firefox/browser', '11', 'tab'], 'username': 'nicolargo'}, {'name': 'dockerd', 'io_counters': [0, 0, 0, 0, 0], 'pid': 3807, 'num_threads': 80, 'cpu_times': {'user': 103.99, 'system': 47.08, 'children_user': 3.67, 'children_system': 5.75, 'iowait': 0.0}, 'nice': 0, 'memory_percent': 0.335679523449306, 'status': 'S', 'memory_info': {'rss': 55128064, 'vms': 7906430976, 'shared': 23244800, 'text': 32280576, 'lib': 0, 'data': 795447296, 'dirty': 0}, 'gids': {'real': 0, 'effective': 0, 'saved': 0}, 'cpu_percent': 2.6, 'key': 'pid', 'time_since_update': 0.39455604553222656, 'cmdline': ['/usr/bin/dockerd', '-H', 'fd://', '--containerd=/run/containerd/containerd.sock'], 'username': 'root'}, {'name': 'iio-sensor-proxy', 'io_counters': [0, 0, 0, 0, 0], 'pid': 2755, 'num_threads': 4, 'cpu_times': {'user': 4.86, 'system': 7.32, 'children_user': 0.0, 'children_system': 0.0, 'iowait': 0.0}, 'nice': 0, 'memory_percent': 0.04753734836870327, 'status': 'S', 'memory_info': {'rss': 7806976, 'vms': 321671168, 'shared': 7127040, 'text': 36864, 'lib': 0, 'data': 35307520, 'dirty': 0}, 'gids': {'real': 0, 'effective': 0, 'saved': 0}, 'cpu_percent': 2.6, 'key': 'pid', 'time_since_update': 0.39455604553222656, 'cmdline': ['/usr/libexec/iio-sensor-proxy'], 'username': 'root'}]
Args:

File diff suppressed because it is too large Load Diff

View File

@ -36,6 +36,7 @@ This section describes the available exporters and how to configure them:
kafka
mqtt
mongodb
nats
opentsdb
prometheus
rabbitmq

68
docs/gw/nats.rst Normal file
View File

@ -0,0 +1,68 @@
.. _nats:
NATS
====
NATS is a message broker.
You can export statistics to a ``NATS`` server.
The connection should be defined in the Glances configuration file as
following:
.. code-block:: ini
[nats]
host=nats://localhost:4222
prefix=glances
and run Glances with:
.. code-block:: console
$ glances --export nats
Data model
-----------
Glances stats are published as JSON messagesto the following subjects:
<prefix>.<plugin>
Example:
CPU stats are published to glances.cpu
So a simple Python client will subscribe to this subject with:
import asyncio
import nats
async def main():
nc = nats.NATS()
await nc.connect(servers=["nats://localhost:4222"])
future = asyncio.Future()
async def cb(msg):
nonlocal future
future.set_result(msg)
await nc.subscribe("glances.cpu", cb=cb)
# Wait for message to come in
print("Waiting (max 30 seconds) for a message on 'glances' subject...")
msg = await asyncio.wait_for(future, 30)
print(msg.subject, msg.data)
if __name__ == '__main__':
asyncio.run(main())
To subscribe to all Glannces stats use wildcard:
await nc.subscribe("glances.*", cb=cb)

View File

@ -28,7 +28,7 @@ level margin: \\n[rst2man-indent\\n[rst2man-indent-level]]
.\" new: \\n[rst2man-indent\\n[rst2man-indent-level]]
.in \\n[rst2man-indent\\n[rst2man-indent-level]]u
..
.TH "GLANCES" "1" "Nov 21, 2025" "4.4.2_dev1" "Glances"
.TH "GLANCES" "1" "Jan 02, 2026" "4.4.2_dev1" "Glances"
.SH NAME
glances \- An eye on your system
.SH SYNOPSIS
@ -963,6 +963,6 @@ If you do not want to see the local Glances Web Server in the browser list pleas
.sp
Nicolas Hennion aka Nicolargo <\X'tty: link mailto:contact@nicolargo.com'\fI\%contact@nicolargo.com\fP\X'tty: link'>
.SH COPYRIGHT
2025, Nicolas Hennion
2026, Nicolas Hennion
.\" Generated by docutils manpage writer.
.

View File

@ -1,7 +1,7 @@
#
# This file is part of Glances.
#
# SPDX-FileCopyrightText: 2022 Nicolas Hennion <nicolas@nicolargo.com>
# SPDX-FileCopyrightText: 2026 Nicolas Hennion <nicolas@nicolargo.com>
#
# SPDX-License-Identifier: LGPL-3.0-only
#

View File

@ -0,0 +1,165 @@
#
# This file is part of Glances.
#
# SPDX-FileCopyrightText: 2026 Nicolas Hennion <nicolas@nicolargo.com>
#
# SPDX-License-Identifier: LGPL-3.0-only
#
"""
I am your son...
...abstract class for AsyncIO-based Glances exports.
"""
import asyncio
import threading
import time
from abc import abstractmethod
from glances.exports.export import GlancesExport
from glances.logger import logger
class GlancesExportAsyncio(GlancesExport):
"""Abstract class for AsyncIO-based export modules.
This class manages a persistent event loop in a background thread,
allowing child classes to use AsyncIO operations for exporting data.
Child classes must implement:
- async _async_init(): AsyncIO initialization (e.g., connection setup)
- async _async_exit(): AsyncIO cleanup (e.g., disconnection)
- async _async_export(name, columns, points): AsyncIO export operation
"""
def __init__(self, config=None, args=None):
"""Init the AsyncIO export interface."""
super().__init__(config=config, args=args)
# AsyncIO event loop management
self.loop = None
self._loop_ready = threading.Event()
self._loop_exception = None
self._shutdown = False
# Start the background event loop thread
self._loop_thread = threading.Thread(target=self._run_event_loop, daemon=True)
self._loop_thread.start()
# Wait for the loop to be ready
if not self._loop_ready.wait(timeout=10):
raise RuntimeError("AsyncIO event loop failed to start within timeout")
if self._loop_exception:
raise RuntimeError(f"AsyncIO event loop creation failed: {self._loop_exception}")
if self.loop is None:
raise RuntimeError("AsyncIO event loop is None after initialization")
# Call child class AsyncIO initialization
future = asyncio.run_coroutine_threadsafe(self._async_init(), self.loop)
try:
future.result(timeout=10)
logger.debug(f"{self.export_name} AsyncIO export initialized successfully")
except Exception as e:
logger.warning(f"{self.export_name} AsyncIO initialization failed: {e}. Will retry in background.")
def _run_event_loop(self):
"""Run event loop in background thread."""
try:
self.loop = asyncio.new_event_loop()
asyncio.set_event_loop(self.loop)
self._loop_ready.set()
self.loop.run_forever()
except Exception as e:
self._loop_exception = e
self._loop_ready.set()
logger.error(f"{self.export_name} AsyncIO event loop thread error: {e}")
finally:
# Clean up pending tasks
pending = asyncio.all_tasks(self.loop)
for task in pending:
task.cancel()
if pending:
self.loop.run_until_complete(asyncio.gather(*pending, return_exceptions=True))
self.loop.close()
@abstractmethod
async def _async_init(self):
"""AsyncIO initialization method.
Child classes should implement this method to perform AsyncIO-based
initialization such as connecting to servers, setting up clients, etc.
This method is called once during __init__ after the event loop is ready.
"""
pass
@abstractmethod
async def _async_exit(self):
"""AsyncIO cleanup method.
Child classes should implement this method to perform AsyncIO-based
cleanup such as disconnecting from servers, closing clients, etc.
This method is called during exit() before stopping the event loop.
"""
pass
@abstractmethod
async def _async_export(self, name, columns, points):
"""AsyncIO export method.
Child classes must implement this method to perform the actual
export operation using AsyncIO.
:param name: plugin name
:param columns: list of column names
:param points: list of values corresponding to columns
"""
pass
def exit(self):
"""Close the AsyncIO export module."""
super().exit()
self._shutdown = True
logger.info(f"{self.export_name} AsyncIO export shutting down")
# Call child class cleanup
if self.loop:
future = asyncio.run_coroutine_threadsafe(self._async_exit(), self.loop)
try:
future.result(timeout=5)
except Exception as e:
logger.error(f"{self.export_name} Error in AsyncIO cleanup: {e}")
# Stop the event loop
if self.loop:
self.loop.call_soon_threadsafe(self.loop.stop)
time.sleep(0.5)
logger.debug(f"{self.export_name} AsyncIO export shutdown complete")
def export(self, name, columns, points):
"""Export data using AsyncIO.
This method bridges the synchronous export() interface with
the AsyncIO _async_export() implementation.
"""
if self._shutdown:
logger.debug(f"{self.export_name} Export called during shutdown, skipping")
return
if not self.loop or not self.loop.is_running():
logger.error(f"{self.export_name} AsyncIO event loop is not running")
return
# Submit the export operation to the background event loop
try:
future = asyncio.run_coroutine_threadsafe(self._async_export(name, columns, points), self.loop)
# Don't block forever - use a short timeout
future.result(timeout=1)
except asyncio.TimeoutError:
logger.warning(f"{self.export_name} AsyncIO export timeout for {name}")
except Exception as e:
logger.error(f"{self.export_name} AsyncIO export error for {name}: {e}", exc_info=True)

0
glances/exports/glances_mqtt/__init__.py Executable file → Normal file
View File

View File

@ -0,0 +1,134 @@
#
# This file is part of Glances.
#
# SPDX-FileCopyrightText: 2026 Nicolas Hennion <nicolas@nicolargo.com>
#
# SPDX-License-Identifier: LGPL-3.0-only
#
"""NATS interface class."""
from nats.aio.client import Client as NATS
from nats.errors import ConnectionClosedError
from nats.errors import TimeoutError as NatsTimeoutError
from glances.exports.export_asyncio import GlancesExportAsyncio
from glances.globals import json_dumps
from glances.logger import logger
class Export(GlancesExportAsyncio):
"""This class manages the NATS export module."""
def __init__(self, config=None, args=None):
"""Init the NATS export IF."""
# Load the NATS configuration file before calling super().__init__
# because super().__init__ will call _async_init() which needs config
self.config = config
self.args = args
self.export_name = self.__class__.__module__
export_enable = self.load_conf(
'nats',
mandatories=['host'],
options=['prefix'],
)
if not export_enable:
exit('Missing NATS config')
self.prefix = self.prefix or 'glances'
# Host is a comma-separated list of NATS servers
self.hosts = self.host
# NATS-specific attributes
self.client = None
self._connected = False
self._publish_count = 0
# Call parent __init__ which will start event loop and call _async_init()
super().__init__(config=config, args=args)
# Restore export_enable after super().__init__() resets it to False
self.export_enable = export_enable
async def _async_init(self):
"""Connect to NATS with error handling."""
try:
if self.client:
try:
await self.client.close()
except Exception as e:
logger.debug(f"NATS Error closing existing client: {e}")
self.client = NATS()
logger.debug(f"NATS Connecting to servers: {self.hosts}")
# Configure with reconnection callbacks
await self.client.connect(
servers=[s.strip() for s in self.hosts.split(',')],
reconnect_time_wait=2,
max_reconnect_attempts=60,
error_cb=self._error_callback,
disconnected_cb=self._disconnected_callback,
reconnected_cb=self._reconnected_callback,
)
self._connected = True
logger.info(f"NATS Successfully connected to servers: {self.hosts}")
except Exception as e:
self._connected = False
logger.error(f"NATS connection error: {e}")
raise
async def _error_callback(self, e):
"""Called when NATS client encounters an error."""
logger.error(f"NATS error callback: {e}")
async def _disconnected_callback(self):
"""Called when disconnected from NATS."""
self._connected = False
logger.debug("NATS disconnected callback")
async def _reconnected_callback(self):
"""Called when reconnected to NATS."""
self._connected = True
logger.debug("NATS reconnected callback")
async def _async_exit(self):
"""Disconnect from NATS."""
try:
if self.client and self._connected:
await self.client.drain()
await self.client.close()
self._connected = False
logger.debug(f"NATS disconnected cleanly. Total messages published: {self._publish_count}")
except Exception as e:
logger.error(f"NATS Error in disconnect: {e}")
async def _async_export(self, name, columns, points):
"""Write the points to NATS using AsyncIO."""
if not self._connected:
logger.warning("NATS not connected, skipping export")
return
subject_name = f"{self.prefix}.{name}"
subject_data = dict(zip(columns, points))
# Publish data to NATS
try:
if not self._connected:
raise ConnectionClosedError("NATS Not connected to server")
await self.client.publish(subject_name, json_dumps(subject_data))
await self.client.flush(timeout=2.0)
self._publish_count += 1
except (ConnectionClosedError, NatsTimeoutError) as e:
self._connected = False
logger.error(f"NATS publish failed for {subject_name}: {e}")
raise
except Exception as e:
logger.error(f"NATS Unexpected error publishing {subject_name}: {e}", exc_info=True)
raise
# End of glances/exports/glances_nats/__init__.py

View File

@ -4,6 +4,7 @@
"requires": true,
"packages": {
"": {
"name": "static",
"dependencies": {
"bootstrap": "^5.3.8",
"favico.js": "^0.3.10",
@ -5423,9 +5424,9 @@
}
},
"node_modules/qs": {
"version": "6.14.0",
"resolved": "https://registry.npmjs.org/qs/-/qs-6.14.0.tgz",
"integrity": "sha512-YWWTjgABSKcvs/nWBi9PycY/JiPJqOD4JA6o9Sej2AtvSGarXxKC3OQSk4pAarbdQlKAh5D4FCQkJNkW+GAn3w==",
"version": "6.14.1",
"resolved": "https://registry.npmjs.org/qs/-/qs-6.14.1.tgz",
"integrity": "sha512-4EK3+xJl8Ts67nLYNwqw/dsFVnCf+qR7RgXSK9jEEm9unao3njwMDdmsdvoKBKHzxd7tCYz5e5M+SnMjdtXGQQ==",
"dev": true,
"license": "BSD-3-Clause",
"dependencies": {

View File

@ -966,3 +966,6 @@ class ProcesslistPlugin(GlancesPluginModel):
# By default return 5 (corresponding to 99999 PID number)
return 5
# End of file

View File

@ -478,10 +478,7 @@ class GlancesProcesses:
# Only get the info key
# PsUtil 6+ no longer check PID reused #2755 so use is_running in the loop
# Note: not sure it is realy needed but CPU consumption look the same with or without it
processlist = [p.info for p in processlist if p.is_running()]
# Sort the processes list by the current sort_key
return sort_stats(processlist, sorted_by=self.sort_key, reverse=True)
return [p.info for p in processlist if p.is_running()]
def get_sorted_attrs(self):
defaults = ['cpu_percent', 'cpu_times', 'memory_percent', 'name', 'status', 'num_threads']
@ -599,6 +596,8 @@ class GlancesProcesses:
# Remove attributes set by the user in the config file (see #1524)
sorted_attrs = [i for i in sorted_attrs if i not in self.disable_stats]
# Buid and sort the process list
processlist = self.build_process_list(sorted_attrs)
# Update the processcount
@ -757,6 +756,7 @@ def _sort_io_counters(process, sorted_by='io_counters', sorted_by_secondary='mem
:return: Sum of io_r + io_w
"""
logger.info(f'*** Sort by cpu_times called {type(process[sorted_by])} {process[sorted_by]}')
return process[sorted_by][0] - process[sorted_by][2] + process[sorted_by][1] - process[sorted_by][3]
@ -768,7 +768,7 @@ def _sort_cpu_times(process, sorted_by='cpu_times', sorted_by_secondary='memory_
see (https://github.com/giampaolo/psutil/issues/1339)
The following implementation takes user and system time into account
"""
return process[sorted_by][0] + process[sorted_by][1]
return process[sorted_by]['user'] + process[sorted_by]['system']
def _sort_lambda(sorted_by='cpu_percent', sorted_by_secondary='memory_percent'):
@ -793,18 +793,22 @@ def sort_stats(stats, sorted_by='cpu_percent', sorted_by_secondary='memory_perce
# Specific sort
try:
stats = sorted(stats, key=sort_lambda, reverse=reverse)
except Exception:
except Exception as e:
# If an error is detected, fallback to cpu_percent
logger.debug(f'Error while sorting by {sorted_by}, fallback to cpu_percent ({e})')
stats = sorted(stats, key=sort_by_these_keys('cpu_percent', sorted_by_secondary), reverse=reverse)
else:
# Standard sort
try:
stats = sorted(stats, key=sort_by_these_keys(sorted_by, sorted_by_secondary), reverse=reverse)
except (KeyError, TypeError):
except (KeyError, TypeError) as e:
# Fallback to name
logger.debug(f'Error while sorting by {sorted_by}, fallback to name ({e})')
stats.sort(key=lambda process: process['name'] if process['name'] is not None else '~', reverse=False)
return stats
glances_processes = GlancesProcesses()
# End of file processes.py

View File

@ -83,6 +83,7 @@ export = [
"influxdb>=1.0.0",
"influxdb3-python",
"kafka-python",
"nats-py",
"paho-mqtt",
"pika",
"potsdb",

View File

@ -8,7 +8,7 @@ markupsafe==3.0.3
# via jinja2
packaging==25.0
# via glances
psutil==7.1.3
psutil==7.2.1
# via glances
shtab==1.8.0 ; sys_platform != 'win32'
# via glances

View File

@ -0,0 +1,18 @@
import asyncio
import nats
async def main():
nc = nats.NATS()
await nc.connect(servers=["nats://localhost:4222"])
await nc.publish("glances.test", b'A test')
await nc.flush()
if __name__ == '__main__':
asyncio.run(main())
# To run this test script, make sure you have a NATS server running locally.

View File

@ -0,0 +1,32 @@
import asyncio
import nats
async def main():
duration = 30
subject = "glances.*"
nc = nats.NATS()
await nc.connect(servers=["nats://localhost:4222"])
future = asyncio.Future()
async def cb(msg):
subject = msg.subject
reply = msg.reply
data = msg.data.decode()
print(f"Received a message on '{subject} {reply}': {data}")
print(f"Receiving message from {subject} during {duration} seconds...")
await nc.subscribe(subject, cb=cb)
await asyncio.wait_for(future, duration)
await nc.close()
if __name__ == '__main__':
asyncio.run(main())
# To run this test script, make sure you have a NATS server running locally.

34
tests/test_export_nats.sh Executable file
View File

@ -0,0 +1,34 @@
#!/bin/bash
# Pre-requisites:
# - docker
# - jq
# Exit on error
set -e
echo "Stop previous nats container..."
docker stop nats-for-glances || true
docker rm nats-for-glances || true
echo "Starting nats container..."
docker run -d \
--name nats-for-glances \
-p 4222:4222 \
-p 8222:8222 \
-p 6222:6222 \
nats:latest
# Wait for InfluxDB to be ready (5 seconds)
echo "Waiting for nats to start (~ 5 seconds)..."
sleep 5
# Run glances with export to nats, stopping after 10 writes
# This will run synchronously now since we're using --stop-after
echo "Glances to export system stats to nats (duration: ~ 20 seconds)"
.venv/bin/python -m glances --config ./conf/glances.conf --export nats --stop-after 10 --quiet
# Stop and remove the nats container
echo "Stopping and removing nats container..."
docker stop nats-for-glances && docker rm nats-for-glances
echo "Script completed successfully!"

View File

@ -20,7 +20,7 @@ curl http://localhost:9091/metrics
# Kill the glances process if it's still running
if ps -p $GLANCES_PID > /dev/null; then
kill $GLANCES_PID
kill $GLANCES_PID
fi
echo "Script completed successfully!"

View File

@ -38,6 +38,6 @@ docker exec timescaledb-for-glances psql -d "postgres://postgres:password@localh
# Stop and remove the TimescaleDB container
echo "Stopping and removing TimescaleDB container..."
# docker stop timescaledb-for-glances && docker rm timescaledb-for-glances
docker stop timescaledb-for-glances && docker rm timescaledb-for-glances
echo "Script completed successfully!"