Merge v2.0 release branch
3
.gitignore
vendored
@ -40,3 +40,6 @@ local.properties
|
||||
|
||||
# Lang
|
||||
glances.pot
|
||||
|
||||
# Sphinx
|
||||
_build
|
||||
|
@ -2,7 +2,6 @@ language: python
|
||||
python:
|
||||
- "2.6"
|
||||
- "2.7"
|
||||
- "3.2"
|
||||
- "3.3"
|
||||
- "3.4"
|
||||
install:
|
||||
|
@ -3,10 +3,11 @@ include COPYING
|
||||
include NEWS
|
||||
include README.rst
|
||||
include conf/glances.conf
|
||||
include glances/data/css/*.css
|
||||
include glances/data/html/*.html
|
||||
include glances/data/img/*.png
|
||||
include glances/outputs/bottle/*.tpl
|
||||
include glances/outputs/static/css/*.css
|
||||
include glances/outputs/static/js/*.js
|
||||
include man/glances.1
|
||||
recursive-include docs images/*.png glances-doc.html
|
||||
recursive-include glances *.py
|
||||
recursive-include i18n *.mo
|
||||
prune docs/_build
|
||||
|
92
NEWS
@ -1,3 +1,4 @@
|
||||
<<<<<<< HEAD
|
||||
Version 1.7.7
|
||||
=============
|
||||
|
||||
@ -5,20 +6,105 @@ Version 1.7.7
|
||||
* Adapt to PSUtil 2.1.1
|
||||
* Compatibility with Python 3.4
|
||||
* Improve German update
|
||||
=======
|
||||
==============================================================================
|
||||
Glances Version 2.x
|
||||
==============================================================================
|
||||
|
||||
Version 2.0
|
||||
===========
|
||||
|
||||
Glances v2.0 is not a simple upgrade of the version 1.x but a complete code refactoring.
|
||||
Based on a plugins system, it aims at providing an easy way to add news features.
|
||||
- Core defines the basics and commons functions.
|
||||
- all stats are grabbed through plugins (see the glances/plugins source folder).
|
||||
- also outputs methods (Curse, Web mode, CSV) are managed as plugins.
|
||||
|
||||
The Curse interface is almost the same than the version 1.7. Some improvements have been made:
|
||||
- space optimisation for the CPU, LOAD and MEM stats (justified alignment)
|
||||
- CPU:
|
||||
. CPU stats are displayed as soon as Glances is started
|
||||
. steal CPU alerts are no more logged
|
||||
- LOAD:
|
||||
. 5 min LOAD alerts are no more logged
|
||||
- File System:
|
||||
. Display the device name (if space is available)
|
||||
- Sensors:
|
||||
. Sensors and HDD temperature are displayed in the same block
|
||||
- Process list:
|
||||
. Refactor columns: CPU%, MEM%, VIRT, RES, PID, USER, NICE, STATUS, TIME, IO, Command/name
|
||||
. The running processes status is highlighted
|
||||
. The process name is highlighted in the command line
|
||||
|
||||
Glances 2.0 brings a brand new Web Interface. You can run Glances in Web server mode and
|
||||
consult the stats directly from a standard Web Browser.
|
||||
|
||||
The client mode can now fallback to a simple SNMP mode if Glances server is not found on the remote machine.
|
||||
|
||||
Complete release notes:
|
||||
* Cut ifName and DiskName if they are too long in the curses interface (by Nicolargo)
|
||||
* Windows CLI is OK but early experimental (by Nicolargo)
|
||||
* Add bitrate limits to the networks interfaces (by Nicolargo)
|
||||
* Batteries % stats are now in the sensors list (by Nicolargo)
|
||||
* Refactor the client/server password security: using SHA256 (by Nicolargo,
|
||||
based on Alessio Sergi's example script)
|
||||
* Refactor the CSV output (by Nicolargo)
|
||||
* Glances client fallback to SNMP server if Glances one not found (by Nicolargo)
|
||||
* Process list: Highlight running/basename processes (by Alessio Sergi)
|
||||
* New Web server mode thk to the Bottle library (by Nicolargo)
|
||||
* Responsive design for Bottle interface (by Nicolargo)
|
||||
* Remove HTML output (by Nicolargo)
|
||||
* Enable/disable for optional plugins through the command line (by Nicolargo)
|
||||
* Refactor the API (by Nicolargo)
|
||||
* Load-5 alert are no longer logged (by Nicolargo)
|
||||
* Rename In/Out by Read/Write for DiskIO according to #339 (by Nicolargo)
|
||||
* Migrate from pysensors to py3sensors (by Alessio Sergi)
|
||||
* Migration to PsUtil 2.x (by Nicolargo)
|
||||
* New plugins system (by Nicolargo)
|
||||
* Python 2.x and 3.x compatibility (by Alessio Sergi)
|
||||
* Code quality improvements (by Alessio Sergi)
|
||||
* Refactor unitaries tests (by Nicolargo)
|
||||
* Development now follow the git flow workflow (by Nicolargo)
|
||||
|
||||
|
||||
==============================================================================
|
||||
Glances Version 1.x
|
||||
==============================================================================
|
||||
|
||||
Version 1.7.7
|
||||
=============
|
||||
|
||||
* Fix CVS export [issue #348]
|
||||
* Adapt to PSUtil 2.1.1
|
||||
* Compatibility with Python 3.4
|
||||
* Improve German update
|
||||
>>>>>>> release/v2.0
|
||||
|
||||
Version 1.7.6
|
||||
=============
|
||||
|
||||
<<<<<<< HEAD
|
||||
* Adapt to psutil 2.0.0 API
|
||||
* Fixed psutil 0.5.x support on Windows
|
||||
* Fix help screen in 80x24 terminal size
|
||||
* Implement toggle of process list display ('z' key)
|
||||
=======
|
||||
* Adapt to psutil 2.0.0 API
|
||||
* Fixed psutil 0.5.x support on Windows
|
||||
* Fix help screen in 80x24 terminal size
|
||||
* Implement toggle of process list display ('z' key)
|
||||
>>>>>>> release/v2.0
|
||||
|
||||
Version 1.7.5
|
||||
=============
|
||||
|
||||
<<<<<<< HEAD
|
||||
* Force the Pypi installer to use the PsUtil branch 1.x (#333)
|
||||
|
||||
=======
|
||||
* Force the Pypi installer to use the PsUtil branch 1.x (#333)
|
||||
|
||||
>>>>>>> release/v2.0
|
||||
Version 1.7.4
|
||||
=============
|
||||
|
||||
@ -29,9 +115,9 @@ Version 1.7.4
|
||||
* You can hide network interface from the Network view using the conf file
|
||||
* Optimisation of CPU consumption (around ~10%)
|
||||
* Correct issue #314: Client/server mode always asks for password
|
||||
* Correct issue #315: Defining password in client/server mode doesn't work as intended
|
||||
* Correct issue #316: Crash in client server mode
|
||||
* Correct issue #318: Argument parser, try-except blocks never get triggered
|
||||
* Correct issue #315: Defining password in client/server mode doesn't work as intended
|
||||
* Correct issue #316: Crash in client server mode
|
||||
* Correct issue #318: Argument parser, try-except blocks never get triggered
|
||||
|
||||
Version 1.7.3
|
||||
=============
|
||||
|
80
README.rst
@ -18,7 +18,8 @@ Glances - An eye on your system
|
||||
.. image:: https://raw.github.com/nicolargo/glances/master/docs/images/glances-white-256.png
|
||||
:width: 128
|
||||
|
||||
**Glances** is a cross-platform curses-based monitoring tool written in Python.
|
||||
**Glances** is a cross-platform curses-based system monitoring tool
|
||||
written in Python.
|
||||
|
||||
It uses the `psutil`_ library to get information from your system.
|
||||
|
||||
@ -27,16 +28,29 @@ It uses the `psutil`_ library to get information from your system.
|
||||
Requirements
|
||||
============
|
||||
|
||||
<<<<<<< HEAD
|
||||
- ``python >= 2.6`` (tested with version 2.6, 2.7, 3.2, 3.3, 3.4)
|
||||
- ``psutil >= 0.5.1`` (recommended version >= 2.0.0)
|
||||
=======
|
||||
- ``python >= 2.6`` (tested with version 2.6, 2.7, 3.3, 3.4)
|
||||
- ``psutil >= 2.0.0``
|
||||
>>>>>>> release/v2.0
|
||||
- ``setuptools``
|
||||
|
||||
Optional dependencies:
|
||||
|
||||
<<<<<<< HEAD
|
||||
- ``jinja2`` (for HTML output)
|
||||
- ``pysensors`` (for HW monitoring support) [Linux-only]
|
||||
- ``hddtemp`` (for HDD temperature monitoring support)
|
||||
- ``batinfo`` (for battery monitoring support) [Linux-only]
|
||||
=======
|
||||
- ``bottle`` (for Web server mode)
|
||||
- ``py3sensors`` (for hardware monitoring support) [Linux-only]
|
||||
- ``hddtemp`` (for HDD temperature monitoring support) [Linux-only]
|
||||
- ``batinfo`` (for battery monitoring support) [Linux-only]
|
||||
- ``pysnmp`` (for SNMP support)
|
||||
>>>>>>> release/v2.0
|
||||
|
||||
Installation
|
||||
============
|
||||
@ -44,14 +58,22 @@ Installation
|
||||
PyPI: The simple way
|
||||
--------------------
|
||||
|
||||
Glances is on `PyPI`_. To install, simply use `pip`_:
|
||||
Glances is on `PyPI`_. By using PyPI, you are sure to have the latest
|
||||
stable version.
|
||||
|
||||
To install, simply use `pip`_:
|
||||
|
||||
.. code-block:: console
|
||||
|
||||
pip install Glances
|
||||
|
||||
<<<<<<< HEAD
|
||||
*Note*: Python headers are required to install psutil.
|
||||
For example, on Debian/Ubuntu you need to install first the *python-dev* package.
|
||||
=======
|
||||
*Note*: Python headers are required to install psutil. For example,
|
||||
on Debian/Ubuntu you need to install first the *python-dev* package.
|
||||
>>>>>>> release/v2.0
|
||||
|
||||
To upgrade Glances to the latest version:
|
||||
|
||||
@ -59,10 +81,14 @@ To upgrade Glances to the latest version:
|
||||
|
||||
pip install --upgrade Glances
|
||||
|
||||
Linux
|
||||
-----
|
||||
GNU/Linux
|
||||
---------
|
||||
|
||||
<<<<<<< HEAD
|
||||
At the moment, packages exist for the following distributions:
|
||||
=======
|
||||
At the moment, packages exist for the following GNU/Linux distributions:
|
||||
>>>>>>> release/v2.0
|
||||
|
||||
- Arch Linux
|
||||
- Debian (Testing/Sid)
|
||||
@ -99,7 +125,7 @@ To install Glances from ports:
|
||||
OS X
|
||||
----
|
||||
|
||||
OS X users can also install Glances using `Homebrew`_ or `MacPorts`_.
|
||||
OS X users can install Glances using `Homebrew`_ or `MacPorts`_.
|
||||
|
||||
Homebrew
|
||||
````````
|
||||
@ -119,6 +145,7 @@ MacPorts
|
||||
Windows
|
||||
-------
|
||||
|
||||
<<<<<<< HEAD
|
||||
Glances proposes a Windows client based on the `colorconsole`_ Python library.
|
||||
Glances version < 1.7.2 only works in server mode.
|
||||
|
||||
@ -127,6 +154,12 @@ Thanks to Nicolas Bourges, a Windows installer is available:
|
||||
- Glances-1.7.2-win32.msi_ (32-bit, MD5: dba4f6cc9f47b6806ffaeb665c093270)
|
||||
|
||||
Otherwise, you have to follow these steps:
|
||||
=======
|
||||
Glances proposes a Windows client based on the `colorconsole`_ Python
|
||||
library.
|
||||
|
||||
To install Glances on Windows, you have to follow these steps:
|
||||
>>>>>>> release/v2.0
|
||||
|
||||
- Install Python for Windows: http://www.python.org/getit/
|
||||
- Install the psutil library: https://pypi.python.org/pypi?:action=display&name=psutil#downloads
|
||||
@ -136,17 +169,22 @@ Otherwise, you have to follow these steps:
|
||||
Source
|
||||
------
|
||||
|
||||
To install Glances from source:
|
||||
To install Glances version X.Y from source:
|
||||
|
||||
.. code-block:: console
|
||||
|
||||
$ curl -L https://github.com/nicolargo/glances/archive/vX.X.tar.gz -o glances-X.X.tar.gz
|
||||
$ curl -L https://github.com/nicolargo/glances/archive/vX.Y.tar.gz -o glances-X.Y.tar.gz
|
||||
$ tar -zxvf glances-*.tar.gz
|
||||
$ cd glances-*
|
||||
# python setup.py install
|
||||
|
||||
<<<<<<< HEAD
|
||||
*Note*: Python headers are required to install psutil.
|
||||
For example, on Debian/Ubuntu you need to install first the *python-dev* package.
|
||||
=======
|
||||
*Note*: Python headers are required to install psutil. For example,
|
||||
on Debian/Ubuntu you need to install first the *python-dev* package.
|
||||
>>>>>>> release/v2.0
|
||||
|
||||
Puppet
|
||||
------
|
||||
@ -156,13 +194,36 @@ You can install Glances using `Puppet`_: https://github.com/rverchere/puppet-gla
|
||||
Usage
|
||||
=====
|
||||
|
||||
Just run:
|
||||
For the standalone mode, just run:
|
||||
|
||||
.. code-block:: console
|
||||
|
||||
$ glances
|
||||
|
||||
and RTFM, always.
|
||||
|
||||
For the Web server mode, run:
|
||||
|
||||
.. code-block:: console
|
||||
|
||||
$ glances -w
|
||||
|
||||
and enter the URL ``http://<ip>:61208`` in your favorite web browser.
|
||||
|
||||
For the client/server mode, run:
|
||||
|
||||
.. code-block:: console
|
||||
|
||||
$ glances -s
|
||||
|
||||
on the server side and run:
|
||||
|
||||
.. code-block:: console
|
||||
|
||||
$ glances -c <ip>
|
||||
|
||||
on the client one.
|
||||
|
||||
And RTFM, always.
|
||||
|
||||
Documentation
|
||||
=============
|
||||
@ -186,7 +247,6 @@ LGPL. See ``COPYING`` for more details.
|
||||
.. _pip: http://www.pip-installer.org/
|
||||
.. _Homebrew: http://brew.sh/
|
||||
.. _MacPorts: https://www.macports.org/
|
||||
.. _Glances-1.7.2-win32.msi: http://glances.s3.amazonaws.com/Glances-1.7.2-win32.msi
|
||||
.. _colorconsole: https://pypi.python.org/pypi/colorconsole
|
||||
.. _Puppet: https://puppetlabs.com/puppet/what-is-puppet/
|
||||
.. _glances-doc: https://github.com/nicolargo/glances/blob/master/docs/glances-doc.rst
|
||||
|
1
TODO
@ -1 +0,0 @@
|
||||
See open issues here: https://github.com/nicolargo/glances/issues?milestone=&page=1&state=open
|
@ -1,29 +1,29 @@
|
||||
[cpu]
|
||||
# Limit values for CPU user in %
|
||||
# Default values if not defined: 50/70/90
|
||||
user_careful=50
|
||||
user_warning=70
|
||||
user_critical=90
|
||||
# Limit values for CPU system in %
|
||||
# Default values if not defined: 50/70/90
|
||||
iowait_careful=50
|
||||
iowait_warning=70
|
||||
iowait_critical=90
|
||||
system_careful=50
|
||||
system_warning=70
|
||||
system_critical=90
|
||||
steal_careful=50
|
||||
steal_warning=70
|
||||
steal_critical=90
|
||||
|
||||
[percpu]
|
||||
# Default values if not defined: 50/70/90
|
||||
user_careful=50
|
||||
user_warning=70
|
||||
user_critical=90
|
||||
iowait_careful=50
|
||||
iowait_warning=70
|
||||
iowait_critical=90
|
||||
system_careful=50
|
||||
system_warning=70
|
||||
system_critical=90
|
||||
# Limit values for CPU iowait in %
|
||||
# Default values if not defined: 40/60/80
|
||||
# Not easy to tweak...
|
||||
# Source: http://blog.scoutapp.com/articles/2011/02/10/understanding-disk-i-o-when-should-you-be-worried
|
||||
# http://blog.logicmonitor.com/2011/04/20/troubleshooting-server-performance-and-application-monitoring-a-real-example/
|
||||
# http://blog.developpeur-neurasthenique.fr/auto-hebergement-iowait-ma-tuer-1-2-vmstat-mpstat-atop-pidstat.html (FR)
|
||||
iowait_careful=40
|
||||
iowait_warning=60
|
||||
iowait_critical=80
|
||||
# Limit values for CPU steal in %
|
||||
# Default values if not defined: 10/15/20
|
||||
# Source: http://blog.scoutapp.com/articles/2013/07/25/understanding-cpu-steal-time-when-should-you-be-worried
|
||||
steal_careful=10
|
||||
steal_warning=15
|
||||
steal_critical=20
|
||||
|
||||
[load]
|
||||
# Value * number of cores
|
||||
@ -34,61 +34,68 @@ careful=0.7
|
||||
warning=1.0
|
||||
critical=5.0
|
||||
|
||||
[memory]
|
||||
[mem]
|
||||
# Default limits for free RAM memory in %
|
||||
# Default values if not defined: 50/70/90
|
||||
careful=50
|
||||
warning=70
|
||||
critical=90
|
||||
|
||||
[swap]
|
||||
[memswap]
|
||||
# Default limits for free swap memory in %
|
||||
# Default values if not defined: 50/70/90
|
||||
careful=50
|
||||
warning=70
|
||||
critical=90
|
||||
|
||||
[temperature]
|
||||
# Temperatures in °C for sensors
|
||||
# Default values if not defined: 60/70/80
|
||||
careful=60
|
||||
warning=70
|
||||
critical=80
|
||||
[network]
|
||||
# Define the list of hidden network interfaces (comma separeted)
|
||||
hide=lo
|
||||
# Default limits (in bits per second aka bps) for interface bitrate
|
||||
wlan0_rx_careful=4000000
|
||||
wlan0_rx_warning=5000000
|
||||
wlan0_rx_critical=6000000
|
||||
wlan0_tx_careful=700000
|
||||
wlan0_tx_warning=900000
|
||||
wlan0_tx_critical=1000000
|
||||
|
||||
[hddtemperature]
|
||||
# Temperatures in °C for hddtemp
|
||||
# Default values if not defined: 45/52/60
|
||||
careful=45
|
||||
warning=52
|
||||
critical=60
|
||||
[diskio]
|
||||
# Define the list of hidden disks (comma separeted)
|
||||
hide=sda2,sda5
|
||||
|
||||
[filesystem]
|
||||
[fs]
|
||||
# Default limits for free filesytem space in %
|
||||
# Default values if not defined: 50/70/90
|
||||
careful=50
|
||||
warning=70
|
||||
critical=90
|
||||
|
||||
[process]
|
||||
# Limit values for CPU per process in %
|
||||
[sensors]
|
||||
# Sensors core limits
|
||||
# Default values if not defined: 60/70/80
|
||||
temperature_core_careful=60
|
||||
temperature_core_warning=70
|
||||
temperature_core_critical=80
|
||||
# Temperatures in °C for hddtemp
|
||||
# Default values if not defined: 45/52/60
|
||||
temperature_hdd_careful=45
|
||||
temperature_hdd_warning=52
|
||||
temperature_hdd_critical=60
|
||||
# Battery % limits
|
||||
battery_careful=80
|
||||
battery_warning=90
|
||||
battery_critical=95
|
||||
|
||||
[processlist]
|
||||
# Limit values for CPU/MEM per process in %
|
||||
# Default values if not defined: 50/70/90
|
||||
cpu_careful=50
|
||||
cpu_warning=70
|
||||
cpu_critical=90
|
||||
# Limit values for MEM per process in %
|
||||
# Default values if not defined: 50/70/90
|
||||
mem_careful=50
|
||||
mem_warning=70
|
||||
mem_critical=90
|
||||
|
||||
[iodisk]
|
||||
# Define the list of hidden disks (comma separeted)
|
||||
#hide=sda2,sda5
|
||||
|
||||
[network]
|
||||
# Define the list of hidden network interfaces (comma separeted)
|
||||
#hide=lo
|
||||
|
||||
[monitor]
|
||||
# Define the list of processes to monitor
|
||||
# *** This section is optional ***
|
||||
@ -105,14 +112,12 @@ mem_critical=90
|
||||
# A warning will be displayed if number of process < count
|
||||
# * countmax: (optional) maximum number of processes
|
||||
# A warning will be displayed if number of process > count
|
||||
list_1_description=Stress programs
|
||||
list_1_regex=.*stress.*
|
||||
list_1_command=stress --version
|
||||
list_1_countmin=1
|
||||
list_1_countmax=4
|
||||
list_2_description=Python programs
|
||||
list_2_regex=.*python.*
|
||||
list_3_description=Famous Xeyes
|
||||
list_3_regex=.*xeyes.*
|
||||
list_3_countmin=0
|
||||
list_3_countmax=1
|
||||
#list_1_description=Dropbox
|
||||
#list_1_regex=.*dropbox.*
|
||||
#list_1_countmin=1
|
||||
#list_1_command=dropbox status | head -1
|
||||
list_1_description=Python programs
|
||||
list_1_regex=.*python.*
|
||||
list_2_description=Famous Xeyes
|
||||
list_2_regex=.*xeyes.*
|
||||
list_2_countmin=1
|
||||
|
@ -1,29 +1,29 @@
|
||||
[cpu]
|
||||
# Limit values for CPU user in %
|
||||
# Default values if not defined: 50/70/90
|
||||
user_careful=50
|
||||
user_warning=70
|
||||
user_critical=90
|
||||
# Limit values for CPU system in %
|
||||
# Default values if not defined: 50/70/90
|
||||
iowait_careful=50
|
||||
iowait_warning=70
|
||||
iowait_critical=90
|
||||
system_careful=50
|
||||
system_warning=70
|
||||
system_critical=90
|
||||
steal_careful=50
|
||||
steal_warning=70
|
||||
steal_critical=90
|
||||
|
||||
[percpu]
|
||||
# Default values if not defined: 50/70/90
|
||||
user_careful=50
|
||||
user_warning=70
|
||||
user_critical=90
|
||||
iowait_careful=50
|
||||
iowait_warning=70
|
||||
iowait_critical=90
|
||||
system_careful=50
|
||||
system_warning=70
|
||||
system_critical=90
|
||||
# Limit values for CPU iowait in %
|
||||
# Default values if not defined: 40/60/80
|
||||
# Not easy to tweak...
|
||||
# Source: http://blog.scoutapp.com/articles/2011/02/10/understanding-disk-i-o-when-should-you-be-worried
|
||||
# http://blog.logicmonitor.com/2011/04/20/troubleshooting-server-performance-and-application-monitoring-a-real-example/
|
||||
# http://blog.developpeur-neurasthenique.fr/auto-hebergement-iowait-ma-tuer-1-2-vmstat-mpstat-atop-pidstat.html (FR)
|
||||
iowait_careful=40
|
||||
iowait_warning=60
|
||||
iowait_critical=80
|
||||
# Limit values for CPU steal in %
|
||||
# Default values if not defined: 10/15/20
|
||||
# Source: http://blog.scoutapp.com/articles/2013/07/25/understanding-cpu-steal-time-when-should-you-be-worried
|
||||
steal_careful=10
|
||||
steal_warning=15
|
||||
steal_critical=20
|
||||
|
||||
[load]
|
||||
# Value * number of cores
|
||||
@ -34,80 +34,64 @@ careful=0.7
|
||||
warning=1.0
|
||||
critical=5.0
|
||||
|
||||
[memory]
|
||||
[mem]
|
||||
# Default limits for free RAM memory in %
|
||||
# Default values if not defined: 50/70/90
|
||||
careful=50
|
||||
warning=70
|
||||
critical=90
|
||||
|
||||
[swap]
|
||||
[memswap]
|
||||
# Default limits for free swap memory in %
|
||||
# Default values if not defined: 50/70/90
|
||||
careful=50
|
||||
warning=70
|
||||
critical=90
|
||||
|
||||
[temperature]
|
||||
# Temperatures in °C for sensors
|
||||
# Default values if not defined: 60/70/80
|
||||
careful=60
|
||||
warning=70
|
||||
critical=80
|
||||
[network]
|
||||
# Define the list of hidden network interfaces (comma separeted)
|
||||
hide=lo
|
||||
# Default limits (in bits per second aka bps) for interface bitrate
|
||||
wlan0_rx_careful=4000000
|
||||
wlan0_rx_warning=5000000
|
||||
wlan0_rx_critical=6000000
|
||||
wlan0_tx_careful=700000
|
||||
wlan0_tx_warning=900000
|
||||
wlan0_tx_critical=1000000
|
||||
|
||||
[hddtemperature]
|
||||
# Temperatures in °C for hddtemp
|
||||
# Default values if not defined: 45/52/60
|
||||
careful=45
|
||||
warning=52
|
||||
critical=60
|
||||
[diskio]
|
||||
# Define the list of hidden disks (comma separeted)
|
||||
hide=sda2,sda5
|
||||
|
||||
[filesystem]
|
||||
[fs]
|
||||
# Default limits for free filesytem space in %
|
||||
# Default values if not defined: 50/70/90
|
||||
careful=50
|
||||
warning=70
|
||||
critical=90
|
||||
|
||||
[process]
|
||||
# Limit values for CPU per process in %
|
||||
[sensors]
|
||||
# Sensors core limits
|
||||
# Default values if not defined: 60/70/80
|
||||
temperature_core_careful=60
|
||||
temperature_core_warning=70
|
||||
temperature_core_critical=80
|
||||
# Temperatures in °C for hddtemp
|
||||
# Default values if not defined: 45/52/60
|
||||
temperature_hdd_careful=45
|
||||
temperature_hdd_warning=52
|
||||
temperature_hdd_critical=60
|
||||
# Battery % limits
|
||||
battery_careful=80
|
||||
battery_warning=90
|
||||
battery_critical=95
|
||||
|
||||
[processlist]
|
||||
# Limit values for CPU/MEM per process in %
|
||||
# Default values if not defined: 50/70/90
|
||||
cpu_careful=50
|
||||
cpu_warning=70
|
||||
cpu_critical=90
|
||||
# Limit values for MEM per process in %
|
||||
# Default values if not defined: 50/70/90
|
||||
mem_careful=50
|
||||
mem_warning=70
|
||||
mem_critical=90
|
||||
|
||||
[iodisk]
|
||||
# Define the list of hidden disks (comma separated)
|
||||
#hide=sda2,sda5
|
||||
|
||||
[network]
|
||||
# Define the list of hidden network interfaces (comma separated)
|
||||
#hide=lo
|
||||
|
||||
[monitor]
|
||||
# Define the list of processes to monitor
|
||||
# *** This section is optional ***
|
||||
# The list is composed of items (list_#nb <= 10)
|
||||
# An item is defined:
|
||||
# * description: Description of the processes (max 16 chars)
|
||||
# * regex: regular expression of the processes to monitor
|
||||
# * command: (optional) full path to shell command/script for extended stat
|
||||
# Use with caution. Should return a single line string.
|
||||
# * countmin: (optional) minimal number of processes
|
||||
# A warning will be displayed if number of process < count
|
||||
# * countmax: (optional) maximum number of processes
|
||||
# A warning will be displayed if number of process > count
|
||||
#list_1_description=Redis server
|
||||
#list_1_regex=.*redis-server.*
|
||||
#list_1_command=echo "Additional stats"
|
||||
#list_2_description=Python programs
|
||||
#list_2_regex=.*python.*
|
||||
#list_2_countmin=1
|
||||
#list_2_countmax=8
|
||||
#list_3_description=Famous Xeyes
|
||||
#list_3_regex=.*xeyes.*
|
||||
|
@ -70,12 +70,12 @@ p.topic-title {
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
pre.code {
|
||||
pre {
|
||||
margin-left: 2em;
|
||||
margin-right: 2em;
|
||||
}
|
||||
|
||||
.console {
|
||||
.console, .literal-block {
|
||||
background-color: #eeeeee;
|
||||
border: 1px solid #cccccc;
|
||||
max-width: 60em;
|
||||
@ -123,71 +123,78 @@ td.option-group {
|
||||
<div class="document" id="glances">
|
||||
<h1 class="title">Glances</h1>
|
||||
|
||||
<p>This manual describes <em>Glances</em> version 1.7.7.</p>
|
||||
<p>This manual describes <em>Glances</em> version 2.0.</p>
|
||||
<p>Copyright © 2012-2014 Nicolas Hennion <<a class="reference external" href="mailto:nicolas@nicolargo.com">nicolas@nicolargo.com</a>></p>
|
||||
<p>May 2014</p>
|
||||
<p>June 2014</p>
|
||||
<div class="contents topic" id="table-of-contents">
|
||||
<p class="topic-title first">Table of Contents</p>
|
||||
<ul class="simple">
|
||||
<li><a class="reference internal" href="#introduction" id="id7">Introduction</a></li>
|
||||
<li><a class="reference internal" href="#usage" id="id8">Usage</a><ul>
|
||||
<li><a class="reference internal" href="#standalone-mode" id="id9">Standalone mode</a></li>
|
||||
<li><a class="reference internal" href="#client-server-mode" id="id10">Client/Server mode</a></li>
|
||||
<li><a class="reference internal" href="#introduction" id="id6">Introduction</a></li>
|
||||
<li><a class="reference internal" href="#usage" id="id7">Usage</a><ul>
|
||||
<li><a class="reference internal" href="#standalone-mode" id="id8">Standalone Mode</a></li>
|
||||
<li><a class="reference internal" href="#client-server-mode" id="id9">Client/Server Mode</a></li>
|
||||
<li><a class="reference internal" href="#web-server-mode" id="id10">Web Server Mode</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li><a class="reference internal" href="#command-reference" id="id11">Command reference</a><ul>
|
||||
<li><a class="reference internal" href="#command-line-options" id="id12">Command-line options</a></li>
|
||||
<li><a class="reference internal" href="#interactive-commands" id="id13">Interactive commands</a></li>
|
||||
<li><a class="reference internal" href="#command-reference" id="id11">Command Reference</a><ul>
|
||||
<li><a class="reference internal" href="#command-line-options" id="id12">Command-Line Options</a></li>
|
||||
<li><a class="reference internal" href="#interactive-commands" id="id13">Interactive Commands</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li><a class="reference internal" href="#configuration" id="id14">Configuration</a></li>
|
||||
<li><a class="reference internal" href="#anatomy-of-the-application" id="id15">Anatomy of the application</a><ul>
|
||||
<li><a class="reference internal" href="#anatomy-of-the-application" id="id15">Anatomy Of The Application</a><ul>
|
||||
<li><a class="reference internal" href="#legend" id="id16">Legend</a></li>
|
||||
<li><a class="reference internal" href="#header" id="id17">Header</a></li>
|
||||
<li><a class="reference internal" href="#cpu" id="id18">CPU</a></li>
|
||||
<li><a class="reference internal" href="#load" id="id19">Load</a></li>
|
||||
<li><a class="reference internal" href="#memory" id="id20">Memory</a></li>
|
||||
<li><a class="reference internal" href="#network" id="id21">Network</a></li>
|
||||
<li><a class="reference internal" href="#sensors" id="id22">Sensors</a></li>
|
||||
<li><a class="reference internal" href="#disk-i-o" id="id23">Disk I/O</a></li>
|
||||
<li><a class="reference internal" href="#file-system" id="id24">File system</a></li>
|
||||
<li><a class="reference internal" href="#processes-list" id="id25">Processes list</a></li>
|
||||
<li><a class="reference internal" href="#monitored-processes-list" id="id26">Monitored processes list</a></li>
|
||||
<li><a class="reference internal" href="#disk-i-o" id="id22">Disk I/O</a></li>
|
||||
<li><a class="reference internal" href="#file-system" id="id23">File System</a></li>
|
||||
<li><a class="reference internal" href="#sensors" id="id24">Sensors</a></li>
|
||||
<li><a class="reference internal" href="#processes-list" id="id25">Processes List</a></li>
|
||||
<li><a class="reference internal" href="#monitored-processes-list" id="id26">Monitored Processes List</a></li>
|
||||
<li><a class="reference internal" href="#logs" id="id27">Logs</a></li>
|
||||
<li><a class="reference internal" href="#footer" id="id28">Footer</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li><a class="reference internal" href="#api-documentation" id="id29">API documentation</a></li>
|
||||
<li><a class="reference internal" href="#other-outputs" id="id30">Other outputs</a></li>
|
||||
<li><a class="reference internal" href="#support" id="id31">Support</a></li>
|
||||
<li><a class="reference internal" href="#other-outputs" id="id28">Other Outputs</a></li>
|
||||
<li><a class="reference internal" href="#api-documentation" id="id29">API Documentation</a></li>
|
||||
<li><a class="reference internal" href="#id3" id="id30">Other outputs</a></li>
|
||||
<li><a class="reference internal" href="#note-the-css-and-img-folders-glances-data-should-be-in-the-tmp-folder" id="id31"><em>Note</em>: The css and img folders (glances/data) should be in the /tmp folder.</a></li>
|
||||
<li><a class="reference internal" href="#support" id="id32">Support</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="section" id="introduction">
|
||||
<h1><a class="toc-backref" href="#id7">Introduction</a></h1>
|
||||
<p>Glances is a cross-platform curses-based monitoring tool which aims to
|
||||
present a maximum of information in a minimum of space, ideally to fit
|
||||
in a classical 80x24 terminal or higher to have additional information.</p>
|
||||
<p>Glances can adapt dynamically the displayed information depending on the
|
||||
terminal size. It can also work in a client/server mode for remote monitoring.</p>
|
||||
<p>Glances is written in Python and uses the <a class="reference external" href="https://code.google.com/p/psutil/">psutil</a> library to get information from your system.</p>
|
||||
<h1><a class="toc-backref" href="#id6">Introduction</a></h1>
|
||||
<p>Glances is a cross-platform curses-based system monitoring tool which
|
||||
aims to present a maximum of information in a minimum of space, ideally
|
||||
to fit in a classical 80x24 terminal or higher to have additional
|
||||
information. It can adapt dynamically the displayed information depending
|
||||
on the terminal size.</p>
|
||||
<p>Glances can also work in client/server mode. Remote monitoring could be
|
||||
done via terminal or web interface.</p>
|
||||
<p>Glances is written in Python and uses the <a class="reference external" href="https://code.google.com/p/psutil/">psutil</a> library to get
|
||||
information from your system.</p>
|
||||
<p>Console (80x24)</p>
|
||||
<img alt="images/screenshot.png" src="images/screenshot.png" />
|
||||
<p>Full view (>80x24)</p>
|
||||
<img alt="images/screenshot-wide.png" src="images/screenshot-wide.png" />
|
||||
<p>Web interface (Firefox)</p>
|
||||
<img alt="images/screenshot-web.png" src="images/screenshot-web.png" />
|
||||
</div>
|
||||
<div class="section" id="usage">
|
||||
<h1><a class="toc-backref" href="#id8">Usage</a></h1>
|
||||
<h1><a class="toc-backref" href="#id7">Usage</a></h1>
|
||||
<div class="section" id="standalone-mode">
|
||||
<h2><a class="toc-backref" href="#id9">Standalone mode</a></h2>
|
||||
<h2><a class="toc-backref" href="#id8">Standalone Mode</a></h2>
|
||||
<p>Simply run:</p>
|
||||
<pre class="code console literal-block">
|
||||
<span class="generic prompt">$</span> glances
|
||||
</pre>
|
||||
</div>
|
||||
<div class="section" id="client-server-mode">
|
||||
<h2><a class="toc-backref" href="#id10">Client/Server mode</a></h2>
|
||||
<p>If you want to remotely monitor a machine, called <tt class="docutils literal">server</tt>, from another one, called <tt class="docutils literal">client</tt>,
|
||||
just run on the server:</p>
|
||||
<h2><a class="toc-backref" href="#id9">Client/Server Mode</a></h2>
|
||||
<p>If you want to remotely monitor a machine, called <tt class="docutils literal">server</tt>, from
|
||||
another one, called <tt class="docutils literal">client</tt>, just run on the server:</p>
|
||||
<pre class="code console literal-block">
|
||||
<span class="generic output">server$ glances -s</span>
|
||||
</pre>
|
||||
@ -196,90 +203,146 @@ just run on the server:</p>
|
||||
<span class="generic output">client$ glances -c @server</span>
|
||||
</pre>
|
||||
<p>where <tt class="docutils literal">@server</tt> is the IP address or hostname of the server.</p>
|
||||
<p>In server mode, you can set the bind address <tt class="docutils literal"><span class="pre">-B</span> ADDRESS</tt> and listening TCP port <tt class="docutils literal"><span class="pre">-p</span> PORT</tt>.</p>
|
||||
<p>In server mode, you can set the bind address <tt class="docutils literal"><span class="pre">-B</span> ADDRESS</tt> and listening
|
||||
TCP port <tt class="docutils literal"><span class="pre">-p</span> PORT</tt>.</p>
|
||||
<p>In client mode, you can set the TCP port of the server <tt class="docutils literal"><span class="pre">-p</span> PORT</tt>.</p>
|
||||
<p>Default binding address is <tt class="docutils literal">0.0.0.0</tt> (Glances will listen on all the network interfaces) and TCP port is <tt class="docutils literal">61209</tt>.</p>
|
||||
<p>You can also set a password to access to the server <tt class="docutils literal"><span class="pre">--password</span></tt>.</p>
|
||||
<p>Default binding address is <tt class="docutils literal">0.0.0.0</tt> (Glances will listen on all the
|
||||
network interfaces) and TCP port is <tt class="docutils literal">61209</tt>.</p>
|
||||
<p>In client/server mode, limits are set by the server side.</p>
|
||||
<p>You can also set a password to access to the server <tt class="docutils literal"><span class="pre">-P</span> password</tt>.</p>
|
||||
<p>Glances is <tt class="docutils literal">IPv6</tt> compatible. Just use the <tt class="docutils literal"><span class="pre">-B</span> ::</tt> option to bind to all IPv6 addresses.</p>
|
||||
<p>Glances is <tt class="docutils literal">IPv6</tt> compatible. Just use the <tt class="docutils literal"><span class="pre">-B</span> ::</tt> option to bind to
|
||||
all IPv6 addresses.</p>
|
||||
<p>As an experimental feature, if Glances server is not detected by the
|
||||
client, the latter will try to grab stats using the <tt class="docutils literal">SNMP</tt> protocol:</p>
|
||||
<pre class="code console literal-block">
|
||||
<span class="generic output">client$ glances -c @snmpserver</span>
|
||||
</pre>
|
||||
<p>Known issues: grab using SNMP is only validated for GNU/Linux with SNMP
|
||||
v2/2c server.</p>
|
||||
</div>
|
||||
<div class="section" id="web-server-mode">
|
||||
<h2><a class="toc-backref" href="#id10">Web Server Mode</a></h2>
|
||||
<p>If you want to remotely monitor a machine, called <tt class="docutils literal">server</tt>, from any
|
||||
device with a web browser, called <tt class="docutils literal">client</tt>, just run on the server:</p>
|
||||
<pre class="code console literal-block">
|
||||
<span class="generic output">server$ glances -w</span>
|
||||
</pre>
|
||||
<p>and on the client enter the following URL in your favorite web browser:</p>
|
||||
<pre class="literal-block">
|
||||
http://@server:61208
|
||||
</pre>
|
||||
<p>where <tt class="docutils literal">@server</tt> is the IP address or hostname of the server.</p>
|
||||
<p>The Glances web interface follows responsive web design principles.</p>
|
||||
<p>Screenshot from Chrome on Android</p>
|
||||
<img alt="images/screenshot-web2.png" src="images/screenshot-web2.png" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="section" id="command-reference">
|
||||
<h1><a class="toc-backref" href="#id11">Command reference</a></h1>
|
||||
<h1><a class="toc-backref" href="#id11">Command Reference</a></h1>
|
||||
<div class="section" id="command-line-options">
|
||||
<h2><a class="toc-backref" href="#id12">Command-line options</a></h2>
|
||||
<h2><a class="toc-backref" href="#id12">Command-Line Options</a></h2>
|
||||
<table class="docutils option-list" frame="void" rules="none">
|
||||
<col class="option" />
|
||||
<col class="description" />
|
||||
<tbody valign="top">
|
||||
<tr><td class="option-group">
|
||||
<kbd><span class="option">-b</span></kbd></td>
|
||||
<td>Display network rate in Byte per second (default: bit per second)</td></tr>
|
||||
<kbd><span class="option">-h</span>, <span class="option">--help</span></kbd></td>
|
||||
<td>show this help message and exit</td></tr>
|
||||
<tr><td class="option-group">
|
||||
<kbd><span class="option">-B <var>IP</var></span></kbd></td>
|
||||
<td>Bind server to the given IPv4/IPv6 address or hostname</td></tr>
|
||||
<kbd><span class="option">-V</span>, <span class="option">--version</span></kbd></td>
|
||||
<td>show program's version number and exit</td></tr>
|
||||
<tr><td class="option-group">
|
||||
<kbd><span class="option">-c <var>IP</var></span></kbd></td>
|
||||
<td>Connect to a Glances server by IPv4/IPv6 address or hostname</td></tr>
|
||||
<kbd><span class="option">-b</span>, <span class="option">--byte</span></kbd></td>
|
||||
<td>display network rate in byte per second</td></tr>
|
||||
<tr><td class="option-group" colspan="2">
|
||||
<kbd><span class="option">-B <var>BIND_ADDRESS</var></span>, <span class="option">--bind <var>BIND_ADDRESS</var></span></kbd></td>
|
||||
</tr>
|
||||
<tr><td> </td><td>bind server to the given IPv4/IPv6 address or hostname</td></tr>
|
||||
<tr><td class="option-group" colspan="2">
|
||||
<kbd><span class="option">-c <var>CLIENT</var></span>, <span class="option">--client <var>CLIENT</var></span></kbd></td>
|
||||
</tr>
|
||||
<tr><td> </td><td>connect to a Glances server by IPv4/IPv6 address or
|
||||
hostname</td></tr>
|
||||
<tr><td class="option-group" colspan="2">
|
||||
<kbd><span class="option">-C <var>CONF_FILE</var></span>, <span class="option">--config <var>CONF_FILE</var></span></kbd></td>
|
||||
</tr>
|
||||
<tr><td> </td><td>path to the configuration file</td></tr>
|
||||
<tr><td class="option-group">
|
||||
<kbd><span class="option">-C <var>FILE</var></span></kbd></td>
|
||||
<td>Path to the configuration file</td></tr>
|
||||
<kbd><span class="option">--disable-bold</span></kbd></td>
|
||||
<td>disable bold mode in the terminal</td></tr>
|
||||
<tr><td class="option-group" colspan="2">
|
||||
<kbd><span class="option">--disable-diskio</span></kbd></td>
|
||||
</tr>
|
||||
<tr><td> </td><td>disable disk I/O module</td></tr>
|
||||
<tr><td class="option-group">
|
||||
<kbd><span class="option">-d</span></kbd></td>
|
||||
<td>Disable disk I/O module</td></tr>
|
||||
<kbd><span class="option">--disable-fs</span></kbd></td>
|
||||
<td>disable file system module</td></tr>
|
||||
<tr><td class="option-group" colspan="2">
|
||||
<kbd><span class="option">--disable-network</span></kbd></td>
|
||||
</tr>
|
||||
<tr><td> </td><td>disable network module</td></tr>
|
||||
<tr><td class="option-group" colspan="2">
|
||||
<kbd><span class="option">--disable-sensors</span></kbd></td>
|
||||
</tr>
|
||||
<tr><td> </td><td>disable sensors module</td></tr>
|
||||
<tr><td class="option-group" colspan="2">
|
||||
<kbd><span class="option">--disable-process</span></kbd></td>
|
||||
</tr>
|
||||
<tr><td> </td><td>disable process module</td></tr>
|
||||
<tr><td class="option-group">
|
||||
<kbd><span class="option">-e</span></kbd></td>
|
||||
<td>Enable sensors module (requires pysensors, Linux-only)</td></tr>
|
||||
<tr><td class="option-group">
|
||||
<kbd><span class="option">-f <var>FOLDER</var></span></kbd></td>
|
||||
<td>Set the HTML or CSV output folder</td></tr>
|
||||
<tr><td class="option-group">
|
||||
<kbd><span class="option">-h</span></kbd></td>
|
||||
<td>Display the help and exit</td></tr>
|
||||
<tr><td class="option-group">
|
||||
<kbd><span class="option">-m</span></kbd></td>
|
||||
<td>Disable mount module</td></tr>
|
||||
<tr><td class="option-group">
|
||||
<kbd><span class="option">-n</span></kbd></td>
|
||||
<td>Disable network module</td></tr>
|
||||
<tr><td class="option-group">
|
||||
<kbd><span class="option">-o <var>OUTPUT</var></span></kbd></td>
|
||||
<td>Define additional output (available: HTML or CSV)</td></tr>
|
||||
<tr><td class="option-group">
|
||||
<kbd><span class="option">-p <var>PORT</var></span></kbd></td>
|
||||
<td>Define the client/server TCP port (default: 61209)</td></tr>
|
||||
<tr><td class="option-group">
|
||||
<kbd><span class="option">-P <var>PASSWORD</var></span></kbd></td>
|
||||
<td>Define a client/server password</td></tr>
|
||||
<kbd><span class="option">--disable-log</span></kbd></td>
|
||||
<td>disable log module</td></tr>
|
||||
<tr><td class="option-group" colspan="2">
|
||||
<kbd><span class="option">--output-csv <var>OUTPUT_CSV</var></span></kbd></td>
|
||||
</tr>
|
||||
<tr><td> </td><td>export stats to a CSV file</td></tr>
|
||||
<tr><td class="option-group" colspan="2">
|
||||
<kbd><span class="option">-p <var>PORT</var></span>, <span class="option">--port <var>PORT</var></span></kbd></td>
|
||||
</tr>
|
||||
<tr><td> </td><td>define the client/server TCP port [default: 61209]</td></tr>
|
||||
<tr><td class="option-group">
|
||||
<kbd><span class="option">--password</span></kbd></td>
|
||||
<td>Define a client/server password from the prompt</td></tr>
|
||||
<td>define a client/server password from the prompt or
|
||||
file</td></tr>
|
||||
<tr><td class="option-group">
|
||||
<kbd><span class="option">-r</span></kbd></td>
|
||||
<td>Disable process list (for low CPU consumption)</td></tr>
|
||||
<kbd><span class="option">-s</span>, <span class="option">--server</span></kbd></td>
|
||||
<td>run Glances in server mode</td></tr>
|
||||
<tr><td class="option-group" colspan="2">
|
||||
<kbd><span class="option">--snmp-community <var>SNMP_COMMUNITY</var></span></kbd></td>
|
||||
</tr>
|
||||
<tr><td> </td><td>SNMP community</td></tr>
|
||||
<tr><td class="option-group" colspan="2">
|
||||
<kbd><span class="option">--snmp-port <var>SNMP_PORT</var></span></kbd></td>
|
||||
</tr>
|
||||
<tr><td> </td><td>SNMP port</td></tr>
|
||||
<tr><td class="option-group" colspan="2">
|
||||
<kbd><span class="option">--snmp-version <var>SNMP_VERSION</var></span></kbd></td>
|
||||
</tr>
|
||||
<tr><td> </td><td>SNMP version (1, 2c or 3)</td></tr>
|
||||
<tr><td class="option-group" colspan="2">
|
||||
<kbd><span class="option">--snmp-user <var>SNMP_USER</var></span></kbd></td>
|
||||
</tr>
|
||||
<tr><td> </td><td>SNMP username (only for SNMPv3)</td></tr>
|
||||
<tr><td class="option-group" colspan="2">
|
||||
<kbd><span class="option">--snmp-auth <var>SNMP_AUTH</var></span></kbd></td>
|
||||
</tr>
|
||||
<tr><td> </td><td>SNMP authentication key (only for SNMPv3)</td></tr>
|
||||
<tr><td class="option-group" colspan="2">
|
||||
<kbd><span class="option">-t <var>TIME</var></span>, <span class="option">--time <var>TIME</var></span></kbd></td>
|
||||
</tr>
|
||||
<tr><td> </td><td>set refresh time in seconds [default: 3 sec]</td></tr>
|
||||
<tr><td class="option-group" colspan="2">
|
||||
<kbd><span class="option">-w</span>, <span class="option">--webserver</span></kbd></td>
|
||||
</tr>
|
||||
<tr><td> </td><td>run Glances in Web server mode</td></tr>
|
||||
<tr><td class="option-group">
|
||||
<kbd><span class="option">-s</span></kbd></td>
|
||||
<td>Run Glances in server mode</td></tr>
|
||||
<tr><td class="option-group">
|
||||
<kbd><span class="option">-t <var>SECONDS</var></span></kbd></td>
|
||||
<td>Set refresh time in seconds (default: 3 sec)</td></tr>
|
||||
<tr><td class="option-group">
|
||||
<kbd><span class="option">-v</span></kbd></td>
|
||||
<td>Display the version and exit</td></tr>
|
||||
<tr><td class="option-group">
|
||||
<kbd><span class="option">-y</span></kbd></td>
|
||||
<td>Enable hddtemp module (requires hddtemp)</td></tr>
|
||||
<tr><td class="option-group">
|
||||
<kbd><span class="option">-z</span></kbd></td>
|
||||
<td>Do not use the bold color attribute</td></tr>
|
||||
<tr><td class="option-group">
|
||||
<kbd><span class="option">-1</span></kbd></td>
|
||||
<td>Start Glances in per-CPU mode</td></tr>
|
||||
<kbd><span class="option">-1</span>, <span class="option">--percpu</span></kbd></td>
|
||||
<td>start Glances in per CPU mode</td></tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<div class="section" id="interactive-commands">
|
||||
<h2><a class="toc-backref" href="#id13">Interactive commands</a></h2>
|
||||
<h2><a class="toc-backref" href="#id13">Interactive Commands</a></h2>
|
||||
<p>The following commands (key pressed) are supported while in Glances:</p>
|
||||
<dl class="docutils">
|
||||
<dt><tt class="docutils literal">a</tt></dt>
|
||||
@ -301,7 +364,7 @@ just run on the server:</p>
|
||||
<dt><tt class="docutils literal">h</tt></dt>
|
||||
<dd>Show/hide the help screen</dd>
|
||||
<dt><tt class="docutils literal">i</tt></dt>
|
||||
<dd>Sort processes by I/O rate (may need root privileges on some OSes)</dd>
|
||||
<dd>Sort processes by I/O rate</dd>
|
||||
<dt><tt class="docutils literal">l</tt></dt>
|
||||
<dd>Show/hide log messages</dd>
|
||||
<dt><tt class="docutils literal">m</tt></dt>
|
||||
@ -313,7 +376,7 @@ just run on the server:</p>
|
||||
<dt><tt class="docutils literal">q</tt></dt>
|
||||
<dd>Quit</dd>
|
||||
<dt><tt class="docutils literal">s</tt></dt>
|
||||
<dd>Show/hide sensors stats (only available with -e flag)</dd>
|
||||
<dd>Show/hide sensors stats</dd>
|
||||
<dt><tt class="docutils literal">t</tt></dt>
|
||||
<dd>View network I/O as combination</dd>
|
||||
<dt><tt class="docutils literal">u</tt></dt>
|
||||
@ -322,10 +385,8 @@ just run on the server:</p>
|
||||
<dd>Delete finished warning log messages</dd>
|
||||
<dt><tt class="docutils literal">x</tt></dt>
|
||||
<dd>Delete finished warning and critical log messages</dd>
|
||||
<dt><tt class="docutils literal">y</tt></dt>
|
||||
<dd>Show/hide hddtemp stats (only available with -y flag)</dd>
|
||||
<dt><tt class="docutils literal">z</tt></dt>
|
||||
<dd>Show/hide processes list (for low CPU consumption)</dd>
|
||||
<dd>Show/hide processes stats</dd>
|
||||
<dt><tt class="docutils literal">1</tt></dt>
|
||||
<dd>Switch between global CPU and per-CPU stats</dd>
|
||||
</dl>
|
||||
@ -333,8 +394,11 @@ just run on the server:</p>
|
||||
</div>
|
||||
<div class="section" id="configuration">
|
||||
<h1><a class="toc-backref" href="#id14">Configuration</a></h1>
|
||||
<p><strong>Caution! Glances version 1.x configuration files are not compatible
|
||||
with the version 2.x.</strong></p>
|
||||
<p>No configuration file is mandatory to use Glances.</p>
|
||||
<p>Furthermore a configuration file is needed for setup limits, disks or network interfaces to hide and/or monitored processes list.</p>
|
||||
<p>Furthermore a configuration file is needed to set up limits, disks or
|
||||
network interfaces to hide and/or monitored processes list.</p>
|
||||
<p>By default, the configuration file is under:</p>
|
||||
<table class="docutils field-list" frame="void" rules="none">
|
||||
<col class="field-name" />
|
||||
@ -349,24 +413,26 @@ just run on the server:</p>
|
||||
</tbody>
|
||||
</table>
|
||||
<p>On Windows XP, the <tt class="docutils literal">%APPDATA%</tt> path is:</p>
|
||||
<pre class="code console literal-block">
|
||||
<span class="generic output">C:\Documents and Settings\<User>\Application Data</span>
|
||||
<pre class="literal-block">
|
||||
C:\Documents and Settings\<User>\Application Data
|
||||
</pre>
|
||||
<p>Since Windows Vista and newer versions:</p>
|
||||
<pre class="code console literal-block">
|
||||
<span class="generic output">C:\Users\<User>\AppData\Roaming</span>
|
||||
<pre class="literal-block">
|
||||
C:\Users\<User>\AppData\Roaming
|
||||
</pre>
|
||||
<p>You can override the default configuration, located in one of the above
|
||||
directories on your system, except for Windows.</p>
|
||||
<p>Just copy the <tt class="docutils literal">glances.conf</tt> file to your <tt class="docutils literal">$XDG_CONFIG_HOME</tt> directory, e.g. Linux:</p>
|
||||
<p>Just copy the <tt class="docutils literal">glances.conf</tt> file to your <tt class="docutils literal">$XDG_CONFIG_HOME</tt> directory,
|
||||
e.g., on Linux:</p>
|
||||
<pre class="code console literal-block">
|
||||
<span class="generic output">mkdir -p $XDG_CONFIG_HOME/glances
|
||||
cp /etc/glances/glances.conf $XDG_CONFIG_HOME/glances/</span>
|
||||
cp /usr/share/doc/glances/glances.conf $XDG_CONFIG_HOME/glances/</span>
|
||||
</pre>
|
||||
<p>On OS X, you should copy the configuration file to <tt class="docutils literal">~/Library/Application Support/glances/</tt>.</p>
|
||||
<p>On OS X, you should copy the configuration file to
|
||||
<tt class="docutils literal">~/Library/Application Support/glances/</tt>.</p>
|
||||
</div>
|
||||
<div class="section" id="anatomy-of-the-application">
|
||||
<h1><a class="toc-backref" href="#id15">Anatomy of the application</a></h1>
|
||||
<h1><a class="toc-backref" href="#id15">Anatomy Of The Application</a></h1>
|
||||
<div class="section" id="legend">
|
||||
<h2><a class="toc-backref" href="#id16">Legend</a></h2>
|
||||
<div class="line-block">
|
||||
@ -375,123 +441,127 @@ cp /etc/glances/glances.conf $XDG_CONFIG_HOME/glances/</span>
|
||||
<div class="line"><tt class="docutils literal">MAGENTA</tt> stat counter is <tt class="docutils literal">"WARNING"</tt></div>
|
||||
<div class="line"><tt class="docutils literal">RED</tt> stat counter is <tt class="docutils literal">"CRITICAL"</tt></div>
|
||||
</div>
|
||||
<p><em>Note</em>: only stats with colored background will be logged in the alert
|
||||
view.</p>
|
||||
</div>
|
||||
<div class="section" id="header">
|
||||
<h2><a class="toc-backref" href="#id17">Header</a></h2>
|
||||
<img alt="images/header.png" src="images/header.png" />
|
||||
<p>The header shows the hostname, OS name, release version, platform architecture and system uptime.
|
||||
On Linux, it shows also the kernel version.</p>
|
||||
<p>The header shows the hostname, OS name, release version, platform
|
||||
architecture and system uptime (on the upper right corner).
|
||||
Additionally, on GNU/Linux, it also shows the kernel version.</p>
|
||||
<p>In client mode, the server connection status is displayed.</p>
|
||||
<p>Connected:</p>
|
||||
<img alt="images/connected.png" src="images/connected.png" />
|
||||
<p>Disconnected:</p>
|
||||
<img alt="images/disconnected.png" src="images/disconnected.png" />
|
||||
</div>
|
||||
<div class="section" id="cpu">
|
||||
<h2><a class="toc-backref" href="#id18">CPU</a></h2>
|
||||
<p>Short view:</p>
|
||||
<img alt="images/cpu.png" src="images/cpu.png" />
|
||||
<p>If enough horizontal space is available, extended CPU informations are displayed.</p>
|
||||
<p>If enough horizontal space is available, extended CPU information are
|
||||
displayed.</p>
|
||||
<p>Extended view:</p>
|
||||
<img alt="images/cpu-wide.png" src="images/cpu-wide.png" />
|
||||
<p>To switch to per-CPU stats, just hit the <tt class="docutils literal">1</tt> key:</p>
|
||||
<img alt="images/per-cpu.png" src="images/per-cpu.png" />
|
||||
<p>The CPU stats are shown as a percentage and for the configured refresh time.
|
||||
The total CPU usage is displayed on the first line.</p>
|
||||
<p>The CPU stats are shown as a percentage and for the configured refresh
|
||||
time. The total CPU usage is displayed on the first line.</p>
|
||||
<div class="line-block">
|
||||
<div class="line">If user|system|nice CPU is <tt class="docutils literal"><50%</tt>, then status is set to <tt class="docutils literal">"OK"</tt></div>
|
||||
<div class="line">If user|system|nice CPU is <tt class="docutils literal">>50%</tt>, then status is set to <tt class="docutils literal">"CAREFUL"</tt></div>
|
||||
<div class="line">If user|system|nice CPU is <tt class="docutils literal">>70%</tt>, then status is set to <tt class="docutils literal">"WARNING"</tt></div>
|
||||
<div class="line">If user|system|nice CPU is <tt class="docutils literal">>90%</tt>, then status is set to <tt class="docutils literal">"CRITICAL"</tt></div>
|
||||
<div class="line">If user|system CPU is <tt class="docutils literal"><50%</tt>, then status is set to <tt class="docutils literal">"OK"</tt></div>
|
||||
<div class="line">If user|system CPU is <tt class="docutils literal">>50%</tt>, then status is set to <tt class="docutils literal">"CAREFUL"</tt></div>
|
||||
<div class="line">If user|system CPU is <tt class="docutils literal">>70%</tt>, then status is set to <tt class="docutils literal">"WARNING"</tt></div>
|
||||
<div class="line">If user|system CPU is <tt class="docutils literal">>90%</tt>, then status is set to <tt class="docutils literal">"CRITICAL"</tt></div>
|
||||
</div>
|
||||
<p><em>Note</em>: limit values can be overwritten in the configuration file under the <tt class="docutils literal">[cpu]</tt> section.</p>
|
||||
<p><em>Note</em>: limit values can be overwritten in the configuration file under
|
||||
the <tt class="docutils literal">[cpu]</tt> and/or <tt class="docutils literal">[percpu]</tt> sections.</p>
|
||||
</div>
|
||||
<div class="section" id="load">
|
||||
<h2><a class="toc-backref" href="#id19">Load</a></h2>
|
||||
<img alt="images/load.png" src="images/load.png" />
|
||||
<p>On the <em>No Sheep</em> blog, <em>Zachary Tirrell</em> defines the average load <a class="footnote-reference" href="#id4" id="id1">[1]</a>:</p>
|
||||
<p>On the <em>No Sheep</em> blog, <em>Zachary Tirrell</em> defines the load average <a class="footnote-reference" href="#id4" id="id1">[1]</a>:</p>
|
||||
<blockquote>
|
||||
"In short it is the average sum of the number of processes
|
||||
waiting in the run-queue plus the number currently executing
|
||||
over 1, 5, and 15 minute time periods."</blockquote>
|
||||
over 1, 5, and 15 minutes time periods."</blockquote>
|
||||
<p>Glances gets the number of CPU core to adapt the alerts.
|
||||
Alerts on average load are only set on 5 and 15 min.
|
||||
The first line also display the number of CPU core.</p>
|
||||
Alerts on load average are only set on 15 minutes time period.
|
||||
The first line also displays the number of CPU core.</p>
|
||||
<div class="line-block">
|
||||
<div class="line">If average load is <tt class="docutils literal"><0.7*core</tt>, then status is set to <tt class="docutils literal">"OK"</tt></div>
|
||||
<div class="line">If average load is <tt class="docutils literal">>0.7*core</tt>, then status is set to <tt class="docutils literal">"CAREFUL"</tt></div>
|
||||
<div class="line">If average load is <tt class="docutils literal">>1*core</tt>, then status is set to <tt class="docutils literal">"WARNING"</tt></div>
|
||||
<div class="line">If average load is <tt class="docutils literal">>5*core</tt>, then status is set to <tt class="docutils literal">"CRITICAL"</tt></div>
|
||||
<div class="line">If load average is <tt class="docutils literal"><0.7*core</tt>, then status is set to <tt class="docutils literal">"OK"</tt></div>
|
||||
<div class="line">If load average is <tt class="docutils literal">>0.7*core</tt>, then status is set to <tt class="docutils literal">"CAREFUL"</tt></div>
|
||||
<div class="line">If load average is <tt class="docutils literal">>1*core</tt>, then status is set to <tt class="docutils literal">"WARNING"</tt></div>
|
||||
<div class="line">If load average is <tt class="docutils literal">>5*core</tt>, then status is set to <tt class="docutils literal">"CRITICAL"</tt></div>
|
||||
</div>
|
||||
<p><em>Note</em>: limit values can be overwritten in the configuration file under the <tt class="docutils literal">[load]</tt> section.</p>
|
||||
<p><em>Note</em>: limit values can be overwritten in the configuration file under
|
||||
the <tt class="docutils literal">[load]</tt> section.</p>
|
||||
</div>
|
||||
<div class="section" id="memory">
|
||||
<h2><a class="toc-backref" href="#id20">Memory</a></h2>
|
||||
<p>Glances uses two columns: one for the <tt class="docutils literal">RAM</tt> and another one for the <tt class="docutils literal">Swap</tt>.</p>
|
||||
<p>Glances uses two columns: one for the <tt class="docutils literal">RAM</tt> and one for the <tt class="docutils literal">SWAP</tt>.</p>
|
||||
<img alt="images/mem.png" src="images/mem.png" />
|
||||
<p>If enough space is available, Glances displays extended informations:</p>
|
||||
<p>If enough space is available, Glances displays extended information for
|
||||
the <tt class="docutils literal">RAM</tt>:</p>
|
||||
<img alt="images/mem-wide.png" src="images/mem-wide.png" />
|
||||
<p>With Glances, alerts are only set for on used memory and used swap.</p>
|
||||
<p>Alerts are only set for used memory and used swap.</p>
|
||||
<div class="line-block">
|
||||
<div class="line">If memory is <tt class="docutils literal"><50%</tt>, then status is set to <tt class="docutils literal">"OK"</tt></div>
|
||||
<div class="line">If memory is <tt class="docutils literal">>50%</tt>, then status is set to <tt class="docutils literal">"CAREFUL"</tt></div>
|
||||
<div class="line">If memory is <tt class="docutils literal">>70%</tt>, then status is set to <tt class="docutils literal">"WARNING"</tt></div>
|
||||
<div class="line">If memory is <tt class="docutils literal">>90%</tt>, then status is set to <tt class="docutils literal">"CRITICAL"</tt></div>
|
||||
<div class="line">If used memory|swap is <tt class="docutils literal"><50%</tt>, then status is set to <tt class="docutils literal">"OK"</tt></div>
|
||||
<div class="line">If used memory|swap is <tt class="docutils literal">>50%</tt>, then status is set to <tt class="docutils literal">"CAREFUL"</tt></div>
|
||||
<div class="line">If used memory|swap is <tt class="docutils literal">>70%</tt>, then status is set to <tt class="docutils literal">"WARNING"</tt></div>
|
||||
<div class="line">If used memory|swap is <tt class="docutils literal">>90%</tt>, then status is set to <tt class="docutils literal">"CRITICAL"</tt></div>
|
||||
</div>
|
||||
<p><em>Note</em>: limit values can be overwritten in the configuration file under the <tt class="docutils literal">[memory]</tt> and <tt class="docutils literal">[swap]</tt> sections.</p>
|
||||
<p><em>Note</em>: limit values can be overwritten in the configuration file under
|
||||
the <tt class="docutils literal">[memory]</tt> and/or <tt class="docutils literal">[memswap]</tt> sections.</p>
|
||||
</div>
|
||||
<div class="section" id="network">
|
||||
<h2><a class="toc-backref" href="#id21">Network</a></h2>
|
||||
<img alt="images/network.png" src="images/network.png" />
|
||||
<p>Glances displays the network interface bit rate. The unit is adapted
|
||||
dynamically (bits per second, kbits per second, Mbits per second, etc).</p>
|
||||
<p>Alerts are only set if the network interface maximum speed is available.</p>
|
||||
<p>For example, on a 100 Mbps ethernet interface, the warning status is set
|
||||
if the bit rate is higher than 70 Mbps.</p>
|
||||
<div class="line-block">
|
||||
<div class="line">If bit rate is <tt class="docutils literal"><50%</tt>, then status is set to <tt class="docutils literal">"OK"</tt></div>
|
||||
<div class="line">If bit rate is <tt class="docutils literal">>50%</tt>, then status is set to <tt class="docutils literal">"CAREFUL"</tt></div>
|
||||
<div class="line">If bit rate is <tt class="docutils literal">>70%</tt>, then status is set to <tt class="docutils literal">"WARNING"</tt></div>
|
||||
<div class="line">If bit rate is <tt class="docutils literal">>90%</tt>, then status is set to <tt class="docutils literal">"CRITICAL"</tt></div>
|
||||
</div>
|
||||
<p><em>Note</em>: In the configuration file, you can define a list of network interfaces to hide.</p>
|
||||
</div>
|
||||
<div class="section" id="sensors">
|
||||
<h2><a class="toc-backref" href="#id22">Sensors</a></h2>
|
||||
<p>Glances can displays the sensors informations trough <cite>lm-sensors</cite> (only available on Linux).</p>
|
||||
<p>As of lm-sensors, a filter is processed in order to display temperature only:</p>
|
||||
<img alt="images/sensors.png" src="images/sensors.png" />
|
||||
<p>Glances can also grab hard disk temperature through the <cite>hddtemp</cite> daemon (see here <a class="footnote-reference" href="#id5" id="id2">[2]</a> to install hddtemp on your system):</p>
|
||||
<img alt="images/hddtemp.png" src="images/hddtemp.png" />
|
||||
<p>To enable the lm-sensors module:</p>
|
||||
<pre class="code console literal-block">
|
||||
<span class="generic prompt">$</span> glances -e
|
||||
</pre>
|
||||
<p>To enable the hddtemp module:</p>
|
||||
<pre class="code console literal-block">
|
||||
<span class="generic prompt">$</span> glances -y
|
||||
</pre>
|
||||
<p>There is no alert on this information.</p>
|
||||
<p><em>Note</em>: limit values can be overwritten in the configuration file under the <tt class="docutils literal">[temperature]</tt> and <tt class="docutils literal">[hddtemperature]</tt> sections.</p>
|
||||
<p>Alerts are only set if the maximum speed per network interface is available
|
||||
(see sample in the configuration file).</p>
|
||||
<p><em>Note</em>: it is possibile to define a list of network interfaces to hide
|
||||
and per-interface limit values in the <tt class="docutils literal">[network]</tt> section of the
|
||||
configuration file.</p>
|
||||
</div>
|
||||
<div class="section" id="disk-i-o">
|
||||
<h2><a class="toc-backref" href="#id23">Disk I/O</a></h2>
|
||||
<h2><a class="toc-backref" href="#id22">Disk I/O</a></h2>
|
||||
<img alt="images/diskio.png" src="images/diskio.png" />
|
||||
<p>Glances displays the disk I/O throughput. The unit is adapted dynamically.</p>
|
||||
<p><em>Note</em>: There is no alert on this information.</p>
|
||||
<p><em>Note</em>: In the configuration file, you can define a list of disk to hide.</p>
|
||||
<p>There is no alert on this information.</p>
|
||||
<p><em>Note</em>: it is possible to define a list of disks to hide under the
|
||||
<tt class="docutils literal">[diskio]</tt> section in the configuration file.</p>
|
||||
</div>
|
||||
<div class="section" id="file-system">
|
||||
<h2><a class="toc-backref" href="#id24">File system</a></h2>
|
||||
<h2><a class="toc-backref" href="#id23">File System</a></h2>
|
||||
<img alt="images/fs.png" src="images/fs.png" />
|
||||
<p>Glances displays the used and total file system disk space. The unit is
|
||||
adapted dynamically.</p>
|
||||
<p>Alerts are set for used disk space:</p>
|
||||
<p>Alerts are set for used disk space.</p>
|
||||
<div class="line-block">
|
||||
<div class="line">If disk used is <tt class="docutils literal"><50%</tt>, then status is set to <tt class="docutils literal">"OK"</tt></div>
|
||||
<div class="line">If disk used is <tt class="docutils literal">>50%</tt>, then status is set to <tt class="docutils literal">"CAREFUL"</tt></div>
|
||||
<div class="line">If disk used is <tt class="docutils literal">>70%</tt>, then status is set to <tt class="docutils literal">"WARNING"</tt></div>
|
||||
<div class="line">If disk used is <tt class="docutils literal">>90%</tt>, then status is set to <tt class="docutils literal">"CRITICAL"</tt></div>
|
||||
<div class="line">If used disk is <tt class="docutils literal"><50%</tt>, then status is set to <tt class="docutils literal">"OK"</tt></div>
|
||||
<div class="line">If used disk is <tt class="docutils literal">>50%</tt>, then status is set to <tt class="docutils literal">"CAREFUL"</tt></div>
|
||||
<div class="line">If used disk is <tt class="docutils literal">>70%</tt>, then status is set to <tt class="docutils literal">"WARNING"</tt></div>
|
||||
<div class="line">If used disk is <tt class="docutils literal">>90%</tt>, then status is set to <tt class="docutils literal">"CRITICAL"</tt></div>
|
||||
</div>
|
||||
<p><em>Note</em>: limit values can be overwritten in the configuration file under <tt class="docutils literal">[filesystem]</tt> section.</p>
|
||||
<p><em>Note</em>: limit values can be overwritten in the configuration file under
|
||||
the <tt class="docutils literal">[filesystem]</tt> section.</p>
|
||||
</div>
|
||||
<div class="section" id="sensors">
|
||||
<h2><a class="toc-backref" href="#id24">Sensors</a></h2>
|
||||
<p>Glances can displays the sensors information using <cite>lm-sensors</cite>,
|
||||
<cite>hddtemp</cite> and <cite>batinfo</cite> <a class="footnote-reference" href="#id5" id="id2">[2]</a>.</p>
|
||||
<p>All of the above libraries are available only on Linux.</p>
|
||||
<p>As of lm-sensors, a filter is being applied in order to display
|
||||
temperature only.</p>
|
||||
<img alt="images/sensors.png" src="images/sensors.png" />
|
||||
<p>There is no alert on this information.</p>
|
||||
<p><em>Note</em>: limit values can be overwritten in the configuration file under
|
||||
the <tt class="docutils literal">[sensors]</tt> section.</p>
|
||||
</div>
|
||||
<div class="section" id="processes-list">
|
||||
<h2><a class="toc-backref" href="#id25">Processes list</a></h2>
|
||||
<h2><a class="toc-backref" href="#id25">Processes List</a></h2>
|
||||
<p>Compact view:</p>
|
||||
<img alt="images/processlist.png" src="images/processlist.png" />
|
||||
<p>Full view:</p>
|
||||
@ -499,7 +569,7 @@ adapted dynamically.</p>
|
||||
<p>Three views are available for processes:</p>
|
||||
<ul class="simple">
|
||||
<li>Processes summary</li>
|
||||
<li>Optional monitored processes list (new in 1.7)</li>
|
||||
<li>Optional monitored processes list (see below)</li>
|
||||
<li>Processes list</li>
|
||||
</ul>
|
||||
<p>The processes summary line display:</p>
|
||||
@ -509,78 +579,91 @@ adapted dynamically.</p>
|
||||
<li>Running tasks number</li>
|
||||
<li>Sleeping tasks number</li>
|
||||
<li>Other tasks number (not running or sleeping)</li>
|
||||
<li>Sort key</li>
|
||||
</ul>
|
||||
<p>By default, or if you hit the <tt class="docutils literal">a</tt> key, the processes list is
|
||||
automatically sorted by:</p>
|
||||
<ul class="simple">
|
||||
<li><tt class="docutils literal">CPU</tt> if there is no alert (default behavior)</li>
|
||||
<li><tt class="docutils literal">CPU</tt> if a CPU or LOAD alert is detected</li>
|
||||
<li><tt class="docutils literal">MEM</tt> if a memory alert is detected</li>
|
||||
<li><tt class="docutils literal">Disk I/O</tt> if a CPU iowait alert is detected</li>
|
||||
</ul>
|
||||
<p>By default, or if you hit the <tt class="docutils literal">a</tt> key, the processes list is automatically
|
||||
sorted by CPU of memory usage.</p>
|
||||
<p><em>Note</em>: limit values can be overwritten in the configuration file under the <tt class="docutils literal">[process]</tt> section.</p>
|
||||
<p>The number of processes in the list is adapted to the screen size.</p>
|
||||
<dl class="docutils">
|
||||
<dt><tt class="docutils literal">VIRT</tt></dt>
|
||||
<dd>Total program size (VMS)</dd>
|
||||
<dt><tt class="docutils literal">RES</tt></dt>
|
||||
<dd>Resident set size (RSS)</dd>
|
||||
<dt><tt class="docutils literal">CPU%</tt></dt>
|
||||
<dd>% of CPU used by the process</dd>
|
||||
<dt><tt class="docutils literal">MEM%</tt></dt>
|
||||
<dd>% of MEM used by the process</dd>
|
||||
<dt><tt class="docutils literal">VIRT</tt></dt>
|
||||
<dd>Total program size aka Virtual Memory Size (VMS)</dd>
|
||||
<dt><tt class="docutils literal">RES</tt></dt>
|
||||
<dd>Resident Set Size (RSS)</dd>
|
||||
<dt><tt class="docutils literal">PID</tt></dt>
|
||||
<dd>Process ID</dd>
|
||||
<dt><tt class="docutils literal">USER</tt></dt>
|
||||
<dd>User ID per process</dd>
|
||||
<dd>User ID</dd>
|
||||
<dt><tt class="docutils literal">NI</tt></dt>
|
||||
<dd>Nice level of the process</dd>
|
||||
<dd>Nice level of the process (niceness other than 0 is highlighted)</dd>
|
||||
<dt><tt class="docutils literal">S</tt></dt>
|
||||
<dd>Process status</dd>
|
||||
<dd>Process status (running process is highlighted)</dd>
|
||||
<dt><tt class="docutils literal">TIME+</tt></dt>
|
||||
<dd>Cumulative CPU time used</dd>
|
||||
<dt><tt class="docutils literal">IOR/s</tt></dt>
|
||||
<dd>Per process IO read rate (in Byte/s)</dd>
|
||||
<dd>Per process I/O read rate (in Byte/s)</dd>
|
||||
<dt><tt class="docutils literal">IOW/s</tt></dt>
|
||||
<dd>Per process IO write rate (in Byte/s)</dd>
|
||||
<dt><tt class="docutils literal">NAME</tt></dt>
|
||||
<dd>Process name or command line</dd>
|
||||
<dd>Per process I/O write rate (in Byte/s)</dd>
|
||||
<dt><tt class="docutils literal">COMMAND</tt></dt>
|
||||
<dd>Process command line (process name is highlighted)</dd>
|
||||
</dl>
|
||||
<p>Process status legend:</p>
|
||||
<dl class="docutils">
|
||||
<dt><tt class="docutils literal">R</tt></dt>
|
||||
<dd>running</dd>
|
||||
<dd>Running</dd>
|
||||
<dt><tt class="docutils literal">S</tt></dt>
|
||||
<dd>sleeping (may be interrupted)</dd>
|
||||
<dd>Sleeping (may be interrupted)</dd>
|
||||
<dt><tt class="docutils literal">D</tt></dt>
|
||||
<dd>disk sleep (may not be interrupted)</dd>
|
||||
<dd>Disk sleep (may not be interrupted)</dd>
|
||||
<dt><tt class="docutils literal">T</tt></dt>
|
||||
<dd>traced/stopped</dd>
|
||||
<dd>Traced / Stopped</dd>
|
||||
<dt><tt class="docutils literal">Z</tt></dt>
|
||||
<dd>zombie</dd>
|
||||
<dd>Zombie</dd>
|
||||
</dl>
|
||||
<p><em>Note</em>: limits values can be overwritten in the configuration file under
|
||||
the <tt class="docutils literal">[process]</tt> section.</p>
|
||||
</div>
|
||||
<div class="section" id="monitored-processes-list">
|
||||
<h2><a class="toc-backref" href="#id26">Monitored processes list</a></h2>
|
||||
<p>New in version 1.7. Optional.</p>
|
||||
<h2><a class="toc-backref" href="#id26">Monitored Processes List</a></h2>
|
||||
<p>The monitored processes list allows user, through the configuration file,
|
||||
to group processes and quickly show if the number of running process is not good.</p>
|
||||
to group processes and quickly show if the number of running processes is
|
||||
not good.</p>
|
||||
<img alt="images/monitored.png" src="images/monitored.png" />
|
||||
<p>Each item is defined by:</p>
|
||||
<ul class="simple">
|
||||
<li><tt class="docutils literal">description</tt>: description of the processes (max 16 chars).</li>
|
||||
<li><tt class="docutils literal">regex</tt>: regular expression of the processes to monitor.</li>
|
||||
<li><tt class="docutils literal">command</tt> (optional): full path to shell command/script for extended stat. Should return a single line string. Use with caution.</li>
|
||||
<li><tt class="docutils literal">countmin</tt> (optional): minimal number of processes. A warning will be displayed if number of processes < count.</li>
|
||||
<li><tt class="docutils literal">countmax</tt> (optional): maximum number of processes. A warning will be displayed if number of processes > count.</li>
|
||||
<li><tt class="docutils literal">command</tt> (optional): full path to shell command/script for extended
|
||||
stat. Should return a single line string. Use with caution.</li>
|
||||
<li><tt class="docutils literal">countmin</tt> (optional): minimal number of processes. A warning will
|
||||
be displayed if number of processes < count.</li>
|
||||
<li><tt class="docutils literal">countmax</tt> (optional): maximum number of processes. A warning will
|
||||
be displayed if number of processes > count.</li>
|
||||
</ul>
|
||||
<p>Up to 10 items can be defined.</p>
|
||||
<p>For example, if you want to monitor the Nginx processes on a Web server, the following definition should do the job:</p>
|
||||
<pre class="code console literal-block">
|
||||
<span class="generic output">[monitor]
|
||||
<p>For example, if you want to monitor the Nginx processes on a Web server,
|
||||
the following definition should do the job:</p>
|
||||
<pre class="literal-block">
|
||||
[monitor]
|
||||
list_1_description=Nginx server
|
||||
list_1_regex=.*nginx.*
|
||||
list_1_command=nginx -v
|
||||
list_1_countmin=1
|
||||
list_1_countmax=4</span>
|
||||
list_1_countmax=4
|
||||
</pre>
|
||||
<p>If you also want to monitor the PHP-FPM daemon processes, you should add another item:</p>
|
||||
<pre class="code console literal-block">
|
||||
<span class="generic output">[monitor]
|
||||
<p>If you also want to monitor the PHP-FPM daemon processes, you should add
|
||||
another item:</p>
|
||||
<pre class="literal-block">
|
||||
[monitor]
|
||||
list_1_description=Nginx server
|
||||
list_1_regex=.*nginx.*
|
||||
list_1_command=nginx -v
|
||||
@ -589,10 +672,11 @@ list_1_countmax=4
|
||||
list_1_description=PHP-FPM
|
||||
list_1_regex=.*php-fpm.*
|
||||
list_1_countmin=1
|
||||
list_1_countmax=20</span>
|
||||
list_1_countmax=20
|
||||
</pre>
|
||||
<p>In client/server mode, the list is defined on the server side.
|
||||
A new method, called getAllMonitored, is available in the APIs and get the JSON representation of the monitored processes list.</p>
|
||||
A new method, called <cite>getAllMonitored</cite>, is available in the APIs and
|
||||
get the JSON representation of the monitored processes list.</p>
|
||||
<p>Alerts are set as following:</p>
|
||||
<div class="line-block">
|
||||
<div class="line">If number of processes is 0, then status is set to <tt class="docutils literal">"CRITICAL"</tt></div>
|
||||
@ -603,40 +687,42 @@ A new method, called getAllMonitored, is available in the APIs and get the JSON
|
||||
<div class="section" id="logs">
|
||||
<h2><a class="toc-backref" href="#id27">Logs</a></h2>
|
||||
<img alt="images/logs.png" src="images/logs.png" />
|
||||
<p>A log messages list is displayed in the bottom of the screen if (and only if):</p>
|
||||
<p>A log messages list is displayed in the bottom of the screen if (and
|
||||
only if):</p>
|
||||
<ul class="simple">
|
||||
<li>at least one <tt class="docutils literal">WARNING</tt> or <tt class="docutils literal">CRITICAL</tt> alert was occurred</li>
|
||||
<li>space is available in the bottom of the console/terminal</li>
|
||||
</ul>
|
||||
<p>Each alert message displays the following information:</p>
|
||||
<ol class="arabic simple">
|
||||
<li>start date</li>
|
||||
<li>end date</li>
|
||||
<li>start datetime</li>
|
||||
<li>duration if alert is terminated or <cite>ongoing</cite> if the alert is still in
|
||||
progress</li>
|
||||
<li>alert name</li>
|
||||
<li>{min/avg/max} values or number of running processes for monitored processes list alerts</li>
|
||||
<li>{min,avg,max} values or number of running processes for monitored
|
||||
processes list alerts</li>
|
||||
</ol>
|
||||
</div>
|
||||
<div class="section" id="footer">
|
||||
<h2><a class="toc-backref" href="#id28">Footer</a></h2>
|
||||
<img alt="images/footer.png" src="images/footer.png" />
|
||||
<p>Glances displays the current date & time and access to the embedded help screen.</p>
|
||||
<p>If one or mode batteries were found on your machine and if the batinfo Python library <a class="footnote-reference" href="#id6" id="id3">[3]</a>
|
||||
is installed on your system then Glances displays the available percent capacity in the middle on the footer.</p>
|
||||
<img alt="images/battery.png" src="images/battery.png" />
|
||||
<p>If you have ran Glances in client mode <tt class="docutils literal"><span class="pre">-c</span></tt>, you can also see if the client is connected to the server.</p>
|
||||
<p>If client is connected:</p>
|
||||
<img alt="images/client-connected.png" src="images/client-connected.png" />
|
||||
<p>else:</p>
|
||||
<img alt="images/client-disconnected.png" src="images/client-disconnected.png" />
|
||||
<p>On the left, you can easily see if you are connected to a Glances server.</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="section" id="api-documentation">
|
||||
<h1><a class="toc-backref" href="#id29">API documentation</a></h1>
|
||||
<p>Glances uses a <a class="reference external" href="http://docs.python.org/2/library/simplexmlrpcserver.html">XML-RPC server</a> and can be used by another client software.</p>
|
||||
<p>API documentation is available at <a class="reference external" href="https://github.com/nicolargo/glances/wiki/The-Glances-API-How-To">https://github.com/nicolargo/glances/wiki/The-Glances-API-How-To</a></p>
|
||||
</div>
|
||||
<div class="section" id="other-outputs">
|
||||
<h1><a class="toc-backref" href="#id28">Other Outputs</a></h1>
|
||||
<p>It is possible to export statistics to CSV file.</p>
|
||||
<pre class="code console literal-block">
|
||||
<span class="generic prompt">$</span> glances --output-csv /tmp/glances.csv
|
||||
</pre>
|
||||
<p>CSV files have two lines per stats:</p>
|
||||
<ul class="simple">
|
||||
<li>Stats description</li>
|
||||
<li>Stats (comma separated)</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="section" id="api-documentation">
|
||||
<h1><a class="toc-backref" href="#id29">API Documentation</a></h1>
|
||||
<p>Glances uses a <a class="reference external" href="http://docs.python.org/2/library/simplexmlrpcserver.html">XML-RPC server</a> and can be used by another client software.</p>
|
||||
<p><<<<<<< HEAD
|
||||
API documentation is available at <a class="reference external" href="https://github.com/nicolargo/glances/wiki/The-Glances-API-How-To">https://github.com/nicolargo/glances/wiki/The-Glances-API-How-To</a></p>
|
||||
</div>
|
||||
<div class="section" id="id3">
|
||||
<h1><a class="toc-backref" href="#id30">Other outputs</a></h1>
|
||||
<p>Thanks to the -o (output) option, it is possible to export statistics to <cite>CSV</cite> or <cite>HTML</cite> files.</p>
|
||||
<pre class="code console literal-block">
|
||||
@ -654,11 +740,25 @@ is installed on your system then Glances displays the available percent capacity
|
||||
<span class="generic prompt">$</span> glances -o HTML -f /tmp
|
||||
</pre>
|
||||
<p>The HTML output file is named <tt class="docutils literal">glances.html</tt>.</p>
|
||||
<p><em>Note</em>: The css and img folders (glances/data) should be in the /tmp folder.</p>
|
||||
</div>
|
||||
<div class="section" id="note-the-css-and-img-folders-glances-data-should-be-in-the-tmp-folder">
|
||||
<h1><a class="toc-backref" href="#id31"><em>Note</em>: The css and img folders (glances/data) should be in the /tmp folder.</a></h1>
|
||||
<div class="system-message">
|
||||
<p class="system-message-title">System Message: WARNING/2 (<tt class="docutils">./docs/glances-doc.rst</tt>, line 628)</p>
|
||||
<p>Title underline too short.</p>
|
||||
<pre class="literal-block">
|
||||
*Note*: The css and img folders (glances/data) should be in the /tmp folder.
|
||||
=======
|
||||
</pre>
|
||||
</div>
|
||||
<p>API documentation is available at
|
||||
<a class="reference external" href="https://github.com/nicolargo/glances/wiki/The-Glances-2.x-API-How-to">https://github.com/nicolargo/glances/wiki/The-Glances-2.x-API-How-to</a>.
|
||||
>>>>>>> release/v2.0</p>
|
||||
</div>
|
||||
<div class="section" id="support">
|
||||
<h1><a class="toc-backref" href="#id31">Support</a></h1>
|
||||
<p>To report a bug or a feature request use the bug tracking system at <a class="reference external" href="https://github.com/nicolargo/glances/issues">https://github.com/nicolargo/glances/issues</a></p>
|
||||
<h1><a class="toc-backref" href="#id32">Support</a></h1>
|
||||
<p>To report a bug or a feature request use the bug tracking system at
|
||||
<a class="reference external" href="https://github.com/nicolargo/glances/issues">https://github.com/nicolargo/glances/issues</a>.</p>
|
||||
<p>Feel free to contribute!</p>
|
||||
<table class="docutils footnote" frame="void" id="id4" rules="none">
|
||||
<colgroup><col class="label" /><col /></colgroup>
|
||||
@ -669,13 +769,7 @@ is installed on your system then Glances displays the available percent capacity
|
||||
<table class="docutils footnote" frame="void" id="id5" rules="none">
|
||||
<colgroup><col class="label" /><col /></colgroup>
|
||||
<tbody valign="top">
|
||||
<tr><td class="label"><a class="fn-backref" href="#id2">[2]</a></td><td><a class="reference external" href="http://www.cyberciti.biz/tips/howto-monitor-hard-drive-temperature.html">http://www.cyberciti.biz/tips/howto-monitor-hard-drive-temperature.html</a></td></tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<table class="docutils footnote" frame="void" id="id6" rules="none">
|
||||
<colgroup><col class="label" /><col /></colgroup>
|
||||
<tbody valign="top">
|
||||
<tr><td class="label"><a class="fn-backref" href="#id3">[3]</a></td><td><a class="reference external" href="https://github.com/nicolargo/batinfo">https://github.com/nicolargo/batinfo</a></td></tr>
|
||||
<tr><td class="label"><a class="fn-backref" href="#id2">[2]</a></td><td><a class="reference external" href="https://github.com/nicolargo/batinfo">https://github.com/nicolargo/batinfo</a></td></tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
@ -2,25 +2,28 @@
|
||||
Glances
|
||||
=======
|
||||
|
||||
This manual describes *Glances* version 1.7.7.
|
||||
This manual describes *Glances* version 2.0.
|
||||
|
||||
Copyright © 2012-2014 Nicolas Hennion <nicolas@nicolargo.com>
|
||||
|
||||
May 2014
|
||||
June 2014
|
||||
|
||||
.. contents:: Table of Contents
|
||||
|
||||
Introduction
|
||||
============
|
||||
|
||||
Glances is a cross-platform curses-based monitoring tool which aims to
|
||||
present a maximum of information in a minimum of space, ideally to fit
|
||||
in a classical 80x24 terminal or higher to have additional information.
|
||||
Glances is a cross-platform curses-based system monitoring tool which
|
||||
aims to present a maximum of information in a minimum of space, ideally
|
||||
to fit in a classical 80x24 terminal or higher to have additional
|
||||
information. It can adapt dynamically the displayed information depending
|
||||
on the terminal size.
|
||||
|
||||
Glances can adapt dynamically the displayed information depending on the
|
||||
terminal size. It can also work in a client/server mode for remote monitoring.
|
||||
Glances can also work in client/server mode. Remote monitoring could be
|
||||
done via terminal or web interface.
|
||||
|
||||
Glances is written in Python and uses the `psutil`_ library to get information from your system.
|
||||
Glances is written in Python and uses the `psutil`_ library to get
|
||||
information from your system.
|
||||
|
||||
Console (80x24)
|
||||
|
||||
@ -30,10 +33,14 @@ Full view (>80x24)
|
||||
|
||||
.. image:: images/screenshot-wide.png
|
||||
|
||||
Web interface (Firefox)
|
||||
|
||||
.. image:: images/screenshot-web.png
|
||||
|
||||
Usage
|
||||
=====
|
||||
|
||||
Standalone mode
|
||||
Standalone Mode
|
||||
---------------
|
||||
|
||||
Simply run:
|
||||
@ -42,11 +49,11 @@ Simply run:
|
||||
|
||||
$ glances
|
||||
|
||||
Client/Server mode
|
||||
Client/Server Mode
|
||||
------------------
|
||||
|
||||
If you want to remotely monitor a machine, called ``server``, from another one, called ``client``,
|
||||
just run on the server:
|
||||
If you want to remotely monitor a machine, called ``server``, from
|
||||
another one, called ``client``, just run on the server:
|
||||
|
||||
.. code-block:: console
|
||||
|
||||
@ -60,52 +67,104 @@ and on the client:
|
||||
|
||||
where ``@server`` is the IP address or hostname of the server.
|
||||
|
||||
In server mode, you can set the bind address ``-B ADDRESS`` and listening TCP port ``-p PORT``.
|
||||
In server mode, you can set the bind address ``-B ADDRESS`` and listening
|
||||
TCP port ``-p PORT``.
|
||||
|
||||
In client mode, you can set the TCP port of the server ``-p PORT``.
|
||||
|
||||
Default binding address is ``0.0.0.0`` (Glances will listen on all the network interfaces) and TCP port is ``61209``.
|
||||
You can also set a password to access to the server ``--password``.
|
||||
|
||||
Default binding address is ``0.0.0.0`` (Glances will listen on all the
|
||||
network interfaces) and TCP port is ``61209``.
|
||||
|
||||
In client/server mode, limits are set by the server side.
|
||||
|
||||
You can also set a password to access to the server ``-P password``.
|
||||
Glances is ``IPv6`` compatible. Just use the ``-B ::`` option to bind to
|
||||
all IPv6 addresses.
|
||||
|
||||
Glances is ``IPv6`` compatible. Just use the ``-B ::`` option to bind to all IPv6 addresses.
|
||||
As an experimental feature, if Glances server is not detected by the
|
||||
client, the latter will try to grab stats using the ``SNMP`` protocol:
|
||||
|
||||
Command reference
|
||||
.. code-block:: console
|
||||
|
||||
client$ glances -c @snmpserver
|
||||
|
||||
Known issues: grab using SNMP is only validated for GNU/Linux with SNMP
|
||||
v2/2c server.
|
||||
|
||||
Web Server Mode
|
||||
---------------
|
||||
|
||||
If you want to remotely monitor a machine, called ``server``, from any
|
||||
device with a web browser, called ``client``, just run on the server:
|
||||
|
||||
.. code-block:: console
|
||||
|
||||
server$ glances -w
|
||||
|
||||
and on the client enter the following URL in your favorite web browser:
|
||||
|
||||
::
|
||||
|
||||
http://@server:61208
|
||||
|
||||
where ``@server`` is the IP address or hostname of the server.
|
||||
|
||||
The Glances web interface follows responsive web design principles.
|
||||
|
||||
Screenshot from Chrome on Android
|
||||
|
||||
.. image:: images/screenshot-web2.png
|
||||
|
||||
|
||||
Command Reference
|
||||
=================
|
||||
|
||||
Command-line options
|
||||
Command-Line Options
|
||||
--------------------
|
||||
|
||||
-b Display network rate in Byte per second (default: bit per second)
|
||||
-B IP Bind server to the given IPv4/IPv6 address or hostname
|
||||
-c IP Connect to a Glances server by IPv4/IPv6 address or hostname
|
||||
-C FILE Path to the configuration file
|
||||
-d Disable disk I/O module
|
||||
-e Enable sensors module (requires pysensors, Linux-only)
|
||||
-f FOLDER Set the HTML or CSV output folder
|
||||
-h Display the help and exit
|
||||
-m Disable mount module
|
||||
-n Disable network module
|
||||
-o OUTPUT Define additional output (available: HTML or CSV)
|
||||
-p PORT Define the client/server TCP port (default: 61209)
|
||||
-P PASSWORD Define a client/server password
|
||||
--password Define a client/server password from the prompt
|
||||
-r Disable process list (for low CPU consumption)
|
||||
-s Run Glances in server mode
|
||||
-t SECONDS Set refresh time in seconds (default: 3 sec)
|
||||
-v Display the version and exit
|
||||
-y Enable hddtemp module (requires hddtemp)
|
||||
-z Do not use the bold color attribute
|
||||
-1 Start Glances in per-CPU mode
|
||||
-h, --help show this help message and exit
|
||||
-V, --version show program's version number and exit
|
||||
-b, --byte display network rate in byte per second
|
||||
-B BIND_ADDRESS, --bind BIND_ADDRESS
|
||||
bind server to the given IPv4/IPv6 address or hostname
|
||||
-c CLIENT, --client CLIENT
|
||||
connect to a Glances server by IPv4/IPv6 address or
|
||||
hostname
|
||||
-C CONF_FILE, --config CONF_FILE
|
||||
path to the configuration file
|
||||
--disable-bold disable bold mode in the terminal
|
||||
--disable-diskio disable disk I/O module
|
||||
--disable-fs disable file system module
|
||||
--disable-network disable network module
|
||||
--disable-sensors disable sensors module
|
||||
--disable-process disable process module
|
||||
--disable-log disable log module
|
||||
--output-csv OUTPUT_CSV
|
||||
export stats to a CSV file
|
||||
-p PORT, --port PORT define the client/server TCP port [default: 61209]
|
||||
--password define a client/server password from the prompt or
|
||||
file
|
||||
-s, --server run Glances in server mode
|
||||
--snmp-community SNMP_COMMUNITY
|
||||
SNMP community
|
||||
--snmp-port SNMP_PORT
|
||||
SNMP port
|
||||
--snmp-version SNMP_VERSION
|
||||
SNMP version (1, 2c or 3)
|
||||
--snmp-user SNMP_USER
|
||||
SNMP username (only for SNMPv3)
|
||||
--snmp-auth SNMP_AUTH
|
||||
SNMP authentication key (only for SNMPv3)
|
||||
-t TIME, --time TIME set refresh time in seconds [default: 3 sec]
|
||||
-w, --webserver run Glances in Web server mode
|
||||
-1, --percpu start Glances in per CPU mode
|
||||
|
||||
Interactive commands
|
||||
Interactive Commands
|
||||
--------------------
|
||||
|
||||
The following commands (key pressed) are supported while in Glances:
|
||||
|
||||
|
||||
``a``
|
||||
Sort process list automatically
|
||||
|
||||
@ -123,7 +182,7 @@ The following commands (key pressed) are supported while in Glances:
|
||||
``h``
|
||||
Show/hide the help screen
|
||||
``i``
|
||||
Sort processes by I/O rate (may need root privileges on some OSes)
|
||||
Sort processes by I/O rate
|
||||
``l``
|
||||
Show/hide log messages
|
||||
``m``
|
||||
@ -135,7 +194,7 @@ The following commands (key pressed) are supported while in Glances:
|
||||
``q``
|
||||
Quit
|
||||
``s``
|
||||
Show/hide sensors stats (only available with -e flag)
|
||||
Show/hide sensors stats
|
||||
``t``
|
||||
View network I/O as combination
|
||||
``u``
|
||||
@ -144,19 +203,21 @@ The following commands (key pressed) are supported while in Glances:
|
||||
Delete finished warning log messages
|
||||
``x``
|
||||
Delete finished warning and critical log messages
|
||||
``y``
|
||||
Show/hide hddtemp stats (only available with -y flag)
|
||||
``z``
|
||||
Show/hide processes list (for low CPU consumption)
|
||||
Show/hide processes stats
|
||||
``1``
|
||||
Switch between global CPU and per-CPU stats
|
||||
|
||||
Configuration
|
||||
=============
|
||||
|
||||
**Caution! Glances version 1.x configuration files are not compatible
|
||||
with the version 2.x.**
|
||||
|
||||
No configuration file is mandatory to use Glances.
|
||||
|
||||
Furthermore a configuration file is needed for setup limits, disks or network interfaces to hide and/or monitored processes list.
|
||||
Furthermore a configuration file is needed to set up limits, disks or
|
||||
network interfaces to hide and/or monitored processes list.
|
||||
|
||||
By default, the configuration file is under:
|
||||
|
||||
@ -166,29 +227,31 @@ By default, the configuration file is under:
|
||||
|
||||
On Windows XP, the ``%APPDATA%`` path is:
|
||||
|
||||
.. code-block:: console
|
||||
::
|
||||
|
||||
C:\Documents and Settings\<User>\Application Data
|
||||
|
||||
Since Windows Vista and newer versions:
|
||||
|
||||
.. code-block:: console
|
||||
::
|
||||
|
||||
C:\Users\<User>\AppData\Roaming
|
||||
|
||||
You can override the default configuration, located in one of the above
|
||||
directories on your system, except for Windows.
|
||||
|
||||
Just copy the ``glances.conf`` file to your ``$XDG_CONFIG_HOME`` directory, e.g. Linux:
|
||||
Just copy the ``glances.conf`` file to your ``$XDG_CONFIG_HOME`` directory,
|
||||
e.g., on Linux:
|
||||
|
||||
.. code-block:: console
|
||||
|
||||
mkdir -p $XDG_CONFIG_HOME/glances
|
||||
cp /etc/glances/glances.conf $XDG_CONFIG_HOME/glances/
|
||||
cp /usr/share/doc/glances/glances.conf $XDG_CONFIG_HOME/glances/
|
||||
|
||||
On OS X, you should copy the configuration file to ``~/Library/Application Support/glances/``.
|
||||
On OS X, you should copy the configuration file to
|
||||
``~/Library/Application Support/glances/``.
|
||||
|
||||
Anatomy of the application
|
||||
Anatomy Of The Application
|
||||
==========================
|
||||
|
||||
Legend
|
||||
@ -199,13 +262,27 @@ Legend
|
||||
| ``MAGENTA`` stat counter is ``"WARNING"``
|
||||
| ``RED`` stat counter is ``"CRITICAL"``
|
||||
|
||||
*Note*: only stats with colored background will be logged in the alert
|
||||
view.
|
||||
|
||||
Header
|
||||
------
|
||||
|
||||
.. image:: images/header.png
|
||||
|
||||
The header shows the hostname, OS name, release version, platform architecture and system uptime.
|
||||
On Linux, it shows also the kernel version.
|
||||
The header shows the hostname, OS name, release version, platform
|
||||
architecture and system uptime (on the upper right corner).
|
||||
Additionally, on GNU/Linux, it also shows the kernel version.
|
||||
|
||||
In client mode, the server connection status is displayed.
|
||||
|
||||
Connected:
|
||||
|
||||
.. image:: images/connected.png
|
||||
|
||||
Disconnected:
|
||||
|
||||
.. image:: images/disconnected.png
|
||||
|
||||
CPU
|
||||
---
|
||||
@ -214,7 +291,8 @@ Short view:
|
||||
|
||||
.. image:: images/cpu.png
|
||||
|
||||
If enough horizontal space is available, extended CPU informations are displayed.
|
||||
If enough horizontal space is available, extended CPU information are
|
||||
displayed.
|
||||
|
||||
Extended view:
|
||||
|
||||
@ -224,57 +302,61 @@ To switch to per-CPU stats, just hit the ``1`` key:
|
||||
|
||||
.. image:: images/per-cpu.png
|
||||
|
||||
The CPU stats are shown as a percentage and for the configured refresh time.
|
||||
The total CPU usage is displayed on the first line.
|
||||
The CPU stats are shown as a percentage and for the configured refresh
|
||||
time. The total CPU usage is displayed on the first line.
|
||||
|
||||
| If user|system|nice CPU is ``<50%``, then status is set to ``"OK"``
|
||||
| If user|system|nice CPU is ``>50%``, then status is set to ``"CAREFUL"``
|
||||
| If user|system|nice CPU is ``>70%``, then status is set to ``"WARNING"``
|
||||
| If user|system|nice CPU is ``>90%``, then status is set to ``"CRITICAL"``
|
||||
| If user|system CPU is ``<50%``, then status is set to ``"OK"``
|
||||
| If user|system CPU is ``>50%``, then status is set to ``"CAREFUL"``
|
||||
| If user|system CPU is ``>70%``, then status is set to ``"WARNING"``
|
||||
| If user|system CPU is ``>90%``, then status is set to ``"CRITICAL"``
|
||||
|
||||
*Note*: limit values can be overwritten in the configuration file under the ``[cpu]`` section.
|
||||
*Note*: limit values can be overwritten in the configuration file under
|
||||
the ``[cpu]`` and/or ``[percpu]`` sections.
|
||||
|
||||
Load
|
||||
----
|
||||
|
||||
.. image:: images/load.png
|
||||
|
||||
On the *No Sheep* blog, *Zachary Tirrell* defines the average load [1]_:
|
||||
On the *No Sheep* blog, *Zachary Tirrell* defines the load average [1]_:
|
||||
|
||||
"In short it is the average sum of the number of processes
|
||||
waiting in the run-queue plus the number currently executing
|
||||
over 1, 5, and 15 minute time periods."
|
||||
over 1, 5, and 15 minutes time periods."
|
||||
|
||||
Glances gets the number of CPU core to adapt the alerts.
|
||||
Alerts on average load are only set on 5 and 15 min.
|
||||
The first line also display the number of CPU core.
|
||||
Alerts on load average are only set on 15 minutes time period.
|
||||
The first line also displays the number of CPU core.
|
||||
|
||||
| If average load is ``<0.7*core``, then status is set to ``"OK"``
|
||||
| If average load is ``>0.7*core``, then status is set to ``"CAREFUL"``
|
||||
| If average load is ``>1*core``, then status is set to ``"WARNING"``
|
||||
| If average load is ``>5*core``, then status is set to ``"CRITICAL"``
|
||||
| If load average is ``<0.7*core``, then status is set to ``"OK"``
|
||||
| If load average is ``>0.7*core``, then status is set to ``"CAREFUL"``
|
||||
| If load average is ``>1*core``, then status is set to ``"WARNING"``
|
||||
| If load average is ``>5*core``, then status is set to ``"CRITICAL"``
|
||||
|
||||
*Note*: limit values can be overwritten in the configuration file under the ``[load]`` section.
|
||||
*Note*: limit values can be overwritten in the configuration file under
|
||||
the ``[load]`` section.
|
||||
|
||||
Memory
|
||||
------
|
||||
|
||||
Glances uses two columns: one for the ``RAM`` and another one for the ``Swap``.
|
||||
Glances uses two columns: one for the ``RAM`` and one for the ``SWAP``.
|
||||
|
||||
.. image:: images/mem.png
|
||||
|
||||
If enough space is available, Glances displays extended informations:
|
||||
If enough space is available, Glances displays extended information for
|
||||
the ``RAM``:
|
||||
|
||||
.. image:: images/mem-wide.png
|
||||
|
||||
With Glances, alerts are only set for on used memory and used swap.
|
||||
Alerts are only set for used memory and used swap.
|
||||
|
||||
| If memory is ``<50%``, then status is set to ``"OK"``
|
||||
| If memory is ``>50%``, then status is set to ``"CAREFUL"``
|
||||
| If memory is ``>70%``, then status is set to ``"WARNING"``
|
||||
| If memory is ``>90%``, then status is set to ``"CRITICAL"``
|
||||
| If used memory|swap is ``<50%``, then status is set to ``"OK"``
|
||||
| If used memory|swap is ``>50%``, then status is set to ``"CAREFUL"``
|
||||
| If used memory|swap is ``>70%``, then status is set to ``"WARNING"``
|
||||
| If used memory|swap is ``>90%``, then status is set to ``"CRITICAL"``
|
||||
|
||||
*Note*: limit values can be overwritten in the configuration file under the ``[memory]`` and ``[swap]`` sections.
|
||||
*Note*: limit values can be overwritten in the configuration file under
|
||||
the ``[memory]`` and/or ``[memswap]`` sections.
|
||||
|
||||
Network
|
||||
-------
|
||||
@ -284,47 +366,12 @@ Network
|
||||
Glances displays the network interface bit rate. The unit is adapted
|
||||
dynamically (bits per second, kbits per second, Mbits per second, etc).
|
||||
|
||||
Alerts are only set if the network interface maximum speed is available.
|
||||
Alerts are only set if the maximum speed per network interface is available
|
||||
(see sample in the configuration file).
|
||||
|
||||
For example, on a 100 Mbps ethernet interface, the warning status is set
|
||||
if the bit rate is higher than 70 Mbps.
|
||||
|
||||
| If bit rate is ``<50%``, then status is set to ``"OK"``
|
||||
| If bit rate is ``>50%``, then status is set to ``"CAREFUL"``
|
||||
| If bit rate is ``>70%``, then status is set to ``"WARNING"``
|
||||
| If bit rate is ``>90%``, then status is set to ``"CRITICAL"``
|
||||
|
||||
*Note*: In the configuration file, you can define a list of network interfaces to hide.
|
||||
|
||||
Sensors
|
||||
-------
|
||||
|
||||
Glances can displays the sensors informations trough `lm-sensors` (only available on Linux).
|
||||
|
||||
As of lm-sensors, a filter is processed in order to display temperature only:
|
||||
|
||||
.. image:: images/sensors.png
|
||||
|
||||
|
||||
Glances can also grab hard disk temperature through the `hddtemp` daemon (see here [2]_ to install hddtemp on your system):
|
||||
|
||||
.. image:: images/hddtemp.png
|
||||
|
||||
To enable the lm-sensors module:
|
||||
|
||||
.. code-block:: console
|
||||
|
||||
$ glances -e
|
||||
|
||||
To enable the hddtemp module:
|
||||
|
||||
.. code-block:: console
|
||||
|
||||
$ glances -y
|
||||
|
||||
There is no alert on this information.
|
||||
|
||||
*Note*: limit values can be overwritten in the configuration file under the ``[temperature]`` and ``[hddtemperature]`` sections.
|
||||
*Note*: it is possibile to define a list of network interfaces to hide
|
||||
and per-interface limit values in the ``[network]`` section of the
|
||||
configuration file.
|
||||
|
||||
Disk I/O
|
||||
--------
|
||||
@ -333,11 +380,12 @@ Disk I/O
|
||||
|
||||
Glances displays the disk I/O throughput. The unit is adapted dynamically.
|
||||
|
||||
*Note*: There is no alert on this information.
|
||||
There is no alert on this information.
|
||||
|
||||
*Note*: In the configuration file, you can define a list of disk to hide.
|
||||
*Note*: it is possible to define a list of disks to hide under the
|
||||
``[diskio]`` section in the configuration file.
|
||||
|
||||
File system
|
||||
File System
|
||||
-----------
|
||||
|
||||
.. image:: images/fs.png
|
||||
@ -345,16 +393,35 @@ File system
|
||||
Glances displays the used and total file system disk space. The unit is
|
||||
adapted dynamically.
|
||||
|
||||
Alerts are set for used disk space:
|
||||
Alerts are set for used disk space.
|
||||
|
||||
| If disk used is ``<50%``, then status is set to ``"OK"``
|
||||
| If disk used is ``>50%``, then status is set to ``"CAREFUL"``
|
||||
| If disk used is ``>70%``, then status is set to ``"WARNING"``
|
||||
| If disk used is ``>90%``, then status is set to ``"CRITICAL"``
|
||||
| If used disk is ``<50%``, then status is set to ``"OK"``
|
||||
| If used disk is ``>50%``, then status is set to ``"CAREFUL"``
|
||||
| If used disk is ``>70%``, then status is set to ``"WARNING"``
|
||||
| If used disk is ``>90%``, then status is set to ``"CRITICAL"``
|
||||
|
||||
*Note*: limit values can be overwritten in the configuration file under ``[filesystem]`` section.
|
||||
*Note*: limit values can be overwritten in the configuration file under
|
||||
the ``[filesystem]`` section.
|
||||
|
||||
Processes list
|
||||
Sensors
|
||||
-------
|
||||
|
||||
Glances can displays the sensors information using `lm-sensors`,
|
||||
`hddtemp` and `batinfo` [2]_.
|
||||
|
||||
All of the above libraries are available only on Linux.
|
||||
|
||||
As of lm-sensors, a filter is being applied in order to display
|
||||
temperature only.
|
||||
|
||||
.. image:: images/sensors.png
|
||||
|
||||
There is no alert on this information.
|
||||
|
||||
*Note*: limit values can be overwritten in the configuration file under
|
||||
the ``[sensors]`` section.
|
||||
|
||||
Processes List
|
||||
--------------
|
||||
|
||||
Compact view:
|
||||
@ -368,7 +435,7 @@ Full view:
|
||||
Three views are available for processes:
|
||||
|
||||
* Processes summary
|
||||
* Optional monitored processes list (new in 1.7)
|
||||
* Optional monitored processes list (see below)
|
||||
* Processes list
|
||||
|
||||
The processes summary line display:
|
||||
@ -378,59 +445,65 @@ The processes summary line display:
|
||||
* Running tasks number
|
||||
* Sleeping tasks number
|
||||
* Other tasks number (not running or sleeping)
|
||||
* Sort key
|
||||
|
||||
By default, or if you hit the ``a`` key, the processes list is automatically
|
||||
sorted by CPU of memory usage.
|
||||
By default, or if you hit the ``a`` key, the processes list is
|
||||
automatically sorted by:
|
||||
|
||||
*Note*: limit values can be overwritten in the configuration file under the ``[process]`` section.
|
||||
* ``CPU`` if there is no alert (default behavior)
|
||||
* ``CPU`` if a CPU or LOAD alert is detected
|
||||
* ``MEM`` if a memory alert is detected
|
||||
* ``Disk I/O`` if a CPU iowait alert is detected
|
||||
|
||||
The number of processes in the list is adapted to the screen size.
|
||||
|
||||
``VIRT``
|
||||
Total program size (VMS)
|
||||
``RES``
|
||||
Resident set size (RSS)
|
||||
``CPU%``
|
||||
% of CPU used by the process
|
||||
``MEM%``
|
||||
% of MEM used by the process
|
||||
``VIRT``
|
||||
Total program size aka Virtual Memory Size (VMS)
|
||||
``RES``
|
||||
Resident Set Size (RSS)
|
||||
``PID``
|
||||
Process ID
|
||||
``USER``
|
||||
User ID per process
|
||||
User ID
|
||||
``NI``
|
||||
Nice level of the process
|
||||
Nice level of the process (niceness other than 0 is highlighted)
|
||||
``S``
|
||||
Process status
|
||||
Process status (running process is highlighted)
|
||||
``TIME+``
|
||||
Cumulative CPU time used
|
||||
``IOR/s``
|
||||
Per process IO read rate (in Byte/s)
|
||||
Per process I/O read rate (in Byte/s)
|
||||
``IOW/s``
|
||||
Per process IO write rate (in Byte/s)
|
||||
``NAME``
|
||||
Process name or command line
|
||||
Per process I/O write rate (in Byte/s)
|
||||
``COMMAND``
|
||||
Process command line (process name is highlighted)
|
||||
|
||||
Process status legend:
|
||||
|
||||
``R``
|
||||
running
|
||||
Running
|
||||
``S``
|
||||
sleeping (may be interrupted)
|
||||
Sleeping (may be interrupted)
|
||||
``D``
|
||||
disk sleep (may not be interrupted)
|
||||
Disk sleep (may not be interrupted)
|
||||
``T``
|
||||
traced/stopped
|
||||
Traced / Stopped
|
||||
``Z``
|
||||
zombie
|
||||
Zombie
|
||||
|
||||
Monitored processes list
|
||||
*Note*: limits values can be overwritten in the configuration file under
|
||||
the ``[process]`` section.
|
||||
|
||||
Monitored Processes List
|
||||
------------------------
|
||||
|
||||
New in version 1.7. Optional.
|
||||
|
||||
The monitored processes list allows user, through the configuration file,
|
||||
to group processes and quickly show if the number of running process is not good.
|
||||
to group processes and quickly show if the number of running processes is
|
||||
not good.
|
||||
|
||||
.. image:: images/monitored.png
|
||||
|
||||
@ -438,15 +511,19 @@ Each item is defined by:
|
||||
|
||||
* ``description``: description of the processes (max 16 chars).
|
||||
* ``regex``: regular expression of the processes to monitor.
|
||||
* ``command`` (optional): full path to shell command/script for extended stat. Should return a single line string. Use with caution.
|
||||
* ``countmin`` (optional): minimal number of processes. A warning will be displayed if number of processes < count.
|
||||
* ``countmax`` (optional): maximum number of processes. A warning will be displayed if number of processes > count.
|
||||
* ``command`` (optional): full path to shell command/script for extended
|
||||
stat. Should return a single line string. Use with caution.
|
||||
* ``countmin`` (optional): minimal number of processes. A warning will
|
||||
be displayed if number of processes < count.
|
||||
* ``countmax`` (optional): maximum number of processes. A warning will
|
||||
be displayed if number of processes > count.
|
||||
|
||||
Up to 10 items can be defined.
|
||||
|
||||
For example, if you want to monitor the Nginx processes on a Web server, the following definition should do the job:
|
||||
For example, if you want to monitor the Nginx processes on a Web server,
|
||||
the following definition should do the job:
|
||||
|
||||
.. code-block:: console
|
||||
::
|
||||
|
||||
[monitor]
|
||||
list_1_description=Nginx server
|
||||
@ -455,9 +532,10 @@ For example, if you want to monitor the Nginx processes on a Web server, the fol
|
||||
list_1_countmin=1
|
||||
list_1_countmax=4
|
||||
|
||||
If you also want to monitor the PHP-FPM daemon processes, you should add another item:
|
||||
If you also want to monitor the PHP-FPM daemon processes, you should add
|
||||
another item:
|
||||
|
||||
.. code-block:: console
|
||||
::
|
||||
|
||||
[monitor]
|
||||
list_1_description=Nginx server
|
||||
@ -471,7 +549,8 @@ If you also want to monitor the PHP-FPM daemon processes, you should add another
|
||||
list_1_countmax=20
|
||||
|
||||
In client/server mode, the list is defined on the server side.
|
||||
A new method, called getAllMonitored, is available in the APIs and get the JSON representation of the monitored processes list.
|
||||
A new method, called `getAllMonitored`, is available in the APIs and
|
||||
get the JSON representation of the monitored processes list.
|
||||
|
||||
Alerts are set as following:
|
||||
|
||||
@ -484,48 +563,41 @@ Logs
|
||||
|
||||
.. image:: images/logs.png
|
||||
|
||||
A log messages list is displayed in the bottom of the screen if (and only if):
|
||||
A log messages list is displayed in the bottom of the screen if (and
|
||||
only if):
|
||||
|
||||
- at least one ``WARNING`` or ``CRITICAL`` alert was occurred
|
||||
- space is available in the bottom of the console/terminal
|
||||
|
||||
Each alert message displays the following information:
|
||||
|
||||
1. start date
|
||||
2. end date
|
||||
1. start datetime
|
||||
2. duration if alert is terminated or `ongoing` if the alert is still in
|
||||
progress
|
||||
3. alert name
|
||||
4. {min/avg/max} values or number of running processes for monitored processes list alerts
|
||||
4. {min,avg,max} values or number of running processes for monitored
|
||||
processes list alerts
|
||||
|
||||
Footer
|
||||
------
|
||||
Other Outputs
|
||||
=============
|
||||
|
||||
.. image:: images/footer.png
|
||||
It is possible to export statistics to CSV file.
|
||||
|
||||
Glances displays the current date & time and access to the embedded help screen.
|
||||
.. code-block:: console
|
||||
|
||||
If one or mode batteries were found on your machine and if the batinfo Python library [3]_
|
||||
is installed on your system then Glances displays the available percent capacity in the middle on the footer.
|
||||
$ glances --output-csv /tmp/glances.csv
|
||||
|
||||
.. image:: images/battery.png
|
||||
CSV files have two lines per stats:
|
||||
|
||||
If you have ran Glances in client mode ``-c``, you can also see if the client is connected to the server.
|
||||
- Stats description
|
||||
- Stats (comma separated)
|
||||
|
||||
If client is connected:
|
||||
|
||||
.. image:: images/client-connected.png
|
||||
|
||||
else:
|
||||
|
||||
.. image:: images/client-disconnected.png
|
||||
|
||||
On the left, you can easily see if you are connected to a Glances server.
|
||||
|
||||
|
||||
API documentation
|
||||
API Documentation
|
||||
=================
|
||||
|
||||
Glances uses a `XML-RPC server`_ and can be used by another client software.
|
||||
|
||||
<<<<<<< HEAD
|
||||
API documentation is available at https://github.com/nicolargo/glances/wiki/The-Glances-API-How-To
|
||||
|
||||
Other outputs
|
||||
@ -553,18 +625,22 @@ CSV files have on line per stats:
|
||||
The HTML output file is named ``glances.html``.
|
||||
|
||||
*Note*: The css and img folders (glances/data) should be in the /tmp folder.
|
||||
=======
|
||||
API documentation is available at
|
||||
https://github.com/nicolargo/glances/wiki/The-Glances-2.x-API-How-to.
|
||||
>>>>>>> release/v2.0
|
||||
|
||||
Support
|
||||
=======
|
||||
|
||||
To report a bug or a feature request use the bug tracking system at https://github.com/nicolargo/glances/issues
|
||||
To report a bug or a feature request use the bug tracking system at
|
||||
https://github.com/nicolargo/glances/issues.
|
||||
|
||||
Feel free to contribute!
|
||||
|
||||
|
||||
.. [1] http://nosheep.net/story/defining-unix-load-average/
|
||||
.. [2] http://www.cyberciti.biz/tips/howto-monitor-hard-drive-temperature.html
|
||||
.. [3] https://github.com/nicolargo/batinfo
|
||||
.. [2] https://github.com/nicolargo/batinfo
|
||||
|
||||
.. _psutil: https://code.google.com/p/psutil/
|
||||
.. _XML-RPC server: http://docs.python.org/2/library/simplexmlrpcserver.html
|
||||
|
Before Width: | Height: | Size: 6.8 KiB |
Before Width: | Height: | Size: 9.0 KiB |
Before Width: | Height: | Size: 9.8 KiB |
BIN
docs/images/connected.png
Normal file
After Width: | Height: | Size: 9.2 KiB |
Before Width: | Height: | Size: 6.6 KiB After Width: | Height: | Size: 15 KiB |
Before Width: | Height: | Size: 4.0 KiB After Width: | Height: | Size: 7.3 KiB |
BIN
docs/images/disconnected.png
Normal file
After Width: | Height: | Size: 9.8 KiB |
Before Width: | Height: | Size: 4.2 KiB After Width: | Height: | Size: 7.2 KiB |
Before Width: | Height: | Size: 2.9 KiB |
Before Width: | Height: | Size: 9.5 KiB After Width: | Height: | Size: 9.7 KiB |
Before Width: | Height: | Size: 21 KiB |
Before Width: | Height: | Size: 2.2 KiB |
Before Width: | Height: | Size: 4.1 KiB After Width: | Height: | Size: 7.4 KiB |
Before Width: | Height: | Size: 3.6 KiB After Width: | Height: | Size: 6.8 KiB |
Before Width: | Height: | Size: 12 KiB After Width: | Height: | Size: 24 KiB |
Before Width: | Height: | Size: 9.9 KiB After Width: | Height: | Size: 23 KiB |
Before Width: | Height: | Size: 7.1 KiB After Width: | Height: | Size: 13 KiB |
Before Width: | Height: | Size: 6.0 KiB After Width: | Height: | Size: 10 KiB |
Before Width: | Height: | Size: 7.4 KiB After Width: | Height: | Size: 18 KiB |
Before Width: | Height: | Size: 90 KiB After Width: | Height: | Size: 222 KiB |
Before Width: | Height: | Size: 46 KiB After Width: | Height: | Size: 148 KiB |
BIN
docs/images/screenshot-web.png
Normal file
After Width: | Height: | Size: 198 KiB |
BIN
docs/images/screenshot-web2.png
Normal file
After Width: | Height: | Size: 242 KiB |
Before Width: | Height: | Size: 93 KiB After Width: | Height: | Size: 389 KiB |
Before Width: | Height: | Size: 113 KiB After Width: | Height: | Size: 208 KiB |
Before Width: | Height: | Size: 4.4 KiB After Width: | Height: | Size: 16 KiB |
@ -1,22 +1,28 @@
|
||||
.. Glances documentation master file, created by
|
||||
sphinx-quickstart on Tue Mar 25 19:57:21 2014.
|
||||
You can adapt this file completely to your liking, but it should at least
|
||||
contain the root `toctree` directive.
|
||||
|
||||
Welcome to Glances's documentation!
|
||||
===================================
|
||||
|
||||
Contents:
|
||||
**Glances** is a cross-platform curses-based monitoring tool written in Python.
|
||||
|
||||
It uses the psutil library and some internal code to get information from your system.
|
||||
|
||||
.. image:: https://raw.github.com/nicolargo/glances/master/docs/images/screenshot-wide.png
|
||||
|
||||
Get the code
|
||||
------------
|
||||
|
||||
The `source <http://github.com/nicolargo/glances>`_ is available on GitHub.
|
||||
|
||||
Contents
|
||||
--------
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 2
|
||||
|
||||
|
||||
glances-doc
|
||||
|
||||
Indices and tables
|
||||
==================
|
||||
|
||||
* :ref:`genindex`
|
||||
* :ref:`modindex`
|
||||
* :ref:`search`
|
||||
|
||||
* :ref:`search`
|
@ -61,12 +61,12 @@ p.topic-title {
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
pre.code {
|
||||
pre {
|
||||
margin-left: 2em;
|
||||
margin-right: 2em;
|
||||
}
|
||||
|
||||
.console {
|
||||
.console, .literal-block {
|
||||
background-color: #eeeeee;
|
||||
border: 1px solid #cccccc;
|
||||
max-width: 60em;
|
||||
|
32
glances/README.txt
Normal file
@ -0,0 +1,32 @@
|
||||
You are in the main Glances's source folder.
|
||||
This page is for developpers and contributors.
|
||||
|
||||
If you are lookink for user manual, please follow this link: https://github.com/nicolargo/glances/blob/master/docs/glances-doc.rst
|
||||
|
||||
===
|
||||
|
||||
__init__.py Global module init
|
||||
__main__.py Entry point for module
|
||||
core/
|
||||
glances_config.py Manage configuration file
|
||||
glances_globals.py Share variables uppon modules
|
||||
glances_limits.py Manage limits
|
||||
glances_logs.py Manage logs
|
||||
glances_main.py Main script to rule them up...
|
||||
glances_stats.py Inteface to grab stats
|
||||
glances_client.py Glances client
|
||||
glances_server.py Glances server
|
||||
glances_standalone.py Glances standalone (with curse interface)
|
||||
glances_stats.py The stats manager
|
||||
glances_timer.py Manage timer
|
||||
plugins/
|
||||
glances_plugins.py "Father class" for others plugins
|
||||
glances_cpu.py Manage CPU stats
|
||||
glances_load.py Manage LOAD stats
|
||||
glances_mem.py Manage MEM (both RAM and SWAP) stats
|
||||
...
|
||||
outputs/
|
||||
glances_curse.py The Curse interface
|
||||
glances_csv.py The CSV interface
|
||||
glances_html.py The HTML interface
|
||||
...
|
@ -0,0 +1,159 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
#
|
||||
# This file is part of Glances.
|
||||
#
|
||||
# Copyright (C) 2014 Nicolargo <nicolas@nicolargo.com>
|
||||
#
|
||||
# Glances is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU Lesser General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# Glances is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU Lesser General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU Lesser General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
"""Init the Glances software."""
|
||||
|
||||
__appname__ = 'glances'
|
||||
__version__ = '2.0'
|
||||
__author__ = 'Nicolas Hennion <nicolas@nicolargo.com>'
|
||||
__license__ = 'LGPL'
|
||||
|
||||
# Import system lib
|
||||
import gettext
|
||||
import locale
|
||||
import signal
|
||||
import sys
|
||||
|
||||
# Import psutil
|
||||
try:
|
||||
from psutil import __version__ as __psutil_version
|
||||
except ImportError:
|
||||
print('psutil library not found. Glances cannot start.')
|
||||
sys.exit(1)
|
||||
|
||||
# Check psutil version
|
||||
psutil_min_version = (2, 0, 0)
|
||||
psutil_version = tuple([int(num) for num in __psutil_version.split('.')])
|
||||
if psutil_version < psutil_min_version:
|
||||
print('psutil version {0} detected.').format(__psutil_version)
|
||||
print('psutil 2.0 or higher is needed. Glances cannot start.')
|
||||
sys.exit(1)
|
||||
|
||||
# Import Glances libs
|
||||
# Note: others Glances libs will be imported optionally
|
||||
from glances.core.glances_globals import gettext_domain, locale_dir
|
||||
from glances.core.glances_main import GlancesMain
|
||||
|
||||
|
||||
def __signal_handler(signal, frame):
|
||||
"""Callback for CTRL-C."""
|
||||
end()
|
||||
|
||||
|
||||
def end():
|
||||
"""Stop Glances."""
|
||||
if core.is_standalone():
|
||||
# Stop the standalone (CLI)
|
||||
standalone.end()
|
||||
elif core.is_client():
|
||||
# Stop the client
|
||||
client.end()
|
||||
elif core.is_server():
|
||||
# Stop the server
|
||||
server.end()
|
||||
|
||||
# The end...
|
||||
sys.exit(0)
|
||||
|
||||
|
||||
def main():
|
||||
"""Main entry point for Glances.
|
||||
|
||||
Select the mode (standalone, client or server)
|
||||
Run it...
|
||||
"""
|
||||
# Setup translations
|
||||
locale.setlocale(locale.LC_ALL, '')
|
||||
gettext.install(gettext_domain, locale_dir)
|
||||
|
||||
# Share global var
|
||||
global core, standalone, client, server
|
||||
|
||||
# Create the Glances main instance
|
||||
core = GlancesMain()
|
||||
|
||||
# Catch the CTRL-C signal
|
||||
signal.signal(signal.SIGINT, __signal_handler)
|
||||
|
||||
# Glances can be ran in standalone, client or server mode
|
||||
if core.is_standalone():
|
||||
|
||||
# Import the Glances standalone module
|
||||
from glances.core.glances_standalone import GlancesStandalone
|
||||
|
||||
# Init the standalone mode
|
||||
standalone = GlancesStandalone(config=core.get_config(),
|
||||
args=core.get_args())
|
||||
|
||||
# Start the standalone (CLI) loop
|
||||
standalone.serve_forever()
|
||||
|
||||
elif core.is_client():
|
||||
|
||||
# Import the Glances client module
|
||||
from glances.core.glances_client import GlancesClient
|
||||
|
||||
# Init the client
|
||||
client = GlancesClient(config=core.get_config(),
|
||||
args=core.get_args())
|
||||
|
||||
# Test if client and server are in the same major version
|
||||
if not client.login():
|
||||
print(_("Error: The server version is not compatible with the client"))
|
||||
sys.exit(2)
|
||||
|
||||
# Start the client loop
|
||||
client.serve_forever()
|
||||
|
||||
# Shutdown the client
|
||||
client.close()
|
||||
|
||||
elif core.is_server():
|
||||
|
||||
# Import the Glances server module
|
||||
from glances.core.glances_server import GlancesServer
|
||||
|
||||
args = core.get_args()
|
||||
|
||||
server = GlancesServer(cached_time=core.cached_time,
|
||||
config=core.get_config(),
|
||||
args=args)
|
||||
print(_("Glances server is running on {0}:{1}").format(args.bind_address, args.port))
|
||||
|
||||
# Set the server login/password (if -P/--password tag)
|
||||
if args.password != "":
|
||||
server.add_user(args.username, args.password)
|
||||
|
||||
# Start the server loop
|
||||
server.serve_forever()
|
||||
|
||||
# Shutdown the server?
|
||||
server.server_close()
|
||||
|
||||
elif core.is_webserver():
|
||||
|
||||
# Import the Glances web server module
|
||||
from glances.core.glances_webserver import GlancesWebServer
|
||||
|
||||
# Init the web server mode
|
||||
webserver = GlancesWebServer(config=core.get_config(),
|
||||
args=core.get_args())
|
||||
|
||||
# Start the web server loop
|
||||
webserver.serve_forever()
|
38
glances/__main__.py
Normal file
@ -0,0 +1,38 @@
|
||||
#!/usr/bin/env python
|
||||
# -*- coding: utf-8 -*-
|
||||
#
|
||||
# Glances - An eye on your system
|
||||
#
|
||||
# Copyright (C) 2014 Nicolargo <nicolas@nicolargo.com>
|
||||
#
|
||||
# Glances is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU Lesser General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# Glances is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU Lesser General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU Lesser General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
"""Allow user to run Glances as a module from a dir or zip file."""
|
||||
|
||||
# Execute with:
|
||||
# $ python glances/__main__.py (2.6)
|
||||
# $ python -m glances (2.7+)
|
||||
|
||||
import sys
|
||||
|
||||
if __package__ is None and not hasattr(sys, "frozen"):
|
||||
# It is a direct call to __main__.py
|
||||
import os.path
|
||||
path = os.path.realpath(os.path.abspath(__file__))
|
||||
sys.path.append(os.path.dirname(os.path.dirname(path)))
|
||||
|
||||
import glances
|
||||
|
||||
if __name__ == '__main__':
|
||||
glances.main()
|
188
glances/core/glances_client.py
Normal file
@ -0,0 +1,188 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
#
|
||||
# This file is part of Glances.
|
||||
#
|
||||
# Copyright (C) 2014 Nicolargo <nicolas@nicolargo.com>
|
||||
#
|
||||
# Glances is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU Lesser General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# Glances is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU Lesser General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU Lesser General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
"""Manage the Glances client."""
|
||||
|
||||
# Import system libs
|
||||
import json
|
||||
import socket
|
||||
import sys
|
||||
try:
|
||||
from xmlrpc.client import ServerProxy, ProtocolError
|
||||
except ImportError: # Python 2
|
||||
from xmlrpclib import ServerProxy, ProtocolError
|
||||
|
||||
# Import Glances libs
|
||||
from glances.core.glances_globals import version
|
||||
from glances.core.glances_stats import GlancesStatsClient
|
||||
from glances.outputs.glances_curses import GlancesCurses
|
||||
|
||||
|
||||
class GlancesClient(object):
|
||||
|
||||
"""This class creates and manages the TCP client."""
|
||||
|
||||
def __init__(self, config=None, args=None):
|
||||
# Store the arg/config
|
||||
self.args = args
|
||||
self.config = config
|
||||
|
||||
# Client mode:
|
||||
self.set_mode()
|
||||
|
||||
# Build the URI
|
||||
if args.password != "":
|
||||
uri = 'http://{0}:{1}@{2}:{3}'.format(args.username, args.password,
|
||||
args.client, args.port)
|
||||
else:
|
||||
uri = 'http://{0}:{1}'.format(args.client, args.port)
|
||||
|
||||
# Try to connect to the URI
|
||||
try:
|
||||
self.client = ServerProxy(uri)
|
||||
except Exception as e:
|
||||
print(_("Error: Couldn't create socket {0}: {1}").format(uri, e))
|
||||
sys.exit(2)
|
||||
|
||||
def set_mode(self, mode='glances'):
|
||||
"""Set the client mode.
|
||||
|
||||
- 'glances' = Glances server (default)
|
||||
- 'snmp' = SNMP (fallback)
|
||||
"""
|
||||
self.mode = mode
|
||||
return self.mode
|
||||
|
||||
def get_mode(self):
|
||||
"""Get the client mode.
|
||||
|
||||
- 'glances' = Glances server (default)
|
||||
- 'snmp' = SNMP (fallback)
|
||||
"""
|
||||
return self.mode
|
||||
|
||||
def login(self):
|
||||
"""Logon to the server."""
|
||||
ret = True
|
||||
|
||||
# First of all, trying to connect to a Glances server
|
||||
try:
|
||||
client_version = self.client.init()
|
||||
self.set_mode('glances')
|
||||
except socket.error as err:
|
||||
# print(_("Error: Connection to {0} server failed").format(self.get_mode()))
|
||||
# Fallback to SNMP
|
||||
self.set_mode('snmp')
|
||||
except ProtocolError as err:
|
||||
# Others errors
|
||||
if str(err).find(" 401 ") > 0:
|
||||
print(_("Error: Connection to server failed: Bad password"))
|
||||
else:
|
||||
print(_("Error: Connection to server failed: {0}").format(err))
|
||||
sys.exit(2)
|
||||
|
||||
if self.get_mode() == 'glances' and version[:3] == client_version[:3]:
|
||||
# Init stats
|
||||
self.stats = GlancesStatsClient()
|
||||
self.stats.set_plugins(json.loads(self.client.getAllPlugins()))
|
||||
elif self.get_mode() == 'snmp':
|
||||
print (_("Info: Connection to Glances server failed. Trying fallback to SNMP..."))
|
||||
# Then fallback to SNMP if needed
|
||||
from glances.core.glances_stats import GlancesStatsClientSNMP
|
||||
|
||||
# Init stats
|
||||
self.stats = GlancesStatsClientSNMP(args=self.args)
|
||||
|
||||
if not self.stats.check_snmp():
|
||||
print(_("Error: Connection to SNMP server failed"))
|
||||
sys.exit(2)
|
||||
else:
|
||||
ret = False
|
||||
|
||||
if ret:
|
||||
# Load limits from the configuration file
|
||||
# Each client can choose its owns limits
|
||||
self.stats.load_limits(self.config)
|
||||
|
||||
# Init screen
|
||||
self.screen = GlancesCurses(args=self.args)
|
||||
|
||||
# Return result
|
||||
return ret
|
||||
|
||||
def update(self):
|
||||
"""Update stats from Glances/SNMP server."""
|
||||
if self.get_mode() == 'glances':
|
||||
return self.update_glances()
|
||||
elif self.get_mode() == 'snmp':
|
||||
return self.update_snmp()
|
||||
else:
|
||||
print(_("Error: Unknown server mode: {0}").format(self.get_mode()))
|
||||
sys.exit(2)
|
||||
|
||||
def update_glances(self):
|
||||
"""Get stats from Glances server.
|
||||
|
||||
Return the client/server connection status:
|
||||
- Connected: Connection OK
|
||||
- Disconnected: Connection NOK
|
||||
"""
|
||||
# Update the stats
|
||||
try:
|
||||
server_stats = json.loads(self.client.getAll())
|
||||
server_stats['monitor'] = json.loads(self.client.getAllMonitored())
|
||||
except socket.error:
|
||||
# Client cannot get server stats
|
||||
return "Disconnected"
|
||||
else:
|
||||
# Put it in the internal dict
|
||||
self.stats.update(server_stats)
|
||||
return "Connected"
|
||||
|
||||
def update_snmp(self):
|
||||
"""Get stats from SNMP server.
|
||||
|
||||
Return the client/server connection status:
|
||||
- SNMP: Connection with SNMP server OK
|
||||
- Disconnected: Connection NOK
|
||||
"""
|
||||
# Update the stats
|
||||
try:
|
||||
self.stats.update()
|
||||
except:
|
||||
# Client can not get SNMP server stats
|
||||
return "Disconnected"
|
||||
else:
|
||||
# Grab success
|
||||
return "SNMP"
|
||||
|
||||
def serve_forever(self):
|
||||
"""Main client loop."""
|
||||
while True:
|
||||
# Update the stats
|
||||
cs_status = self.update()
|
||||
|
||||
# Update the screen
|
||||
self.screen.update(self.stats, cs_status=cs_status)
|
||||
# print self.stats
|
||||
# print self.stats.getAll()
|
||||
|
||||
def end(self):
|
||||
"""End of the client session."""
|
||||
self.screen.end()
|
145
glances/core/glances_config.py
Normal file
@ -0,0 +1,145 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
#
|
||||
# This file is part of Glances.
|
||||
#
|
||||
# Copyright (C) 2014 Nicolargo <nicolas@nicolargo.com>
|
||||
#
|
||||
# Glances is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU Lesser General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# Glances is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU Lesser General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU Lesser General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
"""Manage the configuration file."""
|
||||
|
||||
# Import system libs
|
||||
import os
|
||||
import sys
|
||||
try:
|
||||
from configparser import RawConfigParser
|
||||
from configparser import NoOptionError
|
||||
except ImportError: # Python 2
|
||||
from ConfigParser import RawConfigParser
|
||||
from ConfigParser import NoOptionError
|
||||
|
||||
# Import Glances lib
|
||||
from glances.core.glances_globals import (
|
||||
appname,
|
||||
is_bsd,
|
||||
is_linux,
|
||||
is_mac,
|
||||
is_py3,
|
||||
is_windows,
|
||||
sys_prefix,
|
||||
work_path
|
||||
)
|
||||
|
||||
|
||||
class Config(object):
|
||||
|
||||
"""This class is used to access/read config file, if it exists.
|
||||
|
||||
:param location: the custom path to search for config file
|
||||
:type location: str or None
|
||||
"""
|
||||
|
||||
def __init__(self, location=None):
|
||||
self.location = location
|
||||
self.config_filename = 'glances.conf'
|
||||
|
||||
self.parser = RawConfigParser()
|
||||
self.load()
|
||||
|
||||
def load(self):
|
||||
"""Load a config file from the list of paths, if it exists."""
|
||||
for config_file in self.get_config_paths():
|
||||
if os.path.isfile(config_file) and os.path.getsize(config_file) > 0:
|
||||
try:
|
||||
if is_py3:
|
||||
self.parser.read(config_file, encoding='utf-8')
|
||||
else:
|
||||
self.parser.read(config_file)
|
||||
# print(_("DEBUG: Read configuration file %s") % config_file)
|
||||
except UnicodeDecodeError as e:
|
||||
print(_("Error: Cannot decode configuration file '{0}': {1}").format(config_file, e))
|
||||
sys.exit(1)
|
||||
break
|
||||
|
||||
def get_config_paths(self):
|
||||
r"""Get a list of config file paths.
|
||||
|
||||
The list is built taking into account of the OS, priority and location.
|
||||
|
||||
* running from source: /path/to/glances/conf
|
||||
* Linux: ~/.config/glances, /etc/glances
|
||||
* BSD: ~/.config/glances, /usr/local/etc/glances
|
||||
* Mac: ~/Library/Application Support/glances, /usr/local/etc/glances
|
||||
* Windows: %APPDATA%\glances
|
||||
|
||||
The config file will be searched in the following order of priority:
|
||||
* /path/to/file (via -C flag)
|
||||
* /path/to/glances/conf
|
||||
* user's home directory (per-user settings)
|
||||
* {/usr/local,}/etc directory (system-wide settings)
|
||||
"""
|
||||
paths = []
|
||||
conf_path = os.path.realpath(os.path.join(work_path, '..', '..', 'conf'))
|
||||
|
||||
if self.location is not None:
|
||||
paths.append(self.location)
|
||||
|
||||
if os.path.exists(conf_path):
|
||||
paths.append(os.path.join(conf_path, self.config_filename))
|
||||
|
||||
if is_linux or is_bsd:
|
||||
paths.append(os.path.join(
|
||||
os.environ.get('XDG_CONFIG_HOME') or os.path.expanduser('~/.config'),
|
||||
appname, self.config_filename))
|
||||
if hasattr(sys, 'real_prefix') or is_bsd:
|
||||
paths.append(os.path.join(sys.prefix, 'etc', appname, self.config_filename))
|
||||
else:
|
||||
paths.append(os.path.join('/etc', appname, self.config_filename))
|
||||
elif is_mac:
|
||||
paths.append(os.path.join(
|
||||
os.path.expanduser('~/Library/Application Support/'),
|
||||
appname, self.config_filename))
|
||||
paths.append(os.path.join(
|
||||
sys_prefix, 'etc', appname, self.config_filename))
|
||||
elif is_windows:
|
||||
paths.append(os.path.join(
|
||||
os.environ.get('APPDATA'), appname, self.config_filename))
|
||||
|
||||
return paths
|
||||
|
||||
def items(self, section):
|
||||
"""Return the items list of a section."""
|
||||
return self.parser.items(section)
|
||||
|
||||
def has_section(self, section):
|
||||
"""Return info about the existence of a section."""
|
||||
return self.parser.has_section(section)
|
||||
|
||||
def get_option(self, section, option):
|
||||
"""Get the float value of an option, if it exists."""
|
||||
try:
|
||||
value = self.parser.getfloat(section, option)
|
||||
except NoOptionError:
|
||||
return
|
||||
else:
|
||||
return value
|
||||
|
||||
def get_raw_option(self, section, option):
|
||||
"""Get the raw value of an option, if it exists."""
|
||||
try:
|
||||
value = self.parser.get(section, option)
|
||||
except NoOptionError:
|
||||
return
|
||||
else:
|
||||
return value
|
70
glances/core/glances_globals.py
Normal file
@ -0,0 +1,70 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
#
|
||||
# This file is part of Glances.
|
||||
#
|
||||
# Copyright (C) 2014 Nicolargo <nicolas@nicolargo.com>
|
||||
#
|
||||
# Glances is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU Lesser General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# Glances is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU Lesser General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU Lesser General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
"""Common objects shared by all Glances modules."""
|
||||
|
||||
import os
|
||||
import sys
|
||||
|
||||
# Global information
|
||||
appname = 'glances'
|
||||
version = __import__('glances').__version__
|
||||
psutil_version = __import__('glances').__psutil_version
|
||||
|
||||
# PY3?
|
||||
is_py3 = sys.version_info >= (3, 3)
|
||||
|
||||
# Operating system flag
|
||||
# Note: Somes libs depends of OS
|
||||
is_bsd = sys.platform.find('bsd') != -1
|
||||
is_linux = sys.platform.startswith('linux')
|
||||
is_mac = sys.platform.startswith('darwin')
|
||||
is_windows = sys.platform.startswith('win')
|
||||
|
||||
# Path definitions
|
||||
work_path = os.path.realpath(os.path.dirname(__file__))
|
||||
appname_path = os.path.split(sys.argv[0])[0]
|
||||
sys_prefix = os.path.realpath(os.path.dirname(appname_path))
|
||||
|
||||
# Set the plugins path
|
||||
plugins_path = os.path.realpath(os.path.join(work_path, '..', 'plugins'))
|
||||
sys_path = sys.path[:]
|
||||
sys.path.insert(0, plugins_path)
|
||||
|
||||
# i18n
|
||||
gettext_domain = appname
|
||||
i18n_path = os.path.realpath(os.path.join(work_path, '..', '..', 'i18n'))
|
||||
sys_i18n_path = os.path.join(sys_prefix, 'share', 'locale')
|
||||
if os.path.exists(i18n_path):
|
||||
locale_dir = i18n_path
|
||||
elif os.path.exists(sys_i18n_path):
|
||||
locale_dir = sys_i18n_path
|
||||
else:
|
||||
locale_dir = None
|
||||
|
||||
# Instances shared between all Glances scripts
|
||||
# ============================================
|
||||
|
||||
# glances_processes for processcount and processlist plugins
|
||||
from glances.core.glances_processes import GlancesProcesses
|
||||
glances_processes = GlancesProcesses()
|
||||
|
||||
# The global instance for the logs
|
||||
from glances.core.glances_logs import GlancesLogs
|
||||
glances_logs = GlancesLogs()
|
198
glances/core/glances_logs.py
Normal file
@ -0,0 +1,198 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
#
|
||||
# This file is part of Glances.
|
||||
#
|
||||
# Copyright (C) 2014 Nicolargo <nicolas@nicolargo.com>
|
||||
#
|
||||
# Glances is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU Lesser General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# Glances is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU Lesser General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU Lesser General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
"""Manage logs."""
|
||||
|
||||
# Import system libs
|
||||
import time
|
||||
from datetime import datetime
|
||||
|
||||
# Import Glances libs
|
||||
from glances.core.glances_globals import glances_processes
|
||||
|
||||
|
||||
class GlancesLogs(object):
|
||||
|
||||
"""This class manages logs inside the Glances software.
|
||||
|
||||
Logs is a list of list (stored in the self.logs_list var)
|
||||
item_state = "OK|CAREFUL|WARNING|CRITICAL"
|
||||
item_type = "CPU*|LOAD|MEM|MON"
|
||||
item_value = value
|
||||
|
||||
Item is defined by:
|
||||
["begin",
|
||||
"end",
|
||||
"WARNING|CRITICAL",
|
||||
"CPU|LOAD|MEM",
|
||||
MAX, AVG, MIN, SUM, COUNT,
|
||||
[top3 process list],
|
||||
"Processes description"]
|
||||
"""
|
||||
|
||||
def __init__(self):
|
||||
"""Init the logs class."""
|
||||
# Maximum size of the logs list
|
||||
self.logs_max = 10
|
||||
|
||||
# Init the logs list
|
||||
self.logs_list = []
|
||||
|
||||
def get(self):
|
||||
"""Return the raw logs list."""
|
||||
return self.logs_list
|
||||
|
||||
def len(self):
|
||||
"""Return the number of item in the logs list."""
|
||||
return self.logs_list.__len__()
|
||||
|
||||
def __itemexist__(self, item_type):
|
||||
"""Return the item position, if it exists.
|
||||
|
||||
An item exist in the list if:
|
||||
* end is < 0
|
||||
* item_type is matching
|
||||
Return -1 if the item is not found.
|
||||
"""
|
||||
for i in range(self.len()):
|
||||
if self.logs_list[i][1] < 0 and self.logs_list[i][3] == item_type:
|
||||
return i
|
||||
return -1
|
||||
|
||||
def set_process_sort(self, item_type):
|
||||
"""Define the process auto sort key from the alert type."""
|
||||
# Process sort depending on alert type
|
||||
if item_type.startswith("MEM"):
|
||||
# Sort TOP process by memory_percent
|
||||
process_auto_by = 'memory_percent'
|
||||
elif item_type.startswith("CPU_IOWAIT"):
|
||||
# Sort TOP process by io_counters (only for Linux OS)
|
||||
process_auto_by = 'io_counters'
|
||||
else:
|
||||
# Default sort is...
|
||||
process_auto_by = 'cpu_percent'
|
||||
|
||||
glances_processes.setsortkey(process_auto_by)
|
||||
|
||||
return process_auto_by
|
||||
|
||||
def reset_process_sort(self):
|
||||
"""Reset the process_auto_by variable."""
|
||||
# Default sort is...
|
||||
process_auto_by = 'cpu_percent'
|
||||
|
||||
glances_processes.setsortkey(process_auto_by)
|
||||
|
||||
return process_auto_by
|
||||
|
||||
def add(self, item_state, item_type, item_value, proc_list=[], proc_desc=""):
|
||||
"""Add a new item to the logs list.
|
||||
|
||||
If 'item' is a 'new one', add the new item at the beginning of the logs
|
||||
list.
|
||||
If 'item' is not a 'new one', update the existing item.
|
||||
"""
|
||||
# Add or update the log
|
||||
item_index = self.__itemexist__(item_type)
|
||||
if item_index < 0:
|
||||
# Item did not exist, add if WARNING or CRITICAL
|
||||
if item_state == "WARNING" or item_state == "CRITICAL":
|
||||
# Define the automatic process sort key
|
||||
self.set_process_sort(item_type)
|
||||
|
||||
# Create the new log item
|
||||
# Time is stored in Epoch format
|
||||
# Epoch -> DMYHMS = datetime.fromtimestamp(epoch)
|
||||
item = []
|
||||
# START DATE
|
||||
item.append(time.mktime(datetime.now().timetuple()))
|
||||
item.append(-1) # END DATE
|
||||
item.append(item_state) # STATE: WARNING|CRITICAL
|
||||
item.append(item_type) # TYPE: CPU, LOAD, MEM...
|
||||
item.append(item_value) # MAX
|
||||
item.append(item_value) # AVG
|
||||
item.append(item_value) # MIN
|
||||
item.append(item_value) # SUM
|
||||
item.append(1) # COUNT
|
||||
# Process list is sorted automaticaly
|
||||
# Overwrite the user choise
|
||||
# topprocess = sorted(proc_list, key=lambda process: process[process_auto_by],
|
||||
# reverse=True)
|
||||
# item.append(topprocess[0:3]) # TOP 3 PROCESS LIST
|
||||
item.append([]) # TOP 3 PROCESS LIST
|
||||
item.append(proc_desc) # MONITORED PROCESSES DESC
|
||||
|
||||
# Add the item to the list
|
||||
self.logs_list.insert(0, item)
|
||||
if self.len() > self.logs_max:
|
||||
self.logs_list.pop()
|
||||
else:
|
||||
# Item exist, update
|
||||
if item_state == "OK" or item_state == "CAREFUL":
|
||||
# Reset the automatic process sort key
|
||||
self.reset_process_sort()
|
||||
|
||||
# Close the item
|
||||
self.logs_list[item_index][1] = time.mktime(
|
||||
datetime.now().timetuple())
|
||||
else:
|
||||
# Update the item
|
||||
# State
|
||||
if item_state == "CRITICAL":
|
||||
self.logs_list[item_index][2] = item_state
|
||||
# Value
|
||||
if item_value > self.logs_list[item_index][4]:
|
||||
# MAX
|
||||
self.logs_list[item_index][4] = item_value
|
||||
elif item_value < self.logs_list[item_index][6]:
|
||||
# MIN
|
||||
self.logs_list[item_index][6] = item_value
|
||||
# AVG
|
||||
self.logs_list[item_index][7] += item_value
|
||||
self.logs_list[item_index][8] += 1
|
||||
self.logs_list[item_index][5] = (self.logs_list[item_index][7] /
|
||||
self.logs_list[item_index][8])
|
||||
# TOP PROCESS LIST
|
||||
# # Process list is sorted automaticaly
|
||||
# # Overwrite the user choise
|
||||
# topprocess = sorted(proc_list, key=lambda process: process[process_auto_by],
|
||||
# reverse=True)
|
||||
# # TOP PROCESS LIST
|
||||
# self.logs_list[item_index][9] = topprocess[0:3]
|
||||
self.logs_list[item_index][9] = []
|
||||
# MONITORED PROCESSES DESC
|
||||
self.logs_list[item_index][10] = proc_desc
|
||||
|
||||
return self.len()
|
||||
|
||||
def clean(self, critical=False):
|
||||
"""Clean the logs list by deleting finished items.
|
||||
|
||||
By default, only delete WARNING message
|
||||
If critical = True, also delete CRITICAL message
|
||||
"""
|
||||
# Create a new clean list
|
||||
clean_logs_list = []
|
||||
while (self.len() > 0):
|
||||
item = self.logs_list.pop()
|
||||
if item[1] < 0 or (not critical and item[2].startswith("CRITICAL")):
|
||||
clean_logs_list.insert(0, item)
|
||||
# The list is now the clean one
|
||||
self.logs_list = clean_logs_list
|
||||
return self.len()
|
209
glances/core/glances_main.py
Normal file
@ -0,0 +1,209 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
#
|
||||
# This file is part of Glances.
|
||||
#
|
||||
# Copyright (C) 2014 Nicolargo <nicolas@nicolargo.com>
|
||||
#
|
||||
# Glances is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU Lesser General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# Glances is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU Lesser General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU Lesser General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
"""Glances main class."""
|
||||
|
||||
# Import system libs
|
||||
import argparse
|
||||
|
||||
# Import Glances libs
|
||||
from glances.core.glances_config import Config
|
||||
from glances.core.glances_globals import appname, psutil_version, version
|
||||
|
||||
|
||||
class GlancesMain(object):
|
||||
|
||||
"""Main class to manage Glances instance."""
|
||||
|
||||
# Default stats' refresh time is 3 seconds
|
||||
refresh_time = 3
|
||||
# Set the default cache lifetime to 1 second (only for server)
|
||||
# !!! Todo: configuration from the command line
|
||||
cached_time = 1
|
||||
# By default, Glances is ran in standalone mode (no client/server)
|
||||
client_tag = False
|
||||
# Server TCP port number (default is 61209)
|
||||
server_port = 61209
|
||||
# Web Server TCP port number (default is 61208)
|
||||
web_server_port = 61208
|
||||
# Default username/password for client/server mode
|
||||
username = "glances"
|
||||
password = ""
|
||||
|
||||
def __init__(self):
|
||||
"""Manage the command line arguments."""
|
||||
self.args = self.parse_args()
|
||||
|
||||
def init_args(self):
|
||||
"""Init all the command line arguments."""
|
||||
_version = "Glances v" + version + " with psutil v" + psutil_version
|
||||
parser = argparse.ArgumentParser(prog=appname, conflict_handler='resolve')
|
||||
parser.add_argument('-V', '--version', action='version', version=_version)
|
||||
parser.add_argument('-b', '--byte', action='store_true', default=False,
|
||||
dest='byte', help=_('display network rate in byte per second'))
|
||||
parser.add_argument('-B', '--bind', default='0.0.0.0', dest='bind_address',
|
||||
help=_('bind server to the given IPv4/IPv6 address or hostname'))
|
||||
parser.add_argument('-c', '--client', dest='client',
|
||||
help=_('connect to a Glances server by IPv4/IPv6 address or hostname'))
|
||||
parser.add_argument('-C', '--config', dest='conf_file',
|
||||
help=_('path to the configuration file'))
|
||||
# Enable or disable option on startup
|
||||
parser.add_argument('--disable-bold', action='store_false', default=True,
|
||||
dest='disable_bold', help=_('disable bold mode in the terminal'))
|
||||
parser.add_argument('--disable-diskio', action='store_true', default=False,
|
||||
dest='disable_diskio', help=_('disable disk I/O module'))
|
||||
parser.add_argument('--disable-fs', action='store_true', default=False,
|
||||
dest='disable_fs', help=_('disable filesystem module'))
|
||||
parser.add_argument('--disable-network', action='store_true', default=False,
|
||||
dest='disable_network', help=_('disable network module'))
|
||||
parser.add_argument('--disable-sensors', action='store_true', default=False,
|
||||
dest='disable_sensors', help=_('disable sensors module'))
|
||||
parser.add_argument('--disable-process', action='store_true', default=False,
|
||||
dest='disable_process', help=_('disable process module'))
|
||||
parser.add_argument('--disable-log', action='store_true', default=False,
|
||||
dest='disable_log', help=_('disable log module'))
|
||||
# CSV output feature
|
||||
parser.add_argument('--output-csv', default=None,
|
||||
dest='output_csv', help=_('export stats to a CSV file'))
|
||||
# Server option
|
||||
parser.add_argument('-p', '--port', default=self.server_port, type=int, dest='port',
|
||||
help=_('define the client/server TCP port [default: {0}]').format(self.server_port))
|
||||
parser.add_argument('--password-badidea', dest='password_arg',
|
||||
help=_('define password from the command line'))
|
||||
parser.add_argument('--password', action='store_true', default=False, dest='password_prompt',
|
||||
help=_('define a client/server password from the prompt or file'))
|
||||
parser.add_argument('-s', '--server', action='store_true', default=False,
|
||||
dest='server', help=_('run Glances in server mode'))
|
||||
parser.add_argument('--snmp-community', default='public', dest='snmp_community',
|
||||
help=_('SNMP community'))
|
||||
parser.add_argument('--snmp-port', default=161, type=int,
|
||||
dest='snmp_port', help=_('SNMP port'))
|
||||
parser.add_argument('--snmp-version', default='2c', dest='snmp_version',
|
||||
help=_('SNMP version (1, 2c or 3)'))
|
||||
parser.add_argument('--snmp-user', default='private', dest='snmp_user',
|
||||
help=_('SNMP username (only for SNMPv3)'))
|
||||
parser.add_argument('--snmp-auth', default='password', dest='snmp_auth',
|
||||
help=_('SNMP authentication key (only for SNMPv3)'))
|
||||
parser.add_argument('-t', '--time', default=self.refresh_time, type=int,
|
||||
dest='time', help=_('set refresh time in seconds [default: {0} sec]').format(self.refresh_time))
|
||||
parser.add_argument('-w', '--webserver', action='store_true', default=False,
|
||||
dest='webserver', help=_('run Glances in web server mode'))
|
||||
# Other options
|
||||
parser.add_argument('-1', '--percpu', action='store_true', default=False,
|
||||
dest='percpu', help=_('start Glances in per CPU mode'))
|
||||
|
||||
return parser
|
||||
|
||||
def parse_args(self):
|
||||
"""Parse command line arguments."""
|
||||
args = self.init_args().parse_args()
|
||||
|
||||
# Load the configuration file, it it exists
|
||||
self.config = Config(args.conf_file)
|
||||
|
||||
# In web server mode, default:
|
||||
# - refresh time: 5 sec
|
||||
# - host port: 61208
|
||||
if args.webserver:
|
||||
args.time = 5
|
||||
args.port = self.web_server_port
|
||||
|
||||
# Server or client login/password
|
||||
args.username = self.username
|
||||
if args.password_arg is not None:
|
||||
from hashlib import sha256
|
||||
# Password is given as an argument
|
||||
# Hash with SHA256
|
||||
# Only the SHA will be transmit on the network
|
||||
args.password = sha256(args.password_arg).hexdigest()
|
||||
elif args.password_prompt:
|
||||
# Interactive or file password
|
||||
if args.server:
|
||||
args.password = self.__get_password(
|
||||
description=_("Define the password for the Glances server"),
|
||||
confirm=True)
|
||||
elif args.client:
|
||||
args.password = self.__get_password(
|
||||
description=_("Enter the Glances server password"),
|
||||
clear=True)
|
||||
else:
|
||||
# Default is no password
|
||||
args.password = self.password
|
||||
|
||||
# !!! Change global variables regarding to user args
|
||||
# !!! To be refactor to use directly the args list in the code
|
||||
self.server_tag = args.server
|
||||
self.webserver_tag = args.webserver
|
||||
if args.client is not None:
|
||||
self.client_tag = True
|
||||
self.server_ip = args.client
|
||||
# /!!!
|
||||
|
||||
# By default help is hidden
|
||||
args.help_tag = False
|
||||
|
||||
# Display Rx and Tx, not the sum for the network
|
||||
args.network_sum = False
|
||||
args.network_cumul = False
|
||||
|
||||
return args
|
||||
|
||||
def __hash_password(self, plain_password):
|
||||
"""Hash a plain password and return the hashed one."""
|
||||
from glances.core.glances_password import GlancesPassword
|
||||
|
||||
password = GlancesPassword()
|
||||
|
||||
return password.hash_password(plain_password)
|
||||
|
||||
def __get_password(self, description='', confirm=False, clear=False):
|
||||
"""Read a password from the command line.
|
||||
|
||||
- if confirm = True, with confirmation
|
||||
- if clear = True, plain (clear password)
|
||||
"""
|
||||
from glances.core.glances_password import GlancesPassword
|
||||
|
||||
password = GlancesPassword()
|
||||
|
||||
return password.get_password(description, confirm, clear)
|
||||
|
||||
def is_standalone(self):
|
||||
"""Return True if Glances is running in standalone mode."""
|
||||
return not self.client_tag and not self.server_tag and not self.webserver_tag
|
||||
|
||||
def is_client(self):
|
||||
"""Return True if Glances is running in client mode."""
|
||||
return self.client_tag and not self.server_tag
|
||||
|
||||
def is_server(self):
|
||||
"""Return True if Glances is running in server mode."""
|
||||
return not self.client_tag and self.server_tag
|
||||
|
||||
def is_webserver(self):
|
||||
"""Return True if Glances is running in Web server mode."""
|
||||
return not self.client_tag and self.webserver_tag
|
||||
|
||||
def get_config(self):
|
||||
"""Return configuration file object."""
|
||||
return self.config
|
||||
|
||||
def get_args(self):
|
||||
"""Return the arguments."""
|
||||
return self.args
|
185
glances/core/glances_monitor_list.py
Normal file
@ -0,0 +1,185 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
#
|
||||
# This file is part of Glances.
|
||||
#
|
||||
# Copyright (C) 2014 Nicolargo <nicolas@nicolargo.com>
|
||||
#
|
||||
# Glances is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU Lesser General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# Glances is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU Lesser General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU Lesser General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
"""Manage the monitor list."""
|
||||
|
||||
# Import system lib
|
||||
import re
|
||||
import subprocess
|
||||
|
||||
# Import Glances lib
|
||||
from glances.core.glances_globals import glances_processes
|
||||
|
||||
|
||||
class MonitorList(object):
|
||||
|
||||
"""This class describes the optional monitored processes list.
|
||||
|
||||
The monitored list is a list of 'important' processes to monitor.
|
||||
|
||||
The list (Python list) is composed of items (Python dict).
|
||||
An item is defined (dict keys):
|
||||
* description: Description of the processes (max 16 chars)
|
||||
* regex: regular expression of the processes to monitor
|
||||
* command: (optional) shell command for extended stat
|
||||
* countmin: (optional) minimal number of processes
|
||||
* countmax: (optional) maximum number of processes
|
||||
"""
|
||||
|
||||
# Maximum number of items in the list
|
||||
__monitor_list_max_size = 10
|
||||
# The list
|
||||
__monitor_list = []
|
||||
|
||||
def __init__(self, config):
|
||||
"""Init the monitoring list from the configuration file."""
|
||||
self.config = config
|
||||
|
||||
if self.config is not None and self.config.has_section('monitor'):
|
||||
# Process monitoring list
|
||||
self.__set_monitor_list('monitor', 'list')
|
||||
else:
|
||||
self.__monitor_list = []
|
||||
|
||||
def __set_monitor_list(self, section, key):
|
||||
"""Init the monitored processes list.
|
||||
|
||||
The list is defined in the Glances configuration file.
|
||||
"""
|
||||
for l in range(1, self.__monitor_list_max_size + 1):
|
||||
value = {}
|
||||
key = "list_" + str(l) + "_"
|
||||
try:
|
||||
description = self.config.get_raw_option(section, key + "description")
|
||||
regex = self.config.get_raw_option(section, key + "regex")
|
||||
command = self.config.get_raw_option(section, key + "command")
|
||||
countmin = self.config.get_raw_option(section, key + "countmin")
|
||||
countmax = self.config.get_raw_option(section, key + "countmax")
|
||||
except Exception as e:
|
||||
print(_("Error: Cannot read monitored list: {0}").format(e))
|
||||
pass
|
||||
else:
|
||||
if description is not None and regex is not None:
|
||||
# Build the new item
|
||||
value["description"] = description
|
||||
value["regex"] = regex
|
||||
value["command"] = command
|
||||
value["countmin"] = countmin
|
||||
value["countmax"] = countmax
|
||||
value["count"] = None
|
||||
value["result"] = None
|
||||
# Add the item to the list
|
||||
self.__monitor_list.append(value)
|
||||
|
||||
def __str__(self):
|
||||
return str(self.__monitor_list)
|
||||
|
||||
def __repr__(self):
|
||||
return self.__monitor_list
|
||||
|
||||
def __getitem__(self, item):
|
||||
return self.__monitor_list[item]
|
||||
|
||||
def __len__(self):
|
||||
return len(self.__monitor_list)
|
||||
|
||||
def __get__(self, item, key):
|
||||
"""Meta function to return key value of item.
|
||||
|
||||
Return None if not defined or item > len(list)
|
||||
"""
|
||||
if item < len(self.__monitor_list):
|
||||
try:
|
||||
return self.__monitor_list[item][key]
|
||||
except Exception:
|
||||
return None
|
||||
else:
|
||||
return None
|
||||
|
||||
def update(self):
|
||||
"""Update the command result attributed."""
|
||||
# Only continue if monitor list is not empty
|
||||
if len(self.__monitor_list) == 0:
|
||||
return self.__monitor_list
|
||||
|
||||
# Iter upon the monitored list
|
||||
for i in range(0, len(self.get())):
|
||||
# Search monitored processes by a regular expression
|
||||
processlist = glances_processes.getlist()
|
||||
monitoredlist = [p for p in processlist if re.search(self.regex(i), p['cmdline']) is not None]
|
||||
self.__monitor_list[i]['count'] = len(monitoredlist)
|
||||
|
||||
if self.command(i) is None:
|
||||
# If there is no command specified in the conf file
|
||||
# then display CPU and MEM %
|
||||
self.__monitor_list[i]['result'] = 'CPU: {0:.1f}% | MEM: {1:.1f}%'.format(
|
||||
sum([p['cpu_percent'] for p in monitoredlist]),
|
||||
sum([p['memory_percent'] for p in monitoredlist]))
|
||||
continue
|
||||
else:
|
||||
# Execute the user command line
|
||||
try:
|
||||
self.__monitor_list[i]['result'] = subprocess.check_output(self.command(i),
|
||||
shell=True)
|
||||
except subprocess.CalledProcessError:
|
||||
self.__monitor_list[i]['result'] = _("Error: ") + self.command(i)
|
||||
except Exception:
|
||||
self.__monitor_list[i]['result'] = _("Cannot execute command")
|
||||
|
||||
return self.__monitor_list
|
||||
|
||||
def get(self):
|
||||
"""Return the monitored list (list of dict)."""
|
||||
return self.__monitor_list
|
||||
|
||||
def set(self, newlist):
|
||||
"""Set the monitored list (list of dict)."""
|
||||
self.__monitor_list = newlist
|
||||
|
||||
def getAll(self):
|
||||
# Deprecated: use get()
|
||||
return self.get()
|
||||
|
||||
def setAll(self, newlist):
|
||||
# Deprecated: use set()
|
||||
self.set(newlist)
|
||||
|
||||
def description(self, item):
|
||||
"""Return the description of the item number (item)."""
|
||||
return self.__get__(item, "description")
|
||||
|
||||
def regex(self, item):
|
||||
"""Return the regular expression of the item number (item)."""
|
||||
return self.__get__(item, "regex")
|
||||
|
||||
def command(self, item):
|
||||
"""Return the stat command of the item number (item)."""
|
||||
return self.__get__(item, "command")
|
||||
|
||||
def result(self, item):
|
||||
"""Return the reult command of the item number (item)."""
|
||||
return self.__get__(item, "result")
|
||||
|
||||
def countmin(self, item):
|
||||
"""Return the minimum number of processes of the item number (item)."""
|
||||
return self.__get__(item, "countmin")
|
||||
|
||||
def countmax(self, item):
|
||||
"""Return the maximum number of processes of the item number (item)."""
|
||||
return self.__get__(item, "countmax")
|
163
glances/core/glances_password.py
Normal file
@ -0,0 +1,163 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
#
|
||||
# This file is part of Glances.
|
||||
#
|
||||
# Copyright (C) 2014 Nicolargo <nicolas@nicolargo.com>
|
||||
#
|
||||
# Glances is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU Lesser General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# Glances is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU Lesser General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU Lesser General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
"""Manage password."""
|
||||
|
||||
# Import system libs
|
||||
import getpass
|
||||
import hashlib
|
||||
import os
|
||||
import sys
|
||||
import uuid
|
||||
|
||||
# Import Glances lib
|
||||
from glances.core.glances_globals import (
|
||||
appname,
|
||||
is_bsd,
|
||||
is_linux,
|
||||
is_mac,
|
||||
is_windows
|
||||
)
|
||||
|
||||
# Trick: bind raw_input to input in Python 2
|
||||
try:
|
||||
input = raw_input
|
||||
except NameError:
|
||||
pass
|
||||
|
||||
|
||||
class GlancesPassword(object):
|
||||
|
||||
"""This class contains all the methods relating to password."""
|
||||
|
||||
def __init__(self):
|
||||
self.password_path = self.get_password_path()
|
||||
self.password_filename = 'glances.pwd'
|
||||
self.password_filepath = os.path.join(self.password_path, self.password_filename)
|
||||
|
||||
def get_password_path(self):
|
||||
r"""Get the path where the password file will be stored.
|
||||
|
||||
* Linux and BSD: ~/.config/glances
|
||||
* OS X: ~/Library/glances
|
||||
* Windows: %APPDATA%\glances
|
||||
"""
|
||||
if is_linux or is_bsd:
|
||||
app_path = os.environ.get('XDG_CONFIG_HOME') or os.path.expanduser('~/.config')
|
||||
elif is_mac:
|
||||
app_path = os.path.join(os.environ.get('HOME'), 'Library')
|
||||
elif is_windows:
|
||||
app_path = os.environ.get('APPDATA')
|
||||
else:
|
||||
app_path = '.'
|
||||
|
||||
# Append the Glances folder
|
||||
app_path = os.path.join(app_path, appname)
|
||||
|
||||
return app_path
|
||||
|
||||
def get_hash(self, salt, plain_password):
|
||||
"""Return the hashed password, salt + SHA-256."""
|
||||
return hashlib.sha256(salt.encode() + plain_password.encode()).hexdigest()
|
||||
|
||||
def hash_password(self, plain_password):
|
||||
"""Hash password with a salt based on UUID (universally unique identifier)."""
|
||||
salt = uuid.uuid4().hex
|
||||
encrypted_password = self.get_hash(salt, plain_password)
|
||||
return salt + '$' + encrypted_password
|
||||
|
||||
def check_password(self, hashed_password, plain_password):
|
||||
"""Encode the plain_password with the salt of the hashed_password.
|
||||
|
||||
Return the comparison with the encrypted_password.
|
||||
"""
|
||||
salt, encrypted_password = hashed_password.split('$')
|
||||
re_encrypted_password = self.get_hash(salt, plain_password)
|
||||
return encrypted_password == re_encrypted_password
|
||||
|
||||
def get_password(self, description='', confirm=False, clear=False):
|
||||
"""Get the password from a Glances client or server.
|
||||
|
||||
For Glances server, get the password (confirm=True, clear=False):
|
||||
1) from the password file (if it exists)
|
||||
2) from the CLI
|
||||
Optionally: save the password to a file (hashed with salt + SHA-256)
|
||||
|
||||
For Glances client, get the password (confirm=False, clear=True):
|
||||
1) from the CLI
|
||||
2) the password is hashed with SHA-256 (only SHA string transit
|
||||
through the network)
|
||||
"""
|
||||
if os.path.exists(self.password_filepath) and not clear:
|
||||
# If the password file exist then use it
|
||||
print(_("Info: Read password from file: {0}").format(self.password_filepath))
|
||||
password = self.load_password()
|
||||
else:
|
||||
# Else enter the password from the command line
|
||||
if description != '':
|
||||
print(description)
|
||||
|
||||
# password_plain is the plain SHA-256 password
|
||||
# password_hashed is the salt + SHA-256 password
|
||||
password_sha = hashlib.sha256(getpass.getpass(_("Password: ")).encode('utf-8')).hexdigest()
|
||||
password_hashed = self.hash_password(password_sha)
|
||||
if confirm:
|
||||
# password_confirm is the clear password (only used to compare)
|
||||
password_confirm = hashlib.sha256(getpass.getpass(_("Password (confirm): ")).encode('utf-8')).hexdigest()
|
||||
|
||||
if not self.check_password(password_hashed, password_confirm):
|
||||
print(_("Error: Sorry, but passwords did not match..."))
|
||||
sys.exit(1)
|
||||
|
||||
# Return the plain or hashed password
|
||||
if clear:
|
||||
password = password_sha
|
||||
else:
|
||||
password = password_hashed
|
||||
|
||||
# Save the hashed password to the password file
|
||||
if not clear:
|
||||
save_input = input(_("Do you want to save the password? [Yes/No]: "))
|
||||
if len(save_input) > 0 and save_input[0].upper() == _('Y'):
|
||||
self.save_password(password_hashed)
|
||||
|
||||
return password
|
||||
|
||||
def save_password(self, hashed_password):
|
||||
"""Save the hashed password to the Glances folder."""
|
||||
# Check if the Glances folder already exists
|
||||
if not os.path.exists(self.password_path):
|
||||
# Create the Glances folder
|
||||
try:
|
||||
os.makedirs(self.password_path)
|
||||
except OSError as e:
|
||||
print(_("Warning: Cannot create Glances directory: {0}").format(e))
|
||||
return
|
||||
|
||||
# Create/overwrite the password file
|
||||
with open(self.password_filepath, 'w') as file_pwd:
|
||||
file_pwd.write(hashed_password)
|
||||
|
||||
def load_password(self):
|
||||
"""Load the hashed password from the Glances folder."""
|
||||
# Read the password file, if it exists
|
||||
with open(self.password_filepath, 'r') as file_pwd:
|
||||
hashed_password = file_pwd.read()
|
||||
|
||||
return hashed_password
|
251
glances/core/glances_processes.py
Normal file
@ -0,0 +1,251 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
#
|
||||
# This file is part of Glances.
|
||||
#
|
||||
# Copyright (C) 2014 Nicolargo <nicolas@nicolargo.com>
|
||||
#
|
||||
# Glances is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU Lesser General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# Glances is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU Lesser General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU Lesser General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
from glances.core.glances_globals import is_bsd, is_mac, is_windows
|
||||
from glances.core.glances_timer import Timer, getTimeSinceLastUpdate
|
||||
|
||||
import psutil
|
||||
|
||||
|
||||
class GlancesProcesses(object):
|
||||
|
||||
"""Get processed stats using the psutil library."""
|
||||
|
||||
def __init__(self, cache_timeout=60):
|
||||
"""Init the class to collect stats about processes."""
|
||||
# Add internals caches because PSUtil do not cache all the stats
|
||||
# See: https://code.google.com/p/psutil/issues/detail?id=462
|
||||
self.username_cache = {}
|
||||
self.cmdline_cache = {}
|
||||
|
||||
# The internals caches will be cleaned each 'cache_timeout' seconds
|
||||
self.cache_timeout = cache_timeout
|
||||
self.cache_timer = Timer(self.cache_timeout)
|
||||
|
||||
# Init the io dict
|
||||
# key = pid
|
||||
# value = [ read_bytes_old, write_bytes_old ]
|
||||
self.io_old = {}
|
||||
|
||||
# Init stats
|
||||
self.processsort = 'cpu_percent'
|
||||
self.processlist = []
|
||||
self.processcount = {'total': 0, 'running': 0, 'sleeping': 0, 'thread': 0}
|
||||
|
||||
# Tag to enable/disable the processes stats (to reduce the Glances CPU comsumption)
|
||||
# Default is to enable the processes stats
|
||||
self.disable_tag = False
|
||||
|
||||
def enable(self):
|
||||
"""Enable process stats."""
|
||||
self.disable_tag = False
|
||||
self.update()
|
||||
|
||||
def disable(self):
|
||||
"""Disable process stats."""
|
||||
self.disable_tag = True
|
||||
|
||||
def __get_process_stats(self, proc):
|
||||
"""Get process stats."""
|
||||
procstat = {}
|
||||
|
||||
# Process ID
|
||||
procstat['pid'] = proc.pid
|
||||
|
||||
# Process name (cached by PSUtil)
|
||||
procstat['name'] = proc.name()
|
||||
|
||||
# Process username (cached with internal cache)
|
||||
try:
|
||||
self.username_cache[procstat['pid']]
|
||||
except:
|
||||
try:
|
||||
self.username_cache[procstat['pid']] = proc.username()
|
||||
except KeyError:
|
||||
try:
|
||||
self.username_cache[procstat['pid']] = proc.uids().real
|
||||
except KeyError:
|
||||
self.username_cache[procstat['pid']] = "?"
|
||||
procstat['username'] = self.username_cache[procstat['pid']]
|
||||
|
||||
# Process command line (cached with internal cache)
|
||||
try:
|
||||
self.cmdline_cache[procstat['pid']]
|
||||
except:
|
||||
self.cmdline_cache[procstat['pid']] = ' '.join(proc.cmdline())
|
||||
procstat['cmdline'] = self.cmdline_cache[procstat['pid']]
|
||||
|
||||
# Process status
|
||||
procstat['status'] = str(proc.status())[:1].upper()
|
||||
|
||||
# Process nice
|
||||
procstat['nice'] = proc.nice()
|
||||
|
||||
# Process memory
|
||||
procstat['memory_info'] = proc.memory_info()
|
||||
procstat['memory_percent'] = proc.memory_percent()
|
||||
|
||||
# Process CPU
|
||||
procstat['cpu_times'] = proc.cpu_times()
|
||||
procstat['cpu_percent'] = proc.cpu_percent(interval=0)
|
||||
|
||||
# Process network connections (TCP and UDP) (Experimental)
|
||||
# !!! High CPU consumption
|
||||
# try:
|
||||
# procstat['tcp'] = len(proc.connections(kind="tcp"))
|
||||
# procstat['udp'] = len(proc.connections(kind="udp"))
|
||||
# except:
|
||||
# procstat['tcp'] = 0
|
||||
# procstat['udp'] = 0
|
||||
|
||||
# Process IO
|
||||
# procstat['io_counters'] is a list:
|
||||
# [read_bytes, write_bytes, read_bytes_old, write_bytes_old, io_tag]
|
||||
# If io_tag = 0 > Access denied (display "?")
|
||||
# If io_tag = 1 > No access denied (display the IO rate)
|
||||
# Note Disk IO stat not available on Mac OS
|
||||
if not is_mac:
|
||||
try:
|
||||
# Get the process IO counters
|
||||
proc_io = proc.io_counters()
|
||||
io_new = [proc_io.read_bytes, proc_io.write_bytes]
|
||||
except psutil.AccessDenied:
|
||||
# Access denied to process IO (no root account)
|
||||
# Put 0 in all values (for sort) and io_tag = 0 (for display)
|
||||
procstat['io_counters'] = [0, 0] + [0, 0]
|
||||
io_tag = 0
|
||||
else:
|
||||
# For IO rate computation
|
||||
# Append saved IO r/w bytes
|
||||
try:
|
||||
procstat['io_counters'] = io_new + self.io_old[procstat['pid']]
|
||||
except KeyError:
|
||||
procstat['io_counters'] = io_new + [0, 0]
|
||||
# then save the IO r/w bytes
|
||||
self.io_old[procstat['pid']] = io_new
|
||||
io_tag = 1
|
||||
|
||||
# Append the IO tag (for display)
|
||||
procstat['io_counters'] += [io_tag]
|
||||
|
||||
return procstat
|
||||
|
||||
def update(self):
|
||||
"""Update the processes stats."""
|
||||
# Reset the stats
|
||||
self.processlist = []
|
||||
self.processcount = {'total': 0, 'running': 0, 'sleeping': 0, 'thread': 0}
|
||||
|
||||
# Do not process if disable tag is set
|
||||
if self.disable_tag:
|
||||
return
|
||||
|
||||
# Get the time since last update
|
||||
time_since_update = getTimeSinceLastUpdate('process_disk')
|
||||
|
||||
# For each existing process...
|
||||
for proc in psutil.process_iter():
|
||||
try:
|
||||
# Get stats using the PSUtil
|
||||
procstat = self.__get_process_stats(proc)
|
||||
# Add a specific time_since_update stats for bitrate
|
||||
procstat['time_since_update'] = time_since_update
|
||||
# ignore the 'idle' process on Windows and *BSD
|
||||
# ignore the 'kernel_task' process on OS X
|
||||
# waiting for upstream patch from psutil
|
||||
if (is_bsd and procstat['name'] == 'idle' or
|
||||
is_windows and procstat['name'] == 'System Idle Process' or
|
||||
is_mac and procstat['name'] == 'kernel_task'):
|
||||
continue
|
||||
# Update processcount (global statistics)
|
||||
try:
|
||||
self.processcount[str(proc.status())] += 1
|
||||
except KeyError:
|
||||
# Key did not exist, create it
|
||||
self.processcount[str(proc.status())] = 1
|
||||
else:
|
||||
self.processcount['total'] += 1
|
||||
# Update thread number (global statistics)
|
||||
try:
|
||||
self.processcount['thread'] += proc.num_threads()
|
||||
except:
|
||||
pass
|
||||
except (psutil.NoSuchProcess, psutil.AccessDenied):
|
||||
continue
|
||||
else:
|
||||
# Update processlist
|
||||
self.processlist.append(procstat)
|
||||
|
||||
# Clean internals caches if timeout is reached
|
||||
if self.cache_timer.finished():
|
||||
self.username_cache = {}
|
||||
self.cmdline_cache = {}
|
||||
# Restart the timer
|
||||
self.cache_timer.reset()
|
||||
|
||||
def getcount(self):
|
||||
"""Get the number of processes."""
|
||||
return self.processcount
|
||||
|
||||
def getlist(self, sortedby=None):
|
||||
"""Get the processlist."""
|
||||
return self.processlist
|
||||
|
||||
def getsortkey(self):
|
||||
"""Get the current sort key for automatic sort."""
|
||||
return self.processsort
|
||||
|
||||
def setsortkey(self, sortedby):
|
||||
"""Set the current sort key for automatic sort."""
|
||||
self.processsort = sortedby
|
||||
return self.processsort
|
||||
|
||||
def getsortlist(self, sortedby=None):
|
||||
"""Get the sorted processlist."""
|
||||
if sortedby is None:
|
||||
# No need to sort...
|
||||
return self.processlist
|
||||
|
||||
sortedreverse = True
|
||||
if sortedby == 'name':
|
||||
sortedreverse = False
|
||||
|
||||
if sortedby == 'io_counters':
|
||||
# Specific case for io_counters
|
||||
# Sum of io_r + io_w
|
||||
try:
|
||||
# Sort process by IO rate (sum IO read + IO write)
|
||||
listsorted = sorted(self.processlist,
|
||||
key=lambda process: process[sortedby][0] -
|
||||
process[sortedby][2] + process[sortedby][1] -
|
||||
process[sortedby][3],
|
||||
reverse=sortedreverse)
|
||||
except Exception:
|
||||
listsorted = sorted(self.processlist,
|
||||
key=lambda process: process['cpu_percent'],
|
||||
reverse=sortedreverse)
|
||||
else:
|
||||
# Others sorts
|
||||
listsorted = sorted(self.processlist,
|
||||
key=lambda process: process[sortedby],
|
||||
reverse=sortedreverse)
|
||||
|
||||
self.processlist = listsorted
|
||||
|
||||
return self.processlist
|
231
glances/core/glances_server.py
Normal file
@ -0,0 +1,231 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
#
|
||||
# This file is part of Glances.
|
||||
#
|
||||
# Copyright (C) 2014 Nicolargo <nicolas@nicolargo.com>
|
||||
#
|
||||
# Glances is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU Lesser General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# Glances is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU Lesser General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU Lesser General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
"""Manage the Glances server."""
|
||||
|
||||
# Import system libs
|
||||
import json
|
||||
import socket
|
||||
import sys
|
||||
from base64 import b64decode
|
||||
try:
|
||||
from xmlrpc.server import SimpleXMLRPCRequestHandler
|
||||
from xmlrpc.server import SimpleXMLRPCServer
|
||||
except ImportError: # Python 2
|
||||
from SimpleXMLRPCServer import SimpleXMLRPCRequestHandler
|
||||
from SimpleXMLRPCServer import SimpleXMLRPCServer
|
||||
|
||||
# Import Glances libs
|
||||
from glances.core.glances_globals import version
|
||||
from glances.core.glances_stats import GlancesStatsServer
|
||||
from glances.core.glances_timer import Timer
|
||||
|
||||
|
||||
class GlancesXMLRPCHandler(SimpleXMLRPCRequestHandler):
|
||||
|
||||
"""Main XML-RPC handler."""
|
||||
|
||||
rpc_paths = ('/RPC2', )
|
||||
|
||||
def end_headers(self):
|
||||
# Hack to add a specific header
|
||||
# Thk to: https://gist.github.com/rca/4063325
|
||||
self.send_my_headers()
|
||||
SimpleXMLRPCRequestHandler.end_headers(self)
|
||||
|
||||
def send_my_headers(self):
|
||||
# Specific header is here (solved the issue #227)
|
||||
self.send_header("Access-Control-Allow-Origin", "*")
|
||||
|
||||
def authenticate(self, headers):
|
||||
# auth = headers.get('Authorization')
|
||||
try:
|
||||
(basic, _, encoded) = headers.get('Authorization').partition(' ')
|
||||
except Exception:
|
||||
# Client did not ask for authentidaction
|
||||
# If server need it then exit
|
||||
return not self.server.isAuth
|
||||
else:
|
||||
# Client authentication
|
||||
(basic, _, encoded) = headers.get('Authorization').partition(' ')
|
||||
assert basic == 'Basic', 'Only basic authentication supported'
|
||||
# Encoded portion of the header is a string
|
||||
# Need to convert to bytestring
|
||||
encoded_byte_string = encoded.encode()
|
||||
# Decode base64 byte string to a decoded byte string
|
||||
decoded_bytes = b64decode(encoded_byte_string)
|
||||
# Convert from byte string to a regular string
|
||||
decoded_string = decoded_bytes.decode()
|
||||
# Get the username and password from the string
|
||||
(username, _, password) = decoded_string.partition(':')
|
||||
# Check that username and password match internal global dictionary
|
||||
return self.check_user(username, password)
|
||||
|
||||
def check_user(self, username, password):
|
||||
# Check username and password in the dictionary
|
||||
if username in self.server.user_dict:
|
||||
from glances.core.glances_password import GlancesPassword
|
||||
|
||||
pwd = GlancesPassword()
|
||||
|
||||
return pwd.check_password(self.server.user_dict[username], password)
|
||||
else:
|
||||
return False
|
||||
|
||||
def parse_request(self):
|
||||
if SimpleXMLRPCRequestHandler.parse_request(self):
|
||||
# Next we authenticate
|
||||
if self.authenticate(self.headers):
|
||||
return True
|
||||
else:
|
||||
# if authentication fails, tell the client
|
||||
self.send_error(401, 'Authentication failed')
|
||||
return False
|
||||
|
||||
def log_message(self, format, *args):
|
||||
# No message displayed on the server side
|
||||
pass
|
||||
|
||||
|
||||
class GlancesXMLRPCServer(SimpleXMLRPCServer):
|
||||
|
||||
"""Init a SimpleXMLRPCServer instance (IPv6-ready)."""
|
||||
|
||||
def __init__(self, bind_address, bind_port=61209,
|
||||
requestHandler=GlancesXMLRPCHandler):
|
||||
|
||||
try:
|
||||
self.address_family = socket.getaddrinfo(bind_address, bind_port)[0][0]
|
||||
except socket.error as e:
|
||||
print(_("Error: Couldn't open socket: {0}").format(e))
|
||||
sys.exit(1)
|
||||
|
||||
SimpleXMLRPCServer.__init__(self, (bind_address, bind_port),
|
||||
requestHandler)
|
||||
|
||||
|
||||
class GlancesInstance(object):
|
||||
|
||||
"""All the methods of this class are published as XML-RPC methods."""
|
||||
|
||||
def __init__(self, cached_time=1, config=None):
|
||||
# Init stats
|
||||
self.stats = GlancesStatsServer(config)
|
||||
|
||||
# Initial update
|
||||
self.stats.update()
|
||||
|
||||
# cached_time is the minimum time interval between stats updates
|
||||
# i.e. XML/RPC calls will not retrieve updated info until the time
|
||||
# since last update is passed (will retrieve old cached info instead)
|
||||
self.timer = Timer(0)
|
||||
self.cached_time = cached_time
|
||||
|
||||
def __update__(self):
|
||||
# Never update more than 1 time per cached_time
|
||||
if self.timer.finished():
|
||||
self.stats.update()
|
||||
self.timer = Timer(self.cached_time)
|
||||
|
||||
def init(self):
|
||||
# Return the Glances version
|
||||
return version
|
||||
|
||||
def getAll(self):
|
||||
# Update and return all the stats
|
||||
self.__update__()
|
||||
return json.dumps(self.stats.getAll())
|
||||
|
||||
def getAllPlugins(self):
|
||||
# Return the plugins list
|
||||
return json.dumps(self.stats.getAllPlugins())
|
||||
|
||||
def getAllLimits(self):
|
||||
# Return all the plugins limits
|
||||
return json.dumps(self.stats.getAllLimits())
|
||||
|
||||
def getAllMonitored(self):
|
||||
# Return the processes monitored list
|
||||
# return json.dumps(self.monitors.getAll())
|
||||
return json.dumps(self.stats.getAll()['monitor'])
|
||||
|
||||
def __getattr__(self, item):
|
||||
"""Overwrite the getattr method in case of attribute is not found.
|
||||
|
||||
The goal is to dynamically generate the API get'Stats'() methods.
|
||||
"""
|
||||
# print "DEBUG: Call method: %s" % item
|
||||
header = 'get'
|
||||
# Check if the attribute starts with 'get'
|
||||
if item.startswith(header):
|
||||
try:
|
||||
# Update the stat
|
||||
# !!! All the stat are updated before one grab (not optimized)
|
||||
self.stats.update()
|
||||
# Return the attribute
|
||||
return getattr(self.stats, item)
|
||||
except Exception:
|
||||
# The method is not found for the plugin
|
||||
raise AttributeError(item)
|
||||
else:
|
||||
# Default behavior
|
||||
raise AttributeError(item)
|
||||
|
||||
|
||||
class GlancesServer(object):
|
||||
|
||||
"""This class creates and manages the TCP server."""
|
||||
|
||||
def __init__(self, requestHandler=GlancesXMLRPCHandler,
|
||||
cached_time=1,
|
||||
config=None,
|
||||
args=None):
|
||||
# Init the XML RPC server
|
||||
try:
|
||||
self.server = GlancesXMLRPCServer(args.bind_address, args.port, requestHandler)
|
||||
except Exception as e:
|
||||
print(_("Error: Cannot start Glances server: {0}").format(e))
|
||||
sys.exit(2)
|
||||
|
||||
# The users dict
|
||||
# username / password couple
|
||||
# By default, no auth is needed
|
||||
self.server.user_dict = {}
|
||||
self.server.isAuth = False
|
||||
|
||||
# Register functions
|
||||
self.server.register_introspection_functions()
|
||||
self.server.register_instance(GlancesInstance(cached_time, config))
|
||||
|
||||
def add_user(self, username, password):
|
||||
"""Add an user to the dictionary."""
|
||||
self.server.user_dict[username] = password
|
||||
self.server.isAuth = True
|
||||
|
||||
def serve_forever(self):
|
||||
"""Call the main loop."""
|
||||
self.server.serve_forever()
|
||||
|
||||
def server_close(self):
|
||||
"""Close the Glances server session."""
|
||||
self.server.server_close()
|
||||
|
||||
def end(self):
|
||||
"""End of the Glances server session."""
|
||||
self.server_close()
|
128
glances/core/glances_snmp.py
Normal file
@ -0,0 +1,128 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
#
|
||||
# This file is part of Glances.
|
||||
#
|
||||
# Copyright (C) 2014 Nicolargo <nicolas@nicolargo.com>
|
||||
#
|
||||
# Glances is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU Lesser General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# Glances is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU Lesser General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU Lesser General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
import sys
|
||||
|
||||
try:
|
||||
from pysnmp.entity.rfc3413.oneliner import cmdgen
|
||||
except ImportError:
|
||||
print("PySNMP library not found.")
|
||||
print("Install using pip: # pip install pysnmp")
|
||||
sys.exit(2)
|
||||
|
||||
|
||||
class GlancesSNMPClient(object):
|
||||
|
||||
"""SNMP client class (based on pysnmp library)."""
|
||||
|
||||
def __init__(self, host='localhost', port=161, version='2c',
|
||||
community='public', user='private', auth=''):
|
||||
|
||||
super(GlancesSNMPClient, self).__init__()
|
||||
self.cmdGen = cmdgen.CommandGenerator()
|
||||
|
||||
self.version = version
|
||||
|
||||
self.host = host
|
||||
self.port = port
|
||||
|
||||
self.community = community
|
||||
self.user = user
|
||||
self.auth = auth
|
||||
|
||||
def __get_result__(self, errorIndication, errorStatus, errorIndex, varBinds):
|
||||
"""Put results in table."""
|
||||
ret = {}
|
||||
if not errorIndication or not errorStatus:
|
||||
for name, val in varBinds:
|
||||
if str(val) == '':
|
||||
ret[name.prettyPrint()] = ''
|
||||
else:
|
||||
ret[name.prettyPrint()] = val.prettyPrint()
|
||||
return ret
|
||||
|
||||
def get_by_oid(self, *oid):
|
||||
"""SNMP simple request (list of OID).
|
||||
|
||||
One request per OID list.
|
||||
|
||||
* oid: oid list
|
||||
> Return a dict
|
||||
"""
|
||||
if self.version == '3':
|
||||
errorIndication, errorStatus, errorIndex, varBinds = self.cmdGen.getCmd(
|
||||
cmdgen.UsmUserData(self.user, self.auth),
|
||||
cmdgen.UdpTransportTarget((self.host, self.port)),
|
||||
*oid
|
||||
)
|
||||
else:
|
||||
errorIndication, errorStatus, errorIndex, varBinds = self.cmdGen.getCmd(
|
||||
cmdgen.CommunityData(self.community),
|
||||
cmdgen.UdpTransportTarget((self.host, self.port)),
|
||||
*oid
|
||||
)
|
||||
return self.__get_result__(errorIndication, errorStatus, errorIndex, varBinds)
|
||||
|
||||
def __bulk_result__(self, errorIndication, errorStatus, errorIndex, varBindTable):
|
||||
ret = []
|
||||
if not errorIndication or not errorStatus:
|
||||
for varBindTableRow in varBindTable:
|
||||
item = {}
|
||||
for name, val in varBindTableRow:
|
||||
if str(val) == '':
|
||||
item[name.prettyPrint()] = ''
|
||||
else:
|
||||
item[name.prettyPrint()] = val.prettyPrint()
|
||||
ret.append(item)
|
||||
return ret
|
||||
|
||||
def getbulk_by_oid(self, non_repeaters, max_repetitions, *oid):
|
||||
"""SNMP getbulk request.
|
||||
|
||||
In contrast to snmpwalk, this information will typically be gathered in
|
||||
a single transaction with the agent, rather than one transaction per
|
||||
variable found.
|
||||
|
||||
* non_repeaters: This specifies the number of supplied variables that
|
||||
should not be iterated over.
|
||||
* max_repetitions: This specifies the maximum number of iterations over
|
||||
the repeating variables.
|
||||
* oid: oid list
|
||||
> Return a list of dicts
|
||||
"""
|
||||
if self.version.startswith('3'):
|
||||
errorIndication, errorStatus, errorIndex, varBinds = self.cmdGen.getCmd(
|
||||
cmdgen.UsmUserData(self.user, self.auth),
|
||||
cmdgen.UdpTransportTarget((self.host, self.port)),
|
||||
non_repeaters,
|
||||
max_repetitions,
|
||||
*oid
|
||||
)
|
||||
if self.version.startswith('2'):
|
||||
errorIndication, errorStatus, errorIndex, varBindTable = self.cmdGen.bulkCmd(
|
||||
cmdgen.CommunityData(self.community),
|
||||
cmdgen.UdpTransportTarget((self.host, self.port)),
|
||||
non_repeaters,
|
||||
max_repetitions,
|
||||
*oid
|
||||
)
|
||||
else:
|
||||
# Bulk request are not available with SNMP version 1
|
||||
return []
|
||||
return self.__bulk_result__(errorIndication, errorStatus, errorIndex, varBindTable)
|
69
glances/core/glances_standalone.py
Normal file
@ -0,0 +1,69 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
#
|
||||
# This file is part of Glances.
|
||||
#
|
||||
# Copyright (C) 2014 Nicolargo <nicolas@nicolargo.com>
|
||||
#
|
||||
# Glances is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU Lesser General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# Glances is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU Lesser General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU Lesser General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
"""Manage the Glances standalone session."""
|
||||
|
||||
# Import Glances libs
|
||||
from glances.core.glances_stats import GlancesStats
|
||||
from glances.outputs.glances_curses import GlancesCurses
|
||||
|
||||
|
||||
class GlancesStandalone(object):
|
||||
|
||||
"""This class creates and manages the Glances standalone session."""
|
||||
|
||||
def __init__(self, config=None, args=None):
|
||||
# Init stats
|
||||
self.stats = GlancesStats(config)
|
||||
|
||||
# Initial system informations update
|
||||
self.stats.update()
|
||||
|
||||
# Init CSV output
|
||||
if args.output_csv is not None:
|
||||
from glances.outputs.glances_csv import GlancesCSV
|
||||
|
||||
self.csvoutput = GlancesCSV(args=args)
|
||||
self.csv_tag = True
|
||||
else:
|
||||
self.csv_tag = False
|
||||
|
||||
# Init screen
|
||||
self.screen = GlancesCurses(args=args)
|
||||
|
||||
def serve_forever(self):
|
||||
"""Main loop for the CLI."""
|
||||
while True:
|
||||
# Update system informations
|
||||
self.stats.update()
|
||||
|
||||
# Update the screen
|
||||
self.screen.update(self.stats)
|
||||
|
||||
# Update the CSV output
|
||||
if self.csv_tag:
|
||||
self.csvoutput.update(self.stats)
|
||||
|
||||
def end(self):
|
||||
"""End of the CLI."""
|
||||
self.screen.end()
|
||||
|
||||
# Close the CSV file
|
||||
if self.csv_tag:
|
||||
self.csvoutput.exit()
|
229
glances/core/glances_stats.py
Normal file
@ -0,0 +1,229 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
#
|
||||
# This file is part of Glances.
|
||||
#
|
||||
# Copyright (C) 2014 Nicolargo <nicolas@nicolargo.com>
|
||||
#
|
||||
# Glances is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU Lesser General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# Glances is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU Lesser General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU Lesser General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
"""The stats manager."""
|
||||
|
||||
import collections
|
||||
import os
|
||||
import sys
|
||||
|
||||
from glances.core.glances_globals import plugins_path, sys_path
|
||||
|
||||
|
||||
class GlancesStats(object):
|
||||
|
||||
"""This class stores, updates and gives stats."""
|
||||
|
||||
def __init__(self, config=None):
|
||||
# Init the plugin list dict
|
||||
self._plugins = collections.defaultdict(dict)
|
||||
|
||||
# Load the plugins
|
||||
self.load_plugins()
|
||||
|
||||
# Load the limits
|
||||
self.load_limits(config)
|
||||
|
||||
def __getattr__(self, item):
|
||||
"""Overwrite the getattr method in case of attribute is not found.
|
||||
|
||||
The goal is to dynamically generate the following methods:
|
||||
- getPlugname(): return Plugname stat in JSON format
|
||||
"""
|
||||
# Check if the attribute starts with 'get'
|
||||
if item.startswith('get'):
|
||||
# Get the plugin name
|
||||
plugname = item[len('get'):].lower()
|
||||
# Get the plugin instance
|
||||
plugin = self._plugins[plugname]
|
||||
if hasattr(plugin, 'get_stats'):
|
||||
# The method get_stats exist, return it
|
||||
return getattr(plugin, 'get_stats')
|
||||
else:
|
||||
# The method get_stats is not found for the plugin
|
||||
raise AttributeError(item)
|
||||
else:
|
||||
# Default behavior
|
||||
raise AttributeError(item)
|
||||
|
||||
def load_plugins(self, args=None):
|
||||
"""Load all plugins in the 'plugins' folder."""
|
||||
header = "glances_"
|
||||
for item in os.listdir(plugins_path):
|
||||
if (item.startswith(header) and
|
||||
item.endswith(".py") and
|
||||
item != (header + "plugin.py")):
|
||||
# Import the plugin
|
||||
plugin = __import__(os.path.basename(item)[:-3])
|
||||
# Add the plugin to the dictionary
|
||||
# The key is the plugin name
|
||||
# for example, the file glances_xxx.py
|
||||
# generate self._plugins_list["xxx"] = ...
|
||||
plugin_name = os.path.basename(item)[len(header):-3].lower()
|
||||
self._plugins[plugin_name] = plugin.Plugin(args=args)
|
||||
# Restoring system path
|
||||
sys.path = sys_path
|
||||
|
||||
def getAllPlugins(self):
|
||||
"""Return the plugins list."""
|
||||
return [p for p in self._plugins]
|
||||
|
||||
def load_limits(self, config=None):
|
||||
"""Load the stats limits."""
|
||||
# For each plugins, call the init_limits method
|
||||
for p in self._plugins:
|
||||
# print "DEBUG: Load limits for %s" % p
|
||||
self._plugins[p].load_limits(config)
|
||||
|
||||
def __update__(self, input_stats):
|
||||
"""Update all the stats."""
|
||||
if input_stats == {}:
|
||||
# For standalone and server modes
|
||||
# For each plugins, call the update method
|
||||
for p in self._plugins:
|
||||
# print "DEBUG: Update %s stats" % p
|
||||
self._plugins[p].update()
|
||||
else:
|
||||
# For Glances client mode
|
||||
# Update plugin stats with items sent by the server
|
||||
for p in input_stats:
|
||||
self._plugins[p].set_stats(input_stats[p])
|
||||
|
||||
def update(self, input_stats={}):
|
||||
"""Wrapper method to update the stats."""
|
||||
self.__update__(input_stats)
|
||||
|
||||
def getAll(self):
|
||||
"""Return all the stats."""
|
||||
return [self._plugins[p].get_raw() for p in self._plugins]
|
||||
|
||||
def get_plugin_list(self):
|
||||
"""Return the plugin list."""
|
||||
self._plugins
|
||||
|
||||
def get_plugin(self, plugin_name):
|
||||
"""Return the plugin name."""
|
||||
if plugin_name in self._plugins:
|
||||
return self._plugins[plugin_name]
|
||||
else:
|
||||
return None
|
||||
|
||||
|
||||
class GlancesStatsServer(GlancesStats):
|
||||
|
||||
"""This class stores, updates and gives stats for the server."""
|
||||
|
||||
def __init__(self, config=None):
|
||||
# Init the stats
|
||||
GlancesStats.__init__(self, config)
|
||||
|
||||
# Init the all_stats dict used by the server
|
||||
# all_stats is a dict of dicts filled by the server
|
||||
self.all_stats = collections.defaultdict(dict)
|
||||
|
||||
def update(self, input_stats={}):
|
||||
"""Update the stats."""
|
||||
GlancesStats.update(self)
|
||||
|
||||
# Build the all_stats with the get_raw() method of the plugins
|
||||
for p in self._plugins:
|
||||
self.all_stats[p] = self._plugins[p].get_raw()
|
||||
|
||||
def getAll(self):
|
||||
"""Return the stats as a dict."""
|
||||
return self.all_stats
|
||||
|
||||
def getAllPlugins(self):
|
||||
"""Return the plugins list."""
|
||||
return [p for p in self._plugins]
|
||||
|
||||
def getAllLimits(self):
|
||||
"""Return the plugins limits list."""
|
||||
return [self._plugins[p].get_limits() for p in self._plugins]
|
||||
|
||||
|
||||
class GlancesStatsClient(GlancesStats):
|
||||
|
||||
"""This class stores, updates and gives stats for the client."""
|
||||
|
||||
def __init__(self):
|
||||
"""Init the GlancesStatsClient class."""
|
||||
# Init the plugin list dict
|
||||
self._plugins = collections.defaultdict(dict)
|
||||
|
||||
def set_plugins(self, input_plugins):
|
||||
"""Set the plugin list according to the Glances server."""
|
||||
header = "glances_"
|
||||
for item in input_plugins:
|
||||
# Import the plugin
|
||||
plugin = __import__(header + item)
|
||||
# Add the plugin to the dictionary
|
||||
# The key is the plugin name
|
||||
# for example, the file glances_xxx.py
|
||||
# generate self._plugins_list["xxx"] = ...
|
||||
# print "DEBUG: Init %s plugin" % item
|
||||
self._plugins[item] = plugin.Plugin()
|
||||
# Restoring system path
|
||||
sys.path = sys_path
|
||||
|
||||
|
||||
class GlancesStatsClientSNMP(GlancesStats):
|
||||
|
||||
"""This class stores, updates and gives stats for the SNMP client."""
|
||||
|
||||
def __init__(self, config=None, args=None):
|
||||
# Init the plugin list dict
|
||||
self._plugins = collections.defaultdict(dict)
|
||||
|
||||
# Init the configuration
|
||||
self.config = config
|
||||
|
||||
# Init the arguments
|
||||
self.args = args
|
||||
|
||||
# Load plugins
|
||||
self.load_plugins(args=self.args)
|
||||
|
||||
def check_snmp(self):
|
||||
"""Chek if SNMP is available on the server."""
|
||||
# Import the SNMP client class
|
||||
from glances.core.glances_snmp import GlancesSNMPClient
|
||||
|
||||
# Create an instance of the SNMP client
|
||||
clientsnmp = GlancesSNMPClient(host=self.args.client,
|
||||
port=self.args.snmp_port,
|
||||
version=self.args.snmp_version,
|
||||
community=self.args.snmp_community,
|
||||
user=self.args.snmp_user,
|
||||
auth=self.args.snmp_auth)
|
||||
|
||||
return clientsnmp.get_by_oid("1.3.6.1.2.1.1.5.0") != {}
|
||||
|
||||
def update(self):
|
||||
"""Update the stats using SNMP."""
|
||||
# For each plugins, call the update method
|
||||
for p in self._plugins:
|
||||
# Set the input method to SNMP
|
||||
self._plugins[p].set_input('snmp')
|
||||
# print "DEBUG: Update %s stats using SNMP request" % p
|
||||
try:
|
||||
self._plugins[p].update()
|
||||
except Exception as e:
|
||||
print(_("Error: Update {0} failed: {1}").format(p, e))
|
||||
# pass
|
60
glances/core/glances_timer.py
Normal file
@ -0,0 +1,60 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
#
|
||||
# This file is part of Glances.
|
||||
#
|
||||
# Copyright (C) 2014 Nicolargo <nicolas@nicolargo.com>
|
||||
#
|
||||
# Glances is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU Lesser General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# Glances is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU Lesser General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU Lesser General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
"""The timer manager."""
|
||||
|
||||
from time import time
|
||||
|
||||
# Global list to manage the elapsed time
|
||||
last_update_times = {}
|
||||
|
||||
|
||||
def getTimeSinceLastUpdate(IOType):
|
||||
"""Return the elapsed time since last update."""
|
||||
global last_update_times
|
||||
# assert(IOType in ['net', 'disk', 'process_disk'])
|
||||
current_time = time()
|
||||
last_time = last_update_times.get(IOType)
|
||||
if not last_time:
|
||||
time_since_update = 1
|
||||
else:
|
||||
time_since_update = current_time - last_time
|
||||
last_update_times[IOType] = current_time
|
||||
return time_since_update
|
||||
|
||||
|
||||
class Timer(object):
|
||||
|
||||
"""The timer class. A simple chronometer."""
|
||||
|
||||
def __init__(self, duration):
|
||||
self.duration = duration
|
||||
self.start()
|
||||
|
||||
def start(self):
|
||||
self.target = time() + self.duration
|
||||
|
||||
def reset(self):
|
||||
self.start()
|
||||
|
||||
def set(self, duration):
|
||||
self.duration = duration
|
||||
|
||||
def finished(self):
|
||||
return time() > self.target
|
47
glances/core/glances_webserver.py
Normal file
@ -0,0 +1,47 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
#
|
||||
# This file is part of Glances.
|
||||
#
|
||||
# Copyright (C) 2014 Nicolargo <nicolas@nicolargo.com>
|
||||
#
|
||||
# Glances is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU Lesser General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# Glances is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU Lesser General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU Lesser General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
"""Glances Web Interface (Bottle based)."""
|
||||
|
||||
# Import Glances libs
|
||||
from glances.core.glances_stats import GlancesStats
|
||||
from glances.outputs.glances_bottle import GlancesBottle
|
||||
|
||||
|
||||
class GlancesWebServer(object):
|
||||
|
||||
"""This class creates and manages the Glances Web server session."""
|
||||
|
||||
def __init__(self, config=None, args=None):
|
||||
# Init stats
|
||||
self.stats = GlancesStats(config)
|
||||
|
||||
# Initial system informations update
|
||||
self.stats.update()
|
||||
|
||||
# Init the Bottle Web server
|
||||
self.web = GlancesBottle(args=args)
|
||||
|
||||
def serve_forever(self):
|
||||
"""Main loop for the Web server."""
|
||||
self.web.start(self.stats)
|
||||
|
||||
def end(self):
|
||||
"""End of the Web server."""
|
||||
self.web.end()
|
@ -1,188 +0,0 @@
|
||||
/*
|
||||
Reset the sheet
|
||||
*/
|
||||
|
||||
* { margin: 0; padding: 0; }
|
||||
article, aside, details, figcaption, figure, footer, header, hgroup, nav, section { display: block; }
|
||||
[hidden] { display: none; }
|
||||
|
||||
/*
|
||||
Colors table
|
||||
* bg: background color
|
||||
* fg: foreground color
|
||||
*/
|
||||
|
||||
.bgmain { background: transparent; }
|
||||
.fgmain { color: #FFFFFF; }
|
||||
|
||||
.bghost { background: transparent; }
|
||||
.fghost { color: #E3D7BF; font-size: 50px; text-shadow: 1px 1px 1px #e88860, 2px 2px 1px #e88860, 3px 3px 1px #e88860, 3px 3px 1px #0c0d0d, 4px 4px 3px #0c0d0d;}
|
||||
|
||||
.bgsystem { background: transparent; }
|
||||
.fgsystem { color: #E88860; text-shadow: 1px 1px 1px #000; }
|
||||
|
||||
.bgcpu { background: transparent; }
|
||||
.fgcpu { color: #3C8AAD; }
|
||||
|
||||
.bgload { background: transparent; }
|
||||
.fgload { color: #3C8AAD; }
|
||||
|
||||
.bgmem { background: transparent; }
|
||||
.fgmem { color: #3C8AAD; }
|
||||
|
||||
.bgnet { background: transparent; }
|
||||
.fgnet { color: #3C8AAD; }
|
||||
|
||||
.bgdiskio { background: transparent; }
|
||||
.fgdiskio { color: #3C8AAD; }
|
||||
|
||||
.bgfs { background: transparent; }
|
||||
.fgfs { color: #3C8AAD; }
|
||||
|
||||
.bgproc { background: transparent; }
|
||||
.fgproc { color: #3C8AAD; }
|
||||
|
||||
.bgcdefault { background: transparent; }
|
||||
.fgcdefault { color: #FFFFFF; }
|
||||
.bgcok { background: #60AC39; }
|
||||
.fgcok { color: #FFFFFF; }
|
||||
.bgccareful { background: #6039AC; }
|
||||
.fgccareful { color: #FFFFFF; }
|
||||
.bgcwarning { background: #FFAA00; }
|
||||
.fgcwarning { color: #FFFFFF; }
|
||||
.bgcritical { background: #D92626; }
|
||||
.fgcritical { color: #FFFFFF; }
|
||||
|
||||
/*
|
||||
Main
|
||||
*/
|
||||
|
||||
html {
|
||||
background-image: url('../img/bg.png');
|
||||
font-size: 100%; -webkit-text-size-adjust: 100%; -ms-text-size-adjust: 100%;
|
||||
}
|
||||
html, button, input, select, textarea { font-family: sans-serif; }
|
||||
body { margin: 0; font-size: 1em; line-height: 1.4; }
|
||||
::-moz-selection { background: #fe57a1; color: #fff; text-shadow: none; }
|
||||
::selection { background: #fe57a1; color: #fff; text-shadow: none; }
|
||||
|
||||
/* Tables */
|
||||
|
||||
table{
|
||||
font-family: 'Trebuchet MS', sans-serif;
|
||||
font-size: 14px;
|
||||
font-weight: bold;
|
||||
font-style: normal;
|
||||
border-collapse: separate;
|
||||
}
|
||||
|
||||
thead th{
|
||||
padding:5px;
|
||||
border:1px solid #3C8AAD;
|
||||
-webkit-border-top-left-radius:5px;
|
||||
-webkit-border-top-right-radius:5px;
|
||||
-moz-border-radius:5px 5px 0px 0px;
|
||||
border-top-left-radius:5px;
|
||||
border-top-right-radius:5px;
|
||||
}
|
||||
|
||||
thead th:empty{
|
||||
background:transparent;
|
||||
border:none;
|
||||
}
|
||||
|
||||
tfoot td{
|
||||
font-size:16px;
|
||||
text-align:center;
|
||||
padding:10px 0px;
|
||||
}
|
||||
|
||||
tfoot th{
|
||||
}
|
||||
|
||||
tbody td{
|
||||
width:80px;
|
||||
padding:5px;
|
||||
text-align:center;
|
||||
border:1px solid #3C8AAD;
|
||||
-moz-border-radius:2px;
|
||||
-webkit-border-radius:2px;
|
||||
border-radius:2px;
|
||||
}
|
||||
|
||||
#item{
|
||||
width:60px;
|
||||
border:none;
|
||||
text-align:right;
|
||||
color: #8cf;
|
||||
}
|
||||
|
||||
#command{
|
||||
width:240px;
|
||||
font-size:11px;
|
||||
text-align:left;
|
||||
color: #8cf;
|
||||
}
|
||||
|
||||
/* Header */
|
||||
|
||||
header {
|
||||
text-align: center;
|
||||
margin-bottom: 25px;
|
||||
}
|
||||
|
||||
/* Main */
|
||||
|
||||
#main {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
#firstline, #secondline {
|
||||
margin: 0 auto;
|
||||
}
|
||||
|
||||
#secondline {
|
||||
display: inline-block;
|
||||
vertical-align: top;
|
||||
margin-top: 20px;
|
||||
}
|
||||
|
||||
#sideleft {
|
||||
width: 310px;
|
||||
float: left;
|
||||
margin-right: 25px;
|
||||
}
|
||||
|
||||
#sideright {
|
||||
width: 550px;
|
||||
float: left;
|
||||
}
|
||||
|
||||
#cpu, #load, #mem, #net, #diskio, #fs {
|
||||
display: inline-block;
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
#cpu, #load {
|
||||
margin-right: 50px;
|
||||
}
|
||||
|
||||
#diskio, #fs {
|
||||
margin-top: 25px;
|
||||
}
|
||||
|
||||
#proclist {
|
||||
margin-top: 50px;
|
||||
}
|
||||
|
||||
/* Footer */
|
||||
|
||||
footer {
|
||||
clear: both;
|
||||
margin: 20px 0px 10px 0px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
footer a {
|
||||
color: white;
|
||||
}
|
@ -1,60 +0,0 @@
|
||||
<!doctype html>
|
||||
<html>
|
||||
|
||||
<head>
|
||||
{% block head %}
|
||||
<meta charset="utf-8">
|
||||
<title>{% block title %}Glances{% endblock %}</title>
|
||||
<link rel="stylesheet" href="{% block css %}css/base.css{% endblock %}">
|
||||
{% endblock %}
|
||||
<meta http-equiv="refresh" content="{{ refresh }}" />
|
||||
</head>
|
||||
|
||||
<body class="bgmain fgmain">
|
||||
|
||||
<header>
|
||||
{% block header %}{% endblock %}
|
||||
</header>
|
||||
|
||||
<section id="main">
|
||||
<section id="firstline">
|
||||
<article id="cpu">
|
||||
{% block cpu %}{% endblock %}
|
||||
</article>
|
||||
<article id="load">
|
||||
{% block load %}{% endblock %}
|
||||
</article>
|
||||
<article id="mem">
|
||||
{% block mem %}{% endblock %}
|
||||
</article>
|
||||
</section>
|
||||
<section id="secondline">
|
||||
<section id="sideleft">
|
||||
<article id="net">
|
||||
{% block net %}{% endblock %}
|
||||
</article>
|
||||
<article id="diskio">
|
||||
{% block diskio %}{% endblock %}
|
||||
</article>
|
||||
<article id="fs">
|
||||
{% block fs %}{% endblock %}
|
||||
</article>
|
||||
</section>
|
||||
<section id="sideright">
|
||||
<article id="proccount">
|
||||
{% block proccount %}{% endblock %}
|
||||
</article>
|
||||
<article id="proclist">
|
||||
{% block proclist %}{% endblock %}
|
||||
</article>
|
||||
</section>
|
||||
</section>
|
||||
</section>
|
||||
|
||||
<footer>
|
||||
{% block footer %}{% endblock %}
|
||||
</footer>
|
||||
|
||||
</body>
|
||||
|
||||
</html>
|
@ -1,231 +0,0 @@
|
||||
{% extends "base.html" %}
|
||||
|
||||
{% block css %}css/default.css{% endblock %}
|
||||
|
||||
{% block header %}
|
||||
<h1 class="bghost fghost">Glances running on {{ host.hostname }}</h1>
|
||||
<h2 class="bgsystem fgsystem">{{ system.os_name }} {{ system.platform }} {{ system.os_version }}</h2>
|
||||
{% endblock %}
|
||||
|
||||
{% block cpu %}
|
||||
{% if cpu is defined %}
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th scope="col" class="bgcpu fgcpu"></th>
|
||||
<th scope="col" class="bgcpu fgcpu">Cpu <small>{{ (cpu.user + cpu.system + cpu.nice)|round(1) }}%</small></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td class="bgcpu fgcpu">User</td>
|
||||
<td class="{{ cpu.user_color }}">{{ cpu.user|round(1) }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="bgcpu fgcpu">System</td>
|
||||
<td class="{{ cpu.system_color }}">{{ cpu.system|round(1) }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="bgcpu fgcpu">Nice</td>
|
||||
<td class="{{ cpu.nice_color }}">{{ cpu.nice|round(1) }}</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
{% endif %}
|
||||
{% endblock %}
|
||||
|
||||
{% block load %}
|
||||
{% if (load is defined) and (core is defined) %}
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th scope="col" class="bgload fgload"></th>
|
||||
<th scope="col" class="bgload fgload">Load <small>{{ core }}-Core</small></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td class="bgload fgload">1 min</td>
|
||||
<td class="{{ load.min1_color }}">{{ load.min1|round(2) }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="bgload fgload">5 mins</td>
|
||||
<td class="{{ load.min5_color }}">{{ load.min5|round(2) }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="bgload fgload">15 mins</td>
|
||||
<td class="{{ load.min15_color }}">{{ load.min15|round(2) }}</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
{% endif %}
|
||||
{% endblock %}
|
||||
|
||||
{% block mem %}
|
||||
{% if (mem is defined) and (memswap is defined) %}
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th scope="col" class="bgmem fgmem"></th>
|
||||
<th scope="col" class="bgmem fgmem">Mem</th>
|
||||
<th scope="col" class="bgmem fgmem">Swap</th>
|
||||
<th scope="col" class="bgmem fgmem">Real</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td class="bgmem fgmem">Total</td>
|
||||
<td>{{ mem.total|filesizeformat(binary = true) }}</td>
|
||||
<td>{{ memswap.total|filesizeformat(binary = true) }}</td>
|
||||
<td></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="bgmem fgmem">Used</td>
|
||||
<td>{{ mem.used|filesizeformat(binary = true) }}</td>
|
||||
<td class="{{ memswap.used_color }}">{{ memswap.used|filesizeformat(binary = true) }}</td>
|
||||
<td class="{{ mem.used_color }}">{{ mem.used|filesizeformat(binary = true) }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="bgmem fgmem">Free</td>
|
||||
<td>{{ mem.free|filesizeformat(binary = true) }}</td>
|
||||
<td>{{ memswap.free|filesizeformat(binary = true) }}</td>
|
||||
<td>{{ mem.free|filesizeformat(binary = true) }}</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
{% endif %}
|
||||
{% endblock %}
|
||||
|
||||
{% block net %}
|
||||
{% if net is defined %}
|
||||
<table >
|
||||
<thead>
|
||||
<tr>
|
||||
<th scope="col" class="bgnet fgnet"></th>
|
||||
<th scope="col" class="bgnet fgnet">Net Rx ↓</th>
|
||||
<th scope="col" class="bgnet fgnet">Net TX ↑</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for interface in net %}
|
||||
<tr>
|
||||
<td id="item">{{ interface.interface_name }}</td>
|
||||
{% if interface.rx == 0 %}
|
||||
<td>0</td>
|
||||
{% else %}
|
||||
<td>{{ (interface.rx*8)|filesizeformat(binary = true)|replace("Bytes", "bps")|replace("Byte", "bps")|replace("iB", "bps") }}</td>
|
||||
{% endif %}
|
||||
{% if interface.tx == 0 %}
|
||||
<td>0</td>
|
||||
{% else %}
|
||||
<td>{{ (interface.tx*8)|filesizeformat(binary = true)|replace("Bytes", "bps")|replace("Byte", "bps")|replace("iB", "bps") }}</td>
|
||||
{% endif %}
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
{% endif %}
|
||||
{% endblock %}
|
||||
|
||||
{% block diskio %}
|
||||
{% if diskio is defined %}
|
||||
<table >
|
||||
<thead>
|
||||
<tr>
|
||||
<th scope="col" class="bgdiskio fgdiskio"></th>
|
||||
<th scope="col" class="bgdiskio fgdiskio">Disk Write ↓</th>
|
||||
<th scope="col" class="bgdiskio fgdiskio">Disk Read ↑</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for disk in diskio %}
|
||||
<tr>
|
||||
<td id="item">{{ disk.disk_name }}</td>
|
||||
<td>{{ disk.write_bytes|filesizeformat(binary = true) }}</td>
|
||||
<td>{{ disk.read_bytes|filesizeformat(binary = true) }}</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
{% endif %}
|
||||
{% endblock %}
|
||||
|
||||
{% block fs %}
|
||||
{% if fs is defined %}
|
||||
<table >
|
||||
<thead>
|
||||
<tr>
|
||||
<th scope="col" class="bgdiskio fgdiskio"></th>
|
||||
<th scope="col" class="bgdiskio fgdiskio">FS Size</th>
|
||||
<th scope="col" class="bgdiskio fgdiskio">FS Used</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for mount in fs %}
|
||||
<tr>
|
||||
<td id="item">{{ mount.mnt_point }}</td>
|
||||
<td>{{ mount.size|filesizeformat(binary = true) }}</td>
|
||||
<td class="{{ mount.used_color }}">{{ mount.used|filesizeformat(binary = true) }}</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
{% endif %}
|
||||
{% endblock %}
|
||||
|
||||
{% block proccount %}
|
||||
{% if (proccount is defined) %}
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th scope="col" class="bgproc fgproc"></th>
|
||||
<th scope="col" class="bgproc fgproc">Total</th>
|
||||
<th scope="col" class="bgproc fgproc">Running</th>
|
||||
<th scope="col" class="bgproc fgproc">Sleep</th>
|
||||
<th scope="col" class="bgproc fgproc">Other</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td id="item">Process</td>
|
||||
<td>{{ proccount.total }}</td>
|
||||
<td>{{ proccount.running }}</td>
|
||||
<td>{{ proccount.sleeping }}</td>
|
||||
<td>{{ proccount.total-proccount.running-proccount.sleeping }}</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
{% endif %}
|
||||
{% endblock %}
|
||||
|
||||
{% block proclist %}
|
||||
{% if proclist is defined %}
|
||||
<table >
|
||||
<thead>
|
||||
<tr>
|
||||
<th scope="col" class="bgproc fgproc">CPU %</th>
|
||||
<th scope="col" class="bgproc fgproc">Mem virt.</th>
|
||||
<th scope="col" class="bgproc fgproc">Mem resi.</th>
|
||||
<th scope="col" class="bgproc fgproc">Command</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for proc in proclist %}
|
||||
{% if loop.index > 10 %}
|
||||
{% break %}
|
||||
{% endif %}
|
||||
<tr>
|
||||
<td>{{ proc.cpu_percent }}</td>
|
||||
<td>{{ proc.memory_info.vms|filesizeformat(binary = true) }}</td>
|
||||
<td>{{ proc.memory_info.rss|filesizeformat(binary = true) }}</td>
|
||||
<td id="command">{{ proc.name|truncate(40, killwords=True) }}</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
{% endif %}
|
||||
{% endblock %}
|
||||
|
||||
{% block footer %}
|
||||
<p>Powered by <a href="https://github.com/nicolargo/glances">Glances</a></p>
|
||||
{% endblock %}
|
Before Width: | Height: | Size: 20 KiB |
4943
glances/glances.py
0
glances/outputs/__init__.py
Normal file
4
glances/outputs/bottle/footer.tpl
Normal file
@ -0,0 +1,4 @@
|
||||
</body>
|
||||
<footer>
|
||||
</footer>
|
||||
</html>
|
11
glances/outputs/bottle/header.tpl
Normal file
@ -0,0 +1,11 @@
|
||||
<!DOCTYPE HTML><html>
|
||||
<head>
|
||||
<meta http-equiv="refresh" content="{{refresh_time}}">
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0"/>
|
||||
<title>Glances</title>
|
||||
<link rel="stylesheet" type="text/css" href="normalize.css" />
|
||||
<link rel="stylesheet" type="text/css" href="style.css" />
|
||||
<script src="modernizr.custom.js"></script>
|
||||
</head>
|
||||
<body>
|
1
glances/outputs/bottle/newline.tpl
Normal file
@ -0,0 +1 @@
|
||||
<div id="newline"></div>
|
192
glances/outputs/glances_bottle.py
Normal file
@ -0,0 +1,192 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
#
|
||||
# This file is part of Glances.
|
||||
#
|
||||
# Copyright (C) 2014 Nicolargo <nicolas@nicolargo.com>
|
||||
#
|
||||
# Glances is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU Lesser General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# Glances is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU Lesser General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU Lesser General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
"""Web interface class."""
|
||||
|
||||
import os
|
||||
import sys
|
||||
|
||||
try:
|
||||
from bottle import Bottle, template, static_file, TEMPLATE_PATH
|
||||
except ImportError:
|
||||
print('Bottle module not found. Glances cannot start in web server mode.')
|
||||
sys.exit(1)
|
||||
|
||||
|
||||
class GlancesBottle(object):
|
||||
|
||||
"""This class manages the Bottle Web server."""
|
||||
|
||||
def __init__(self, args=None):
|
||||
# Init args
|
||||
self.args = args
|
||||
|
||||
# Init stats
|
||||
# Will be updated within Bottle route
|
||||
self.stats = None
|
||||
|
||||
# Init Bottle
|
||||
self._app = Bottle()
|
||||
self._route()
|
||||
|
||||
# Update the template path (glances/outputs/bottle)
|
||||
TEMPLATE_PATH.append(os.path.join(os.path.dirname(os.path.realpath(__file__)), 'bottle'))
|
||||
|
||||
# Path where the statics files are stored
|
||||
self.STATIC_PATH = os.path.join(os.path.dirname(os.path.realpath(__file__)), 'static')
|
||||
|
||||
# Define the style (CSS) list (hash table) for stats
|
||||
self.__style_list = {
|
||||
'DEFAULT': '',
|
||||
'UNDERLINE': 'underline',
|
||||
'BOLD': 'bold',
|
||||
'SORT': 'sort',
|
||||
'OK': 'ok',
|
||||
'TITLE': 'title',
|
||||
'CAREFUL': 'careful',
|
||||
'WARNING': 'warning',
|
||||
'CRITICAL': 'critical',
|
||||
'OK_LOG': 'ok_log',
|
||||
'CAREFUL_LOG': 'careful_log',
|
||||
'WARNING_LOG': 'warning_log',
|
||||
'CRITICAL_LOG': 'critical_log',
|
||||
'NICE': 'nice',
|
||||
'STATUS': 'status',
|
||||
'PROCESS': ''
|
||||
}
|
||||
|
||||
def _route(self):
|
||||
"""Define route."""
|
||||
self._app.route('/', method="GET", callback=self._index)
|
||||
self._app.route('/<refresh_time:int>', method=["GET", "POST"], callback=self._index)
|
||||
self._app.route('/<filename:re:.*\.css>', method="GET", callback=self._css)
|
||||
self._app.route('/<filename:re:.*\.js>', method="GET", callback=self._js)
|
||||
|
||||
def start(self, stats):
|
||||
"""Start the bottle."""
|
||||
# Init stats
|
||||
self.stats = stats
|
||||
|
||||
self._app.run(host=self.args.bind_address, port=self.args.port)
|
||||
|
||||
def end(self):
|
||||
"""End the bottle."""
|
||||
pass
|
||||
|
||||
def _index(self, refresh_time=None):
|
||||
"""Bottle callback for index.html (/) file."""
|
||||
# Manage parameter
|
||||
if refresh_time is None:
|
||||
refresh_time = self.args.time
|
||||
|
||||
# Update the stat
|
||||
self.stats.update()
|
||||
|
||||
# Display
|
||||
return self.display(self.stats, refresh_time=refresh_time)
|
||||
|
||||
def _css(self, filename):
|
||||
"""Bottle callback for *.css files."""
|
||||
# Return the static file
|
||||
return static_file(filename, root=os.path.join(self.STATIC_PATH, 'css'))
|
||||
|
||||
def _js(self, filename):
|
||||
"""Bottle callback for *.js files."""
|
||||
# Return the static file
|
||||
return static_file(filename, root=os.path.join(self.STATIC_PATH, 'js'))
|
||||
|
||||
def display(self, stats, refresh_time=None):
|
||||
"""Display stats on the web page.
|
||||
|
||||
stats: Stats database to display
|
||||
"""
|
||||
html = template('header', refresh_time=refresh_time)
|
||||
html += '<header>'
|
||||
html += self.display_plugin('system', self.stats.get_plugin('system').get_stats_display(args=self.args))
|
||||
html += self.display_plugin('uptime', self.stats.get_plugin('uptime').get_stats_display(args=self.args))
|
||||
html += '</header>'
|
||||
html += template('newline')
|
||||
html += '<section>'
|
||||
html += self.display_plugin('cpu', self.stats.get_plugin('cpu').get_stats_display(args=self.args))
|
||||
load_msg = self.stats.get_plugin('load').get_stats_display(args=self.args)
|
||||
if load_msg['msgdict'] != []:
|
||||
# Load is not available on all OS
|
||||
# Only display if stat is available
|
||||
html += self.display_plugin('load', load_msg)
|
||||
html += self.display_plugin('mem', self.stats.get_plugin('mem').get_stats_display(args=self.args))
|
||||
html += self.display_plugin('memswap', self.stats.get_plugin('memswap').get_stats_display(args=self.args))
|
||||
html += '</section>'
|
||||
html += template('newline')
|
||||
html += '<div>'
|
||||
html += '<aside id="lefttstats">'
|
||||
html += self.display_plugin('network', self.stats.get_plugin('network').get_stats_display(args=self.args))
|
||||
html += self.display_plugin('diskio', self.stats.get_plugin('diskio').get_stats_display(args=self.args))
|
||||
html += self.display_plugin('fs', self.stats.get_plugin('fs').get_stats_display(args=self.args))
|
||||
html += self.display_plugin('sensors', self.stats.get_plugin('sensors').get_stats_display(args=self.args))
|
||||
html += '</aside>'
|
||||
html += '<section id="rightstats">'
|
||||
html += self.display_plugin('alert', self.stats.get_plugin('alert').get_stats_display(args=self.args))
|
||||
html += self.display_plugin('processcount', self.stats.get_plugin('processcount').get_stats_display(args=self.args))
|
||||
html += self.display_plugin('monitor', self.stats.get_plugin('monitor').get_stats_display(args=self.args))
|
||||
html += self.display_plugin('processlist', self.stats.get_plugin('processlist').get_stats_display(args=self.args))
|
||||
html += '</section>'
|
||||
html += '</div>'
|
||||
html += template('newline')
|
||||
html += template('footer')
|
||||
|
||||
return html
|
||||
|
||||
def display_plugin(self, plugin_name, plugin_stats):
|
||||
"""Generate the Bottle template for the plugin_stats."""
|
||||
# Template header
|
||||
tpl = """ \
|
||||
%#Template for Bottle
|
||||
"""
|
||||
tpl += '<article class="plugin" id="%s">' % plugin_name
|
||||
|
||||
tpl += '<div id="table">'
|
||||
tpl += '<div class="row">'
|
||||
for m in plugin_stats['msgdict']:
|
||||
# New line
|
||||
if m['msg'].startswith('\n'):
|
||||
tpl += '</div>'
|
||||
tpl += '<div class="row">'
|
||||
continue
|
||||
if plugin_name == 'processlist' and m['splittable']:
|
||||
# Processlist: Display first 20 chars of the process name
|
||||
if m['msg'].split(' ', 1)[0] != '':
|
||||
tpl += '<span class="cell" id="%s"> %s</span>' % \
|
||||
(self.__style_list[m['decoration']],
|
||||
m['msg'].split(' ', 1)[0].replace(' ', ' ')[:20])
|
||||
elif m['optional']:
|
||||
# Manage optional stats (responsive design)
|
||||
tpl += '<span class="cell hide" id="%s">%s</span>' % \
|
||||
(self.__style_list[m['decoration']], m['msg'].replace(' ', ' '))
|
||||
else:
|
||||
# Display stat
|
||||
tpl += '<span class="cell" id="%s">%s</span>' % \
|
||||
(self.__style_list[m['decoration']], m['msg'].replace(' ', ' '))
|
||||
tpl += '</div>'
|
||||
tpl += '</div>'
|
||||
|
||||
tpl += """ \
|
||||
</article>
|
||||
%#End Template for Bottle
|
||||
"""
|
||||
return template(tpl)
|
174
glances/outputs/glances_colorconsole.py
Normal file
@ -0,0 +1,174 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
#
|
||||
# This file is part of Glances.
|
||||
#
|
||||
# Copyright (C) 2014 Nicolargo <nicolas@nicolargo.com>
|
||||
#
|
||||
# Glances is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU Lesser General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# Glances is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU Lesser General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU Lesser General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
import sys
|
||||
import threading
|
||||
import time
|
||||
|
||||
import msvcrt
|
||||
try:
|
||||
import colorconsole
|
||||
import colorconsole.terminal
|
||||
except ImportError:
|
||||
print('Colorconsole module not found. Glances cannot start in standalone mode.')
|
||||
sys.exit(1)
|
||||
|
||||
try:
|
||||
import queue
|
||||
except ImportError: # Python 2
|
||||
import Queue as queue
|
||||
|
||||
|
||||
class ListenGetch(threading.Thread):
|
||||
|
||||
def __init__(self, nom=''):
|
||||
threading.Thread.__init__(self)
|
||||
self.Terminated = False
|
||||
self.q = queue.Queue()
|
||||
|
||||
def run(self):
|
||||
while not self.Terminated:
|
||||
char = msvcrt.getch()
|
||||
self.q.put(char)
|
||||
|
||||
def stop(self):
|
||||
self.Terminated = True
|
||||
while not self.q.empty():
|
||||
self.q.get()
|
||||
|
||||
def get(self, default=None):
|
||||
try:
|
||||
return ord(self.q.get_nowait())
|
||||
except Exception:
|
||||
return default
|
||||
|
||||
|
||||
class Screen(object):
|
||||
|
||||
COLOR_DEFAULT_WIN = '0F' # 07'#'0F'
|
||||
COLOR_BK_DEFAULT = colorconsole.terminal.colors["BLACK"]
|
||||
COLOR_FG_DEFAULT = colorconsole.terminal.colors["WHITE"]
|
||||
|
||||
def __init__(self, nc):
|
||||
self.nc = nc
|
||||
self.term = colorconsole.terminal.get_terminal()
|
||||
# os.system('color %s' % self.COLOR_DEFAULT_WIN)
|
||||
self.listen = ListenGetch()
|
||||
self.listen.start()
|
||||
|
||||
self.term.clear()
|
||||
|
||||
def subwin(self, x, y):
|
||||
return self
|
||||
|
||||
def keypad(self, id):
|
||||
return None
|
||||
|
||||
def nodelay(self, id):
|
||||
return None
|
||||
|
||||
def getch(self):
|
||||
return self.listen.get(27)
|
||||
|
||||
def erase(self):
|
||||
self.reset()
|
||||
return None
|
||||
|
||||
def addnstr(self, y, x, msg, ln, typo=0):
|
||||
try:
|
||||
fgs, bks = self.nc.colors[typo]
|
||||
except Exception:
|
||||
fgs, bks = self.COLOR_FG_DEFAULT, self.COLOR_BK_DEFAULT
|
||||
self.term.set_color(fg=fgs, bk=bks)
|
||||
self.term.print_at(x, y, msg.ljust(ln))
|
||||
self.term.set_color(fg=self.COLOR_FG_DEFAULT, bk=self.COLOR_BK_DEFAULT)
|
||||
|
||||
def getmaxyx(self):
|
||||
x = (self.term._Terminal__get_console_info().srWindow.Right -
|
||||
self.term._Terminal__get_console_info().srWindow.Left + 1)
|
||||
y = (self.term._Terminal__get_console_info().srWindow.Bottom -
|
||||
self.term._Terminal__get_console_info().srWindow.Top + 1)
|
||||
return [y, x]
|
||||
|
||||
def reset(self):
|
||||
self.term.clear()
|
||||
self.term.reset()
|
||||
return None
|
||||
|
||||
def restore_buffered_mode(self):
|
||||
self.term.restore_buffered_mode()
|
||||
return None
|
||||
|
||||
|
||||
class WCurseLight(object):
|
||||
|
||||
COLOR_WHITE = colorconsole.terminal.colors["WHITE"]
|
||||
COLOR_RED = colorconsole.terminal.colors["RED"]
|
||||
COLOR_GREEN = colorconsole.terminal.colors["GREEN"]
|
||||
COLOR_BLUE = colorconsole.terminal.colors["LBLUE"]
|
||||
COLOR_MAGENTA = colorconsole.terminal.colors["LPURPLE"]
|
||||
COLOR_BLACK = colorconsole.terminal.colors["BLACK"]
|
||||
A_UNDERLINE = 0
|
||||
A_BOLD = 0
|
||||
COLOR_PAIRS = 9
|
||||
colors = {}
|
||||
|
||||
def __init__(self):
|
||||
self.term = Screen(self)
|
||||
|
||||
def initscr(self):
|
||||
return self.term
|
||||
|
||||
def start_color(self):
|
||||
return None
|
||||
|
||||
def use_default_colors(self):
|
||||
return None
|
||||
|
||||
def noecho(self):
|
||||
return None
|
||||
|
||||
def cbreak(self):
|
||||
return None
|
||||
|
||||
def curs_set(self, y):
|
||||
return None
|
||||
|
||||
def has_colors(self):
|
||||
return True
|
||||
|
||||
def echo(self):
|
||||
return None
|
||||
|
||||
def nocbreak(self):
|
||||
return None
|
||||
|
||||
def endwin(self):
|
||||
self.term.reset()
|
||||
self.term.restore_buffered_mode()
|
||||
self.term.listen.stop()
|
||||
|
||||
def napms(self, t):
|
||||
time.sleep(t / 1000 if t > 1000 else 1)
|
||||
|
||||
def init_pair(self, id, fg, bk):
|
||||
self.colors[id] = [max(fg, 0), max(bk, 0)]
|
||||
|
||||
def color_pair(self, id):
|
||||
return id
|
76
glances/outputs/glances_csv.py
Normal file
@ -0,0 +1,76 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
#
|
||||
# This file is part of Glances.
|
||||
#
|
||||
# Copyright (C) 2014 Nicolargo <nicolas@nicolargo.com>
|
||||
#
|
||||
# Glances is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU Lesser General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# Glances is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU Lesser General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU Lesser General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
"""CSV interface class."""
|
||||
|
||||
# Import sys libs
|
||||
import csv
|
||||
import sys
|
||||
|
||||
# Import Glances libs
|
||||
from glances.core.glances_globals import is_py3
|
||||
|
||||
# List of stats enabled in the CSV output
|
||||
csv_stats_list = ['cpu', 'load', 'mem', 'memswap']
|
||||
|
||||
|
||||
class GlancesCSV(object):
|
||||
|
||||
"""This class manages the CSV output."""
|
||||
|
||||
def __init__(self, args=None):
|
||||
# CSV file name
|
||||
self.csv_filename = args.output_csv
|
||||
|
||||
# Set the CSV output file
|
||||
try:
|
||||
if is_py3:
|
||||
self.csv_file = open(self.csv_filename, 'w', newline='')
|
||||
else:
|
||||
self.csv_file = open(self.csv_filename, 'wb')
|
||||
self.writer = csv.writer(self.csv_file)
|
||||
except IOError as e:
|
||||
print(_("Error: Cannot create the CSV file: {0}").format(e))
|
||||
sys.exit(2)
|
||||
|
||||
print(_("Stats dumped to CSV file: {0}").format(self.csv_filename))
|
||||
|
||||
def exit(self):
|
||||
"""Close the CSV file."""
|
||||
self.csv_file.close()
|
||||
|
||||
def update(self, stats):
|
||||
"""Update stats in the CSV output file."""
|
||||
all_stats = stats.getAll()
|
||||
plugins = stats.getAllPlugins()
|
||||
|
||||
# Loop over available plugin
|
||||
i = 0
|
||||
for plugin in plugins:
|
||||
if plugin in csv_stats_list:
|
||||
fieldnames = all_stats[i].keys()
|
||||
fieldvalues = all_stats[i].values()
|
||||
# First line: header
|
||||
csv_header = ['# ' + plugin + ': ' + '|'.join(fieldnames)]
|
||||
self.writer.writerow(csv_header)
|
||||
# Second line: stats
|
||||
self.writer.writerow(list(fieldvalues))
|
||||
i += 1
|
||||
|
||||
self.csv_file.flush()
|
492
glances/outputs/glances_curses.py
Normal file
@ -0,0 +1,492 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
#
|
||||
# This file is part of Glances.
|
||||
#
|
||||
# Copyright (C) 2014 Nicolargo <nicolas@nicolargo.com>
|
||||
#
|
||||
# Glances is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU Lesser General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# Glances is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU Lesser General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU Lesser General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
"""Curses interface class."""
|
||||
|
||||
# Import system lib
|
||||
import sys
|
||||
|
||||
# Import Glances lib
|
||||
from glances.core.glances_globals import glances_logs, glances_processes, is_windows
|
||||
from glances.core.glances_timer import Timer
|
||||
|
||||
# Import curses lib for "normal" operating system and consolelog for Windows
|
||||
if not is_windows:
|
||||
try:
|
||||
import curses
|
||||
import curses.panel
|
||||
except ImportError:
|
||||
print('Curses module not found. Glances cannot start in standalone mode.')
|
||||
sys.exit(1)
|
||||
else:
|
||||
from glances.outputs.glances_colorconsole import WCurseLight
|
||||
curses = WCurseLight()
|
||||
|
||||
|
||||
class GlancesCurses(object):
|
||||
|
||||
"""This class manages the curses display (and key pressed)."""
|
||||
|
||||
def __init__(self, args=None):
|
||||
# Init args
|
||||
self.args = args
|
||||
|
||||
# Init windows positions
|
||||
self.term_w = 80
|
||||
self.term_h = 24
|
||||
|
||||
# Space between stats
|
||||
self.space_between_column = 3
|
||||
self.space_between_line = 2
|
||||
|
||||
# Init the curses screen
|
||||
self.screen = curses.initscr()
|
||||
if not self.screen:
|
||||
print(_("Error: Cannot init the curses library.\n"))
|
||||
sys.exit(1)
|
||||
|
||||
# Set curses options
|
||||
if hasattr(curses, 'start_color'):
|
||||
curses.start_color()
|
||||
if hasattr(curses, 'use_default_colors'):
|
||||
curses.use_default_colors()
|
||||
if hasattr(curses, 'noecho'):
|
||||
curses.noecho()
|
||||
if hasattr(curses, 'cbreak'):
|
||||
curses.cbreak()
|
||||
if hasattr(curses, 'curs_set'):
|
||||
try:
|
||||
curses.curs_set(0)
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
# Init colors
|
||||
self.hascolors = False
|
||||
if curses.has_colors() and curses.COLOR_PAIRS > 8:
|
||||
self.hascolors = True
|
||||
# FG color, BG color
|
||||
curses.init_pair(1, curses.COLOR_WHITE, -1)
|
||||
curses.init_pair(2, curses.COLOR_WHITE, curses.COLOR_RED)
|
||||
curses.init_pair(3, curses.COLOR_WHITE, curses.COLOR_GREEN)
|
||||
curses.init_pair(4, curses.COLOR_WHITE, curses.COLOR_BLUE)
|
||||
curses.init_pair(5, curses.COLOR_WHITE, curses.COLOR_MAGENTA)
|
||||
curses.init_pair(6, curses.COLOR_RED, -1)
|
||||
curses.init_pair(7, curses.COLOR_GREEN, -1)
|
||||
curses.init_pair(8, curses.COLOR_BLUE, -1)
|
||||
curses.init_pair(9, curses.COLOR_MAGENTA, -1)
|
||||
else:
|
||||
self.hascolors = False
|
||||
|
||||
if args.disable_bold:
|
||||
A_BOLD = curses.A_BOLD
|
||||
else:
|
||||
A_BOLD = 0
|
||||
|
||||
self.title_color = A_BOLD
|
||||
self.title_underline_color = A_BOLD | curses.A_UNDERLINE
|
||||
self.help_color = A_BOLD
|
||||
if self.hascolors:
|
||||
# Colors text styles
|
||||
self.no_color = curses.color_pair(1)
|
||||
self.default_color = curses.color_pair(3) | A_BOLD
|
||||
self.nice_color = curses.color_pair(9) | A_BOLD
|
||||
self.ifCAREFUL_color = curses.color_pair(4) | A_BOLD
|
||||
self.ifWARNING_color = curses.color_pair(5) | A_BOLD
|
||||
self.ifCRITICAL_color = curses.color_pair(2) | A_BOLD
|
||||
self.default_color2 = curses.color_pair(7) | A_BOLD
|
||||
self.ifCAREFUL_color2 = curses.color_pair(8) | A_BOLD
|
||||
self.ifWARNING_color2 = curses.color_pair(9) | A_BOLD
|
||||
self.ifCRITICAL_color2 = curses.color_pair(6) | A_BOLD
|
||||
else:
|
||||
# B&W text styles
|
||||
self.no_color = curses.A_NORMAL
|
||||
self.default_color = curses.A_NORMAL
|
||||
self.nice_color = A_BOLD
|
||||
self.ifCAREFUL_color = curses.A_UNDERLINE
|
||||
self.ifWARNING_color = A_BOLD
|
||||
self.ifCRITICAL_color = curses.A_REVERSE
|
||||
self.default_color2 = curses.A_NORMAL
|
||||
self.ifCAREFUL_color2 = curses.A_UNDERLINE
|
||||
self.ifWARNING_color2 = A_BOLD
|
||||
self.ifCRITICAL_color2 = curses.A_REVERSE
|
||||
|
||||
# Define the colors list (hash table) for stats
|
||||
self.__colors_list = {
|
||||
'DEFAULT': self.no_color,
|
||||
'UNDERLINE': curses.A_UNDERLINE,
|
||||
'BOLD': A_BOLD,
|
||||
'SORT': A_BOLD,
|
||||
'OK': self.default_color2,
|
||||
'TITLE': self.title_color,
|
||||
'PROCESS': self.default_color2,
|
||||
'STATUS': self.default_color2,
|
||||
'NICE': self.nice_color,
|
||||
'CAREFUL': self.ifCAREFUL_color2,
|
||||
'WARNING': self.ifWARNING_color2,
|
||||
'CRITICAL': self.ifCRITICAL_color2,
|
||||
'OK_LOG': self.default_color,
|
||||
'CAREFUL_LOG': self.ifCAREFUL_color,
|
||||
'WARNING_LOG': self.ifWARNING_color,
|
||||
'CRITICAL_LOG': self.ifCRITICAL_color
|
||||
}
|
||||
|
||||
# Init main window
|
||||
self.term_window = self.screen.subwin(0, 0)
|
||||
|
||||
# Init refresh time
|
||||
self.__refresh_time = args.time
|
||||
|
||||
# Init process sort method
|
||||
self.args.process_sorted_by = 'auto'
|
||||
|
||||
# Catch key pressed with non blocking mode
|
||||
self.term_window.keypad(1)
|
||||
self.term_window.nodelay(1)
|
||||
self.pressedkey = -1
|
||||
|
||||
def __get_key(self, window):
|
||||
# Catch ESC key AND numlock key (issue #163)
|
||||
keycode = [0, 0]
|
||||
keycode[0] = window.getch()
|
||||
keycode[1] = window.getch()
|
||||
|
||||
if keycode[0] == 27 and keycode[1] != -1:
|
||||
# Do not escape on specials keys
|
||||
return -1
|
||||
else:
|
||||
return keycode[0]
|
||||
|
||||
def __catch_key(self):
|
||||
# Catch the pressed key
|
||||
# ~ self.pressedkey = self.term_window.getch()
|
||||
self.pressedkey = self.__get_key(self.term_window)
|
||||
|
||||
# Actions...
|
||||
if self.pressedkey == ord('\x1b') or self.pressedkey == ord('q'):
|
||||
# 'ESC'|'q' > Quit
|
||||
self.end()
|
||||
sys.exit(0)
|
||||
elif self.pressedkey == ord('1'):
|
||||
# '1' > Switch between CPU and PerCPU information
|
||||
self.args.percpu = not self.args.percpu
|
||||
elif self.pressedkey == ord('a'):
|
||||
# 'a' > Sort processes automatically
|
||||
self.args.process_sorted_by = 'auto'
|
||||
elif self.pressedkey == ord('b'):
|
||||
# 'b' > Switch between bit/s and Byte/s for network IO
|
||||
# self.net_byteps_tag = not self.net_byteps_tag
|
||||
self.args.byte = not self.args.byte
|
||||
elif self.pressedkey == ord('c'):
|
||||
# 'c' > Sort processes by CPU usage
|
||||
self.args.process_sorted_by = 'cpu_percent'
|
||||
elif self.pressedkey == ord('d'):
|
||||
# 'd' > Show/hide disk I/O stats
|
||||
self.args.disable_diskio = not self.args.disable_diskio
|
||||
elif self.pressedkey == ord('f'):
|
||||
# 'f' > Show/hide fs stats
|
||||
self.args.disable_fs = not self.args.disable_fs
|
||||
elif self.pressedkey == ord('h'):
|
||||
# 'h' > Show/hide help
|
||||
self.args.help_tag = not self.args.help_tag
|
||||
elif self.pressedkey == ord('i'):
|
||||
# 'i' > Sort processes by IO rate (not available on OS X)
|
||||
self.args.process_sorted_by = 'io_counters'
|
||||
elif self.pressedkey == ord('l'):
|
||||
# 'l' > Show/hide log messages
|
||||
self.args.disable_log = not self.args.disable_log
|
||||
elif self.pressedkey == ord('m'):
|
||||
# 'm' > Sort processes by MEM usage
|
||||
self.args.process_sorted_by = 'memory_percent'
|
||||
elif self.pressedkey == ord('n'):
|
||||
# 'n' > Show/hide network stats
|
||||
self.args.disable_network = not self.args.disable_network
|
||||
elif self.pressedkey == ord('p'):
|
||||
# 'p' > Sort processes by name
|
||||
self.args.process_sorted_by = 'name'
|
||||
elif self.pressedkey == ord('s'):
|
||||
# 's' > Show/hide sensors stats (Linux-only)
|
||||
self.args.disable_sensors = not self.args.disable_sensors
|
||||
elif self.pressedkey == ord('t'):
|
||||
# 't' > View network traffic as sum Rx+Tx
|
||||
self.args.network_sum = not self.args.network_sum
|
||||
elif self.pressedkey == ord('u'):
|
||||
# 'u' > View cumulative network IO (instead of bitrate)
|
||||
self.args.network_cumul = not self.args.network_cumul
|
||||
elif self.pressedkey == ord('w'):
|
||||
# 'w' > Delete finished warning logs
|
||||
glances_logs.clean()
|
||||
elif self.pressedkey == ord('x'):
|
||||
# 'x' > Delete finished warning and critical logs
|
||||
glances_logs.clean(critical=True)
|
||||
elif self.pressedkey == ord('z'):
|
||||
# 'z' > Enable/Disable processes stats (count + list + monitor)
|
||||
# Enable/Disable display
|
||||
self.args.disable_process = not self.args.disable_process
|
||||
# Enable/Disable update
|
||||
if self.args.disable_process:
|
||||
glances_processes.disable()
|
||||
else:
|
||||
glances_processes.enable()
|
||||
# Return the key code
|
||||
return self.pressedkey
|
||||
|
||||
def end(self):
|
||||
"""Shutdown the curses window."""
|
||||
curses.echo()
|
||||
curses.nocbreak()
|
||||
curses.curs_set(1)
|
||||
curses.endwin()
|
||||
|
||||
def display(self, stats, cs_status="None"):
|
||||
"""Display stats on the screen.
|
||||
|
||||
stats: Stats database to display
|
||||
cs_status:
|
||||
"None": standalone or server mode
|
||||
"Connected": Client is connected to a Glances server
|
||||
"SNMP": Client is connected to a SNMP server
|
||||
"Disconnected": Client is disconnected from the server
|
||||
|
||||
Return:
|
||||
True if the stats have been displayed
|
||||
False if the help have been displayed
|
||||
"""
|
||||
# Init the internal line/column dict for Glances Curses
|
||||
self.line_to_y = {}
|
||||
self.column_to_x = {}
|
||||
|
||||
# Get the screen size
|
||||
screen_x = self.screen.getmaxyx()[1]
|
||||
screen_y = self.screen.getmaxyx()[0]
|
||||
|
||||
if self.args.help_tag:
|
||||
# Display the stats...
|
||||
self.display_plugin(stats.get_plugin('help').get_stats_display(args=self.args))
|
||||
# ... and exit
|
||||
return False
|
||||
|
||||
# Update the client server status
|
||||
self.args.cs_status = cs_status
|
||||
|
||||
# Display first line (system+uptime)
|
||||
stats_system = stats.get_plugin('system').get_stats_display(args=self.args)
|
||||
stats_uptime = stats.get_plugin('uptime').get_stats_display()
|
||||
l = self.get_stats_display_width(stats_system) + self.get_stats_display_width(stats_uptime) + self.space_between_column
|
||||
self.display_plugin(stats_system, display_optional=(screen_x >= l))
|
||||
self.display_plugin(stats_uptime)
|
||||
|
||||
# Display second line (CPU|PERCPU+LOAD+MEM+SWAP+<SUMMARY>)
|
||||
# CPU|PERCPU
|
||||
if self.args.percpu:
|
||||
stats_percpu = stats.get_plugin('percpu').get_stats_display()
|
||||
l = self.get_stats_display_width(stats_percpu)
|
||||
else:
|
||||
stats_cpu = stats.get_plugin('cpu').get_stats_display()
|
||||
l = self.get_stats_display_width(stats_cpu)
|
||||
stats_load = stats.get_plugin('load').get_stats_display()
|
||||
stats_mem = stats.get_plugin('mem').get_stats_display()
|
||||
stats_memswap = stats.get_plugin('memswap').get_stats_display()
|
||||
l += self.get_stats_display_width(stats_load) + self.get_stats_display_width(stats_mem) + self.get_stats_display_width(stats_memswap)
|
||||
# Space between column
|
||||
if screen_x > (3 * self.space_between_column + l):
|
||||
self.space_between_column = int((screen_x - l) / 3)
|
||||
# Display
|
||||
if self.args.percpu:
|
||||
self.display_plugin(stats_percpu)
|
||||
else:
|
||||
self.display_plugin(stats_cpu, display_optional=(screen_x >= 80))
|
||||
self.display_plugin(stats_load)
|
||||
self.display_plugin(stats_mem, display_optional=(screen_x >= (3 * self.space_between_column + l)))
|
||||
self.display_plugin(stats_memswap)
|
||||
# Space between column
|
||||
self.space_between_column = 3
|
||||
|
||||
# Display left sidebar (NETWORK+DISKIO+FS+SENSORS)
|
||||
self.display_plugin(stats.get_plugin('network').get_stats_display(args=self.args))
|
||||
self.display_plugin(stats.get_plugin('diskio').get_stats_display(args=self.args))
|
||||
self.display_plugin(stats.get_plugin('fs').get_stats_display(args=self.args))
|
||||
self.display_plugin(stats.get_plugin('sensors').get_stats_display(args=self.args))
|
||||
# Display last line (currenttime)
|
||||
self.display_plugin(stats.get_plugin('now').get_stats_display())
|
||||
|
||||
# Display right sidebar (PROCESS_COUNT+MONITORED+PROCESS_LIST+ALERT)
|
||||
if screen_x > 52:
|
||||
stats_processcount = stats.get_plugin('processcount').get_stats_display(args=self.args)
|
||||
stats_processlist = stats.get_plugin('processlist').get_stats_display(args=self.args)
|
||||
stats_alert = stats.get_plugin('alert').get_stats_display(args=self.args)
|
||||
stats_monitor = stats.get_plugin('monitor').get_stats_display(args=self.args)
|
||||
# Display
|
||||
self.display_plugin(stats_processcount)
|
||||
self.display_plugin(stats_monitor)
|
||||
self.display_plugin(stats_processlist,
|
||||
display_optional=(screen_x > 102),
|
||||
max_y=(screen_y - self.get_stats_display_height(stats_alert) - 2))
|
||||
self.display_plugin(stats_alert)
|
||||
|
||||
return True
|
||||
|
||||
def display_plugin(self, plugin_stats, display_optional=True, max_y=65535):
|
||||
"""Display the plugin_stats on the screen.
|
||||
|
||||
If display_optional=True display the optional stats.
|
||||
max_y do not display line > max_y
|
||||
"""
|
||||
# Exit if:
|
||||
# - the plugin_stats message is empty
|
||||
# - the display tag = False
|
||||
if plugin_stats['msgdict'] == [] or not plugin_stats['display']:
|
||||
# Display the next plugin at the current plugin position
|
||||
try:
|
||||
self.column_to_x[plugin_stats['column'] + 1] = self.column_to_x[plugin_stats['column']]
|
||||
self.line_to_y[plugin_stats['line'] + 1] = self.line_to_y[plugin_stats['line']]
|
||||
except Exception:
|
||||
pass
|
||||
# Exit
|
||||
return 0
|
||||
|
||||
# Get the screen size
|
||||
screen_x = self.screen.getmaxyx()[1]
|
||||
screen_y = self.screen.getmaxyx()[0]
|
||||
|
||||
# Set the upper/left position of the message
|
||||
if plugin_stats['column'] < 0:
|
||||
# Right align (last column)
|
||||
display_x = screen_x - self.get_stats_display_width(plugin_stats)
|
||||
else:
|
||||
if plugin_stats['column'] not in self.column_to_x:
|
||||
self.column_to_x[plugin_stats['column']] = plugin_stats['column']
|
||||
display_x = self.column_to_x[plugin_stats['column']]
|
||||
if plugin_stats['line'] < 0:
|
||||
# Bottom (last line)
|
||||
display_y = screen_y - self.get_stats_display_height(plugin_stats)
|
||||
else:
|
||||
if plugin_stats['line'] not in self.line_to_y:
|
||||
self.line_to_y[plugin_stats['line']] = plugin_stats['line']
|
||||
display_y = self.line_to_y[plugin_stats['line']]
|
||||
|
||||
# Display
|
||||
x = display_x
|
||||
y = display_y
|
||||
for m in plugin_stats['msgdict']:
|
||||
# New line
|
||||
if m['msg'].startswith('\n'):
|
||||
# Go to the next line
|
||||
y = y + 1
|
||||
# Return to the first column
|
||||
x = display_x
|
||||
continue
|
||||
# Do not display outside the screen
|
||||
if x < 0:
|
||||
continue
|
||||
if not m['splittable'] and (x + len(m['msg']) > screen_x):
|
||||
continue
|
||||
if y < 0 or (y + 1 > screen_y) or (y > max_y):
|
||||
break
|
||||
# If display_optional = False do not display optional stats
|
||||
if not display_optional and m['optional']:
|
||||
continue
|
||||
# Is it possible to display the stat with the current screen size
|
||||
# !!! Crach if not try/except... Why ???
|
||||
try:
|
||||
self.term_window.addnstr(y, x,
|
||||
m['msg'],
|
||||
screen_x - x, # Do not disply outside the screen
|
||||
self.__colors_list[m['decoration']])
|
||||
except:
|
||||
pass
|
||||
else:
|
||||
# New column
|
||||
x = x + len(m['msg'])
|
||||
|
||||
# Compute the next Glances column/line position
|
||||
if plugin_stats['column'] > -1:
|
||||
self.column_to_x[plugin_stats['column'] + 1] = x + self.space_between_column
|
||||
if plugin_stats['line'] > -1:
|
||||
self.line_to_y[plugin_stats['line'] + 1] = y + self.space_between_line
|
||||
|
||||
def erase(self):
|
||||
"""Erase the content of the screen."""
|
||||
self.term_window.erase()
|
||||
|
||||
def flush(self, stats, cs_status="None"):
|
||||
"""Clear and update the screen.
|
||||
|
||||
stats: Stats database to display
|
||||
cs_status:
|
||||
"None": standalone or server mode
|
||||
"Connected": Client is connected to the server
|
||||
"Disconnected": Client is disconnected from the server
|
||||
"""
|
||||
self.erase()
|
||||
self.display(stats, cs_status=cs_status)
|
||||
|
||||
def update(self, stats, cs_status="None"):
|
||||
"""Update the screen.
|
||||
|
||||
Wait for __refresh_time sec / catch key every 100 ms.
|
||||
|
||||
stats: Stats database to display
|
||||
cs_status:
|
||||
"None": standalone or server mode
|
||||
"Connected": Client is connected to the server
|
||||
"Disconnected": Client is disconnected from the server
|
||||
"""
|
||||
# Flush display
|
||||
self.flush(stats, cs_status=cs_status)
|
||||
|
||||
# Wait
|
||||
countdown = Timer(self.__refresh_time)
|
||||
while not countdown.finished():
|
||||
# Getkey
|
||||
if self.__catch_key() > -1:
|
||||
# flush display
|
||||
self.flush(stats, cs_status=cs_status)
|
||||
# Wait 100ms...
|
||||
curses.napms(100)
|
||||
|
||||
def get_stats_display_width(self, curse_msg, without_option=False):
|
||||
"""Return the width of the formatted curses message.
|
||||
|
||||
The height is defined by the maximum line.
|
||||
"""
|
||||
try:
|
||||
if without_option:
|
||||
# Size without options
|
||||
c = len(max(''.join([(i['msg'] if not i['optional'] else "")
|
||||
for i in curse_msg['msgdict']]).split('\n'), key=len))
|
||||
else:
|
||||
# Size with all options
|
||||
c = len(max(''.join([i['msg']
|
||||
for i in curse_msg['msgdict']]).split('\n'), key=len))
|
||||
except:
|
||||
return 0
|
||||
else:
|
||||
return c
|
||||
|
||||
def get_stats_display_height(self, curse_msg):
|
||||
r"""Return the height of the formatted curses message.
|
||||
|
||||
The height is defined by the number of '\n' (new line).
|
||||
"""
|
||||
try:
|
||||
c = [i['msg'] for i in curse_msg['msgdict']].count('\n')
|
||||
except:
|
||||
return 0
|
||||
else:
|
||||
return c + 1
|
1
glances/outputs/static/css/normalize.css
vendored
Normal file
@ -0,0 +1 @@
|
||||
article,aside,details,figcaption,figure,footer,header,hgroup,main,nav,section,summary{display:block;}audio,canvas,video{display:inline-block;}audio:not([controls]){display:none;height:0;}[hidden]{display:none;}html{font-family:sans-serif;-ms-text-size-adjust:100%;-webkit-text-size-adjust:100%;}body{margin:0;}a:focus{outline:thin dotted;}a:active,a:hover{outline:0;}h1{font-size:2em;margin:0.67em 0;}abbr[title]{border-bottom:1px dotted;}b,strong{font-weight:bold;}dfn{font-style:italic;}hr{-moz-box-sizing:content-box;box-sizing:content-box;height:0;}mark{background:#ff0;color:#000;}code,kbd,pre,samp{font-family:monospace,serif;font-size:1em;}pre{white-space:pre-wrap;}q{quotes:"\201C" "\201D" "\2018" "\2019";}small{font-size:80%;}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline;}sup{top:-0.5em;}sub{bottom:-0.25em;}img{border:0;}svg:not(:root){overflow:hidden;}figure{margin:0;}fieldset{border:1px solid #c0c0c0;margin:0 2px;padding:0.35em 0.625em 0.75em;}legend{border:0;padding:0;}button,input,select,textarea{font-family:inherit;font-size:100%;margin:0;}button,input{line-height:normal;}button,select{text-transform:none;}button,html input[type="button"],input[type="reset"],input[type="submit"]{-webkit-appearance:button;cursor:pointer;}button[disabled],html input[disabled]{cursor:default;}input[type="checkbox"],input[type="radio"]{box-sizing:border-box;padding:0;}input[type="search"]{-webkit-appearance:textfield;-moz-box-sizing:content-box;-webkit-box-sizing:content-box;box-sizing:content-box;}input[type="search"]::-webkit-search-cancel-button,input[type="search"]::-webkit-search-decoration{-webkit-appearance:none;}button::-moz-focus-inner,input::-moz-focus-inner{border:0;padding:0;}textarea{overflow:auto;vertical-align:top;}table{border-collapse:collapse;border-spacing:0;}
|
157
glances/outputs/static/css/style.css
Normal file
@ -0,0 +1,157 @@
|
||||
body {
|
||||
background: black;
|
||||
color: #BBB;
|
||||
font-family: "Lucida Sans Typewriter", "Lucida Console", Monaco, "Bitstream Vera Sans Mono", monospace;
|
||||
font-size: 100%;
|
||||
}
|
||||
header,footer,
|
||||
article,section,
|
||||
hgroup,nav,
|
||||
figure,div,aside {
|
||||
display: block;
|
||||
}
|
||||
section {
|
||||
text-align: justify;
|
||||
}
|
||||
section > article {
|
||||
display: inline-block;
|
||||
vertical-align: top;
|
||||
*display: inline;
|
||||
zoom: 1;
|
||||
}
|
||||
section:after {
|
||||
content: "";
|
||||
width: 100%;
|
||||
display: inline-block;
|
||||
}
|
||||
aside {
|
||||
float: left;
|
||||
margin-right: 2%;
|
||||
}
|
||||
div#newline{
|
||||
clear: both;
|
||||
height: 1em;
|
||||
}
|
||||
#underline{
|
||||
text-decoration: underline
|
||||
}
|
||||
#bold{
|
||||
font-weight: bold;
|
||||
}
|
||||
#sort{
|
||||
font-weight: bold;
|
||||
}
|
||||
#sort:after{
|
||||
content: '\25BC'
|
||||
}
|
||||
/*Theme*/
|
||||
#title{
|
||||
font-weight: bold;
|
||||
color: white;
|
||||
}
|
||||
#table {
|
||||
display: table;
|
||||
}
|
||||
.row {
|
||||
display: table-row;
|
||||
}
|
||||
.cell {
|
||||
display: table-cell;
|
||||
}
|
||||
#ok {
|
||||
color: green;
|
||||
}
|
||||
#ok_log {
|
||||
background-color: green;
|
||||
color: white;
|
||||
}
|
||||
#careful {
|
||||
color: blueviolet;
|
||||
}
|
||||
#careful_log {
|
||||
background-color: blueviolet;
|
||||
color: white;
|
||||
}
|
||||
#warning {
|
||||
color: orange;
|
||||
}
|
||||
#warning_log {
|
||||
background-color: orange;
|
||||
color: white;
|
||||
}
|
||||
#critical {
|
||||
color: red;
|
||||
}
|
||||
#critical_log {
|
||||
background-color: red;
|
||||
color: white;
|
||||
}
|
||||
#nice {
|
||||
color: magenta;
|
||||
}
|
||||
#status {
|
||||
color: green;
|
||||
}
|
||||
/*Plugins*/
|
||||
#system {
|
||||
float: left;
|
||||
}
|
||||
#uptime {
|
||||
float: right;
|
||||
}
|
||||
#cpu {}
|
||||
#load {}
|
||||
#mem {}
|
||||
#memswap {}
|
||||
#leftstats {}
|
||||
#network {
|
||||
margin-bottom: 1em;
|
||||
}
|
||||
#diskio {
|
||||
margin-bottom: 1em;
|
||||
}
|
||||
#fs {
|
||||
margin-bottom: 1em;
|
||||
}
|
||||
#sensors {}
|
||||
#rightstats {}
|
||||
#alert {
|
||||
display: block;
|
||||
}
|
||||
#processcount {
|
||||
display: block;
|
||||
margin: 1em;
|
||||
}
|
||||
#monitor {
|
||||
display: block;
|
||||
margin: 1em;
|
||||
}
|
||||
#processlist {}
|
||||
/*
|
||||
article#processlist>div>div>span:last-child {
|
||||
visibility: hidden;
|
||||
white-space: nowrap;
|
||||
}
|
||||
*/
|
||||
#now {}
|
||||
/*Responsive design*/
|
||||
@media only screen and (max-width: 1600px) {
|
||||
body { font-size:90%; }
|
||||
}
|
||||
@media only screen and (max-width: 1280px) {
|
||||
body { font-size:80%; }
|
||||
}
|
||||
@media only screen and (max-width: 1024px) {
|
||||
body { font-size:80%; }
|
||||
#processlist .hide { display: none; }
|
||||
}
|
||||
@media only screen and (max-width: 768px) {
|
||||
body { font-size:70%; }
|
||||
aside { margin-right: 1%; }
|
||||
.hide { display: none; }
|
||||
}
|
||||
@media only screen and (max-width: 480px) {
|
||||
body { font-size:60%; }
|
||||
aside { margin-right: 1%; }
|
||||
.hide { display: none; }
|
||||
}
|
4
glances/outputs/static/js/modernizr.custom.js
Executable file
0
glances/plugins/__init__.py
Normal file
124
glances/plugins/glances_alert.py
Normal file
@ -0,0 +1,124 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
#
|
||||
# This file is part of Glances.
|
||||
#
|
||||
# Copyright (C) 2014 Nicolargo <nicolas@nicolargo.com>
|
||||
#
|
||||
# Glances is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU Lesser General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# Glances is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU Lesser General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU Lesser General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
"""Alert plugin."""
|
||||
|
||||
# Import system lib
|
||||
from datetime import datetime
|
||||
|
||||
# Import Glances libs
|
||||
from glances.core.glances_globals import glances_logs
|
||||
from glances.plugins.glances_plugin import GlancesPlugin
|
||||
|
||||
|
||||
class Plugin(GlancesPlugin):
|
||||
|
||||
"""Glances' alert plugin.
|
||||
|
||||
Only for display.
|
||||
"""
|
||||
|
||||
def __init__(self, args=None):
|
||||
"""Init the plugin."""
|
||||
GlancesPlugin.__init__(self, args=args)
|
||||
|
||||
# We want to display the stat in the curse interface
|
||||
self.display_curse = True
|
||||
# Set the message position
|
||||
# It is NOT the curse position but the Glances column/line
|
||||
# Enter -1 to right align
|
||||
self.column_curse = 1
|
||||
# Enter -1 to diplay bottom
|
||||
self.line_curse = -1
|
||||
|
||||
# Init the stats
|
||||
self.reset()
|
||||
|
||||
def reset(self):
|
||||
"""Reset/init the stats."""
|
||||
self.stats = []
|
||||
|
||||
def update(self):
|
||||
"""Nothing to do here. Just return the global glances_log."""
|
||||
# Set the stats to the glances_logs
|
||||
self.stats = glances_logs.get()
|
||||
|
||||
def msg_curse(self, args=None):
|
||||
"""Return the dict to display in the curse interface."""
|
||||
# Init the return message
|
||||
ret = []
|
||||
|
||||
# Only process if display plugin enable...
|
||||
if args.disable_log:
|
||||
return ret
|
||||
|
||||
# Build the string message
|
||||
# Header
|
||||
if self.stats == []:
|
||||
msg = _("No warning or critical alert detected")
|
||||
ret.append(self.curse_add_line(msg, "TITLE"))
|
||||
else:
|
||||
# Header
|
||||
msg = _("Warning or critical alerts")
|
||||
ret.append(self.curse_add_line(msg, "TITLE"))
|
||||
logs_len = glances_logs.len()
|
||||
if logs_len > 1:
|
||||
msg = _(" (lasts {0} entries)").format(logs_len)
|
||||
else:
|
||||
msg = _(" (one entry)")
|
||||
ret.append(self.curse_add_line(msg, "TITLE"))
|
||||
# Loop over alerts
|
||||
for alert in self.stats:
|
||||
# New line
|
||||
ret.append(self.curse_new_line())
|
||||
# Start
|
||||
msg = str(datetime.fromtimestamp(alert[0]))
|
||||
ret.append(self.curse_add_line(msg))
|
||||
# Duration
|
||||
if alert[1] > 0:
|
||||
# If finished display duration
|
||||
msg = ' ({0})'.format(datetime.fromtimestamp(alert[1]) - datetime.fromtimestamp(alert[0]))
|
||||
else:
|
||||
msg = _(" (ongoing)")
|
||||
ret.append(self.curse_add_line(msg))
|
||||
ret.append(self.curse_add_line(" - "))
|
||||
# Infos
|
||||
if alert[1] > 0:
|
||||
# If finished do not display status
|
||||
msg = _("{0} on {1}").format(alert[2], alert[3])
|
||||
ret.append(self.curse_add_line(msg))
|
||||
else:
|
||||
msg = str(alert[3])
|
||||
ret.append(self.curse_add_line(msg, decoration=alert[2]))
|
||||
# Min / Mean / Max
|
||||
if alert[6] == alert[4]:
|
||||
msg = ' ({0:.1f})'.format(alert[5])
|
||||
else:
|
||||
msg = _(" (Min:{0:.1f} Mean:{1:.1f} Max:{2:.1f})").format(alert[6], alert[5], alert[4])
|
||||
ret.append(self.curse_add_line(msg))
|
||||
|
||||
# else:
|
||||
# msg = _(" Running...")
|
||||
# ret.append(self.curse_add_line(msg))
|
||||
|
||||
# !!! Debug only
|
||||
# msg = ' | {0}'.format(alert)
|
||||
# ret.append(self.curse_add_line(msg))
|
||||
|
||||
return ret
|
122
glances/plugins/glances_batpercent.py
Normal file
@ -0,0 +1,122 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
#
|
||||
# This file is part of Glances.
|
||||
#
|
||||
# Copyright (C) 2014 Nicolargo <nicolas@nicolargo.com>
|
||||
#
|
||||
# Glances is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU Lesser General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# Glances is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU Lesser General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU Lesser General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
"""Battery plugin."""
|
||||
|
||||
# Batinfo library (optional; Linux-only)
|
||||
try:
|
||||
import batinfo
|
||||
except ImportError:
|
||||
pass
|
||||
|
||||
# Import Glances libs
|
||||
from glances.plugins.glances_plugin import GlancesPlugin
|
||||
|
||||
|
||||
class Plugin(GlancesPlugin):
|
||||
|
||||
"""Glances' battery capacity plugin.
|
||||
|
||||
stats is a list
|
||||
"""
|
||||
|
||||
def __init__(self, args=None):
|
||||
"""Init the plugin."""
|
||||
GlancesPlugin.__init__(self, args=args)
|
||||
|
||||
# Init the sensor class
|
||||
self.glancesgrabbat = GlancesGrabBat()
|
||||
|
||||
# We do not want to display the stat in a dedicated area
|
||||
# The HDD temp is displayed within the sensors plugin
|
||||
self.display_curse = False
|
||||
|
||||
# Init stats
|
||||
self.reset()
|
||||
|
||||
def reset(self):
|
||||
"""Reset/init the stats."""
|
||||
self.stats = []
|
||||
|
||||
def update(self):
|
||||
"""Update battery capacity stats using the input method."""
|
||||
# Reset stats
|
||||
self.reset()
|
||||
|
||||
if self.get_input() == 'local':
|
||||
# Update stats
|
||||
self.glancesgrabbat.update()
|
||||
self.stats = self.glancesgrabbat.get()
|
||||
|
||||
elif self.get_input() == 'snmp':
|
||||
# Update stats using SNMP
|
||||
# Not avalaible
|
||||
pass
|
||||
|
||||
return self.stats
|
||||
|
||||
|
||||
class GlancesGrabBat(object):
|
||||
|
||||
"""Get batteries stats using the batinfo library."""
|
||||
|
||||
def __init__(self):
|
||||
"""Init batteries stats."""
|
||||
try:
|
||||
self.bat = batinfo.batteries()
|
||||
self.initok = True
|
||||
self.bat_list = []
|
||||
self.update()
|
||||
except Exception:
|
||||
# print(_("Warning: Cannot grab battery sensor. Missing BatInfo library."))
|
||||
self.initok = False
|
||||
|
||||
def update(self):
|
||||
"""Update the stats."""
|
||||
if self.initok:
|
||||
reply = self.bat.update()
|
||||
if reply is not None:
|
||||
self.bat_list = []
|
||||
new_item = {'label': _("Battery (%)"),
|
||||
'value': self.getcapacitypercent()}
|
||||
self.bat_list.append(new_item)
|
||||
else:
|
||||
self.bat_list = []
|
||||
|
||||
def get(self):
|
||||
"""Get the stats."""
|
||||
return self.bat_list
|
||||
|
||||
def getcapacitypercent(self):
|
||||
"""Get batteries capacity percent."""
|
||||
if not self.initok or self.bat.stat == []:
|
||||
return []
|
||||
|
||||
# Init the bsum (sum of percent) and bcpt (number of batteries)
|
||||
# and Loop over batteries (yes a computer could have more than 1 battery)
|
||||
bsum = 0
|
||||
for bcpt in range(len(self.bat.stat)):
|
||||
try:
|
||||
bsum = bsum + int(self.bat.stat[bcpt].capacity)
|
||||
except ValueError:
|
||||
return []
|
||||
bcpt = bcpt + 1
|
||||
|
||||
# Return the global percent
|
||||
return int(bsum / bcpt)
|
78
glances/plugins/glances_core.py
Normal file
@ -0,0 +1,78 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
#
|
||||
# This file is part of Glances.
|
||||
#
|
||||
# Copyright (C) 2014 Nicolargo <nicolas@nicolargo.com>
|
||||
#
|
||||
# Glances is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU Lesser General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# Glances is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU Lesser General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU Lesser General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
"""CPU core plugin."""
|
||||
|
||||
from glances.plugins.glances_plugin import GlancesPlugin
|
||||
|
||||
import psutil
|
||||
|
||||
|
||||
class Plugin(GlancesPlugin):
|
||||
|
||||
"""Glances' CPU core plugin.
|
||||
|
||||
Get stats about CPU core number.
|
||||
|
||||
stats is integer (number of core)
|
||||
"""
|
||||
|
||||
def __init__(self, args=None):
|
||||
"""Init the plugin."""
|
||||
GlancesPlugin.__init__(self, args=args)
|
||||
|
||||
# We dot not want to display the stat in the curse interface
|
||||
# The core number is displayed by the load plugin
|
||||
self.display_curse = False
|
||||
|
||||
# Init the stat
|
||||
self.reset()
|
||||
|
||||
def reset(self):
|
||||
"""Reset/init the stat using the input method."""
|
||||
self.stats = {}
|
||||
|
||||
def update(self):
|
||||
"""Update core stats.
|
||||
|
||||
Stats is a dict (with both physical and log cpu number) instead of a integer.
|
||||
"""
|
||||
# Reset the stats
|
||||
self.reset()
|
||||
|
||||
if self.get_input() == 'local':
|
||||
# Update stats using the standard system lib
|
||||
|
||||
# The PSUtil 2.0 include psutil.cpu_count() and psutil.cpu_count(logical=False)
|
||||
# Return a dict with:
|
||||
# - phys: physical cores only (hyper thread CPUs are excluded)
|
||||
# - log: logical CPUs in the system
|
||||
# Return None if undefine
|
||||
try:
|
||||
self.stats["phys"] = psutil.cpu_count(logical=False)
|
||||
self.stats["log"] = psutil.cpu_count()
|
||||
except NameError:
|
||||
self.reset()
|
||||
|
||||
elif self.get_input() == 'snmp':
|
||||
# Update stats using SNMP
|
||||
# http://stackoverflow.com/questions/5662467/how-to-find-out-the-number-of-cpus-using-snmp
|
||||
pass
|
||||
|
||||
return self.stats
|
171
glances/plugins/glances_cpu.py
Normal file
@ -0,0 +1,171 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
#
|
||||
# This file is part of Glances.
|
||||
#
|
||||
# Copyright (C) 2014 Nicolargo <nicolas@nicolargo.com>
|
||||
#
|
||||
# Glances is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU Lesser General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# Glances is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU Lesser General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU Lesser General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
"""CPU plugin."""
|
||||
|
||||
from glances.plugins.glances_plugin import GlancesPlugin
|
||||
|
||||
import psutil
|
||||
|
||||
# SNMP OID
|
||||
# percentage of user CPU time: .1.3.6.1.4.1.2021.11.9.0
|
||||
# percentages of system CPU time: .1.3.6.1.4.1.2021.11.10.0
|
||||
# percentages of idle CPU time: .1.3.6.1.4.1.2021.11.11.0
|
||||
snmp_oid = {'user': '1.3.6.1.4.1.2021.11.9.0',
|
||||
'system': '1.3.6.1.4.1.2021.11.10.0',
|
||||
'idle': '1.3.6.1.4.1.2021.11.11.0'}
|
||||
|
||||
|
||||
class Plugin(GlancesPlugin):
|
||||
|
||||
"""
|
||||
Glances' CPU plugin.
|
||||
|
||||
stats is a dict
|
||||
"""
|
||||
|
||||
def __init__(self, args=None):
|
||||
"""Init the CPU plugin."""
|
||||
GlancesPlugin.__init__(self, args=args)
|
||||
|
||||
# We want to display the stat in the curse interface
|
||||
self.display_curse = True
|
||||
# Set the message position
|
||||
# It is NOT the curse position but the Glances column/line
|
||||
# Enter -1 to right align
|
||||
self.column_curse = 0
|
||||
# Enter -1 to diplay bottom
|
||||
self.line_curse = 1
|
||||
|
||||
# Init stats
|
||||
self.first_call = True
|
||||
self.reset()
|
||||
|
||||
def reset(self):
|
||||
"""Reset/init the stats."""
|
||||
self.stats = {}
|
||||
|
||||
def update(self):
|
||||
"""Update CPU stats using the input method."""
|
||||
# Reset stats
|
||||
self.reset()
|
||||
|
||||
if self.get_input() == 'local':
|
||||
# Update stats using the standard system lib
|
||||
|
||||
# Grab CPU using the PSUtil cpu_times_percent method
|
||||
cputimespercent = psutil.cpu_times_percent(interval=0.0, percpu=False)
|
||||
|
||||
# Get all possible value for CPU stats
|
||||
# user
|
||||
# system
|
||||
# idle
|
||||
# nice (UNIX)
|
||||
# iowait (Linux)
|
||||
# irq (Linux, FreeBSD)
|
||||
# softirq (Linux)
|
||||
# steal (Linux >= 2.6.11)
|
||||
# The following stats are returned by the API but not displayed in the UI:
|
||||
# guest (Linux >= 2.6.24)
|
||||
# guest_nice (Linux >= 3.2.0)
|
||||
for cpu in ['user', 'system', 'idle', 'nice',
|
||||
'iowait', 'irq', 'softirq', 'steal',
|
||||
'guest', 'guest_nice']:
|
||||
if hasattr(cputimespercent, cpu):
|
||||
self.stats[cpu] = getattr(cputimespercent, cpu)
|
||||
elif self.get_input() == 'snmp':
|
||||
# Update stats using SNMP
|
||||
self.stats = self.set_stats_snmp(snmp_oid=snmp_oid)
|
||||
|
||||
if self.stats['user'] == '':
|
||||
self.reset()
|
||||
return self.stats
|
||||
|
||||
for key in self.stats.iterkeys():
|
||||
self.stats[key] = float(self.stats[key])
|
||||
|
||||
return self.stats
|
||||
|
||||
def msg_curse(self, args=None):
|
||||
"""Return the list to display in the curse interface."""
|
||||
# Init the return message
|
||||
ret = []
|
||||
|
||||
# Only process if stats exist...
|
||||
if self.stats == {}:
|
||||
return ret
|
||||
|
||||
# Build the string message
|
||||
# Header
|
||||
msg = '{0:8}'.format(_("CPU"))
|
||||
ret.append(self.curse_add_line(msg, "TITLE"))
|
||||
# Total CPU usage
|
||||
msg = '{0:>6.1%}'.format((100 - self.stats['idle']) / 100)
|
||||
ret.append(self.curse_add_line(msg))
|
||||
# Nice CPU
|
||||
if 'nice' in self.stats:
|
||||
msg = ' {0:8}'.format(_("nice:"))
|
||||
ret.append(self.curse_add_line(msg, optional=True))
|
||||
msg = '{0:>6.1%}'.format(self.stats['nice'] / 100)
|
||||
ret.append(self.curse_add_line(msg, optional=True))
|
||||
# New line
|
||||
ret.append(self.curse_new_line())
|
||||
# User CPU
|
||||
if 'user' in self.stats:
|
||||
msg = '{0:8}'.format(_("user:"))
|
||||
ret.append(self.curse_add_line(msg))
|
||||
msg = '{0:>6.1%}'.format(self.stats['user'] / 100)
|
||||
ret.append(self.curse_add_line(msg, self.get_alert_log(self.stats['user'], header="user")))
|
||||
# IRQ CPU
|
||||
if 'irq' in self.stats:
|
||||
msg = ' {0:8}'.format(_("irq:"))
|
||||
ret.append(self.curse_add_line(msg, optional=True))
|
||||
msg = '{0:>6.1%}'.format(self.stats['irq'] / 100)
|
||||
ret.append(self.curse_add_line(msg, optional=True))
|
||||
# New line
|
||||
ret.append(self.curse_new_line())
|
||||
# System CPU
|
||||
if 'system' in self.stats:
|
||||
msg = '{0:8}'.format(_("system:"))
|
||||
ret.append(self.curse_add_line(msg))
|
||||
msg = '{0:>6.1%}'.format(self.stats['system'] / 100)
|
||||
ret.append(self.curse_add_line(msg, self.get_alert_log(self.stats['system'], header="system")))
|
||||
# IOWait CPU
|
||||
if 'iowait' in self.stats:
|
||||
msg = ' {0:8}'.format(_("iowait:"))
|
||||
ret.append(self.curse_add_line(msg, optional=True))
|
||||
msg = '{0:>6.1%}'.format(self.stats['iowait'] / 100)
|
||||
ret.append(self.curse_add_line(msg, self.get_alert_log(self.stats['iowait'], header="iowait"), optional=True))
|
||||
# New line
|
||||
ret.append(self.curse_new_line())
|
||||
# Idle CPU
|
||||
if 'idle' in self.stats:
|
||||
msg = '{0:8}'.format(_("idle:"))
|
||||
ret.append(self.curse_add_line(msg))
|
||||
msg = '{0:>6.1%}'.format(self.stats['idle'] / 100)
|
||||
ret.append(self.curse_add_line(msg))
|
||||
# Steal CPU usage
|
||||
if 'steal' in self.stats:
|
||||
msg = ' {0:8}'.format(_("steal:"))
|
||||
ret.append(self.curse_add_line(msg, optional=True))
|
||||
msg = '{0:>6.1%}'.format(self.stats['steal'] / 100)
|
||||
ret.append(self.curse_add_line(msg, self.get_alert(self.stats['steal'], header="steal"), optional=True))
|
||||
|
||||
# Return the message with decoration
|
||||
return ret
|
153
glances/plugins/glances_diskio.py
Normal file
@ -0,0 +1,153 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
#
|
||||
# This file is part of Glances.
|
||||
#
|
||||
# Copyright (C) 2014 Nicolargo <nicolas@nicolargo.com>
|
||||
#
|
||||
# Glances is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU Lesser General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# Glances is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU Lesser General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU Lesser General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
"""Disk I/O plugin."""
|
||||
|
||||
# Import Glances libs
|
||||
from glances.core.glances_timer import getTimeSinceLastUpdate
|
||||
from glances.plugins.glances_plugin import GlancesPlugin
|
||||
|
||||
import psutil
|
||||
|
||||
|
||||
class Plugin(GlancesPlugin):
|
||||
|
||||
"""Glances' disks I/O plugin.
|
||||
|
||||
stats is a list
|
||||
"""
|
||||
|
||||
def __init__(self, args=None):
|
||||
"""Init the plugin."""
|
||||
GlancesPlugin.__init__(self, args=args)
|
||||
|
||||
# We want to display the stat in the curse interface
|
||||
self.display_curse = True
|
||||
# Set the message position
|
||||
# It is NOT the curse position but the Glances column/line
|
||||
# Enter -1 to right align
|
||||
self.column_curse = 0
|
||||
# Enter -1 to diplay bottom
|
||||
self.line_curse = 3
|
||||
|
||||
# Init the stats
|
||||
self.reset()
|
||||
|
||||
def reset(self):
|
||||
"""Reset/init the stats."""
|
||||
self.stats = []
|
||||
|
||||
def update(self):
|
||||
"""Update disk I/O stats using the input method."""
|
||||
# Reset stats
|
||||
self.reset()
|
||||
|
||||
if self.get_input() == 'local':
|
||||
# Update stats using the standard system lib
|
||||
# Grab the stat using the PsUtil disk_io_counters method
|
||||
# read_count: number of reads
|
||||
# write_count: number of writes
|
||||
# read_bytes: number of bytes read
|
||||
# write_bytes: number of bytes written
|
||||
# read_time: time spent reading from disk (in milliseconds)
|
||||
# write_time: time spent writing to disk (in milliseconds)
|
||||
try:
|
||||
diskiocounters = psutil.disk_io_counters(perdisk=True)
|
||||
except:
|
||||
return self.stats
|
||||
|
||||
# Previous disk IO stats are stored in the diskio_old variable
|
||||
if not hasattr(self, 'diskio_old'):
|
||||
# First call, we init the network_old var
|
||||
try:
|
||||
self.diskio_old = diskiocounters
|
||||
except (IOError, UnboundLocalError):
|
||||
pass
|
||||
else:
|
||||
# By storing time data we enable Rx/s and Tx/s calculations in the
|
||||
# XML/RPC API, which would otherwise be overly difficult work
|
||||
# for users of the API
|
||||
time_since_update = getTimeSinceLastUpdate('disk')
|
||||
|
||||
diskio_new = diskiocounters
|
||||
for disk in diskio_new:
|
||||
try:
|
||||
# Try necessary to manage dynamic disk creation/del
|
||||
diskstat = {}
|
||||
diskstat['time_since_update'] = time_since_update
|
||||
diskstat['disk_name'] = disk
|
||||
diskstat['read_bytes'] = (
|
||||
diskio_new[disk].read_bytes -
|
||||
self.diskio_old[disk].read_bytes)
|
||||
diskstat['write_bytes'] = (
|
||||
diskio_new[disk].write_bytes -
|
||||
self.diskio_old[disk].write_bytes)
|
||||
except KeyError:
|
||||
continue
|
||||
else:
|
||||
self.stats.append(diskstat)
|
||||
|
||||
# Save stats to compute next bitrate
|
||||
self.diskio_old = diskio_new
|
||||
elif self.get_input() == 'snmp':
|
||||
# Update stats using SNMP
|
||||
# No standard way for the moment...
|
||||
pass
|
||||
|
||||
return self.stats
|
||||
|
||||
def msg_curse(self, args=None):
|
||||
"""Return the dict to display in the curse interface."""
|
||||
# Init the return message
|
||||
ret = []
|
||||
|
||||
# Only process if stats exist and display plugin enable...
|
||||
if self.stats == [] or args.disable_diskio:
|
||||
return ret
|
||||
|
||||
# Build the string message
|
||||
# Header
|
||||
msg = '{0:9}'.format(_("DISK I/O"))
|
||||
ret.append(self.curse_add_line(msg, "TITLE"))
|
||||
msg = '{0:>7}'.format(_("R/s"))
|
||||
ret.append(self.curse_add_line(msg))
|
||||
msg = '{0:>7}'.format(_("W/s"))
|
||||
ret.append(self.curse_add_line(msg))
|
||||
# Disk list (sorted by name)
|
||||
for i in sorted(self.stats, key=lambda diskio: diskio['disk_name']):
|
||||
# Do not display hidden interfaces
|
||||
if self.is_hide(i['disk_name']):
|
||||
continue
|
||||
# New line
|
||||
ret.append(self.curse_new_line())
|
||||
if len(i['disk_name']) > 9:
|
||||
# Cut disk name if it is too long
|
||||
disk_name = '_' + i['disk_name'][-8:]
|
||||
else:
|
||||
disk_name = i['disk_name']
|
||||
msg = '{0:9}'.format(disk_name)
|
||||
ret.append(self.curse_add_line(msg))
|
||||
txps = self.auto_unit(int(i['read_bytes'] // i['time_since_update']))
|
||||
rxps = self.auto_unit(int(i['write_bytes'] // i['time_since_update']))
|
||||
msg = '{0:>7}'.format(txps)
|
||||
ret.append(self.curse_add_line(msg))
|
||||
msg = '{0:>7}'.format(rxps)
|
||||
ret.append(self.curse_add_line(msg))
|
||||
|
||||
return ret
|
164
glances/plugins/glances_fs.py
Normal file
@ -0,0 +1,164 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
#
|
||||
# This file is part of Glances.
|
||||
#
|
||||
# Copyright (C) 2014 Nicolargo <nicolas@nicolargo.com>
|
||||
#
|
||||
# Glances is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU Lesser General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# Glances is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU Lesser General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU Lesser General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
"""File system plugin."""
|
||||
|
||||
from glances.plugins.glances_plugin import GlancesPlugin
|
||||
|
||||
import psutil
|
||||
|
||||
# SNMP OID
|
||||
# The snmpd.conf needs to be edited.
|
||||
# Add the following to enable it on all disk
|
||||
# ...
|
||||
# includeAllDisks 10%
|
||||
# ...
|
||||
# The OIDs are as follows (for the first disk)
|
||||
# Path where the disk is mounted: .1.3.6.1.4.1.2021.9.1.2.1
|
||||
# Path of the device for the partition: .1.3.6.1.4.1.2021.9.1.3.1
|
||||
# Total size of the disk/partion (kBytes): .1.3.6.1.4.1.2021.9.1.6.1
|
||||
# Available space on the disk: .1.3.6.1.4.1.2021.9.1.7.1
|
||||
# Used space on the disk: .1.3.6.1.4.1.2021.9.1.8.1
|
||||
# Percentage of space used on disk: .1.3.6.1.4.1.2021.9.1.9.1
|
||||
# Percentage of inodes used on disk: .1.3.6.1.4.1.2021.9.1.10.1
|
||||
snmp_oid = {'mnt_point': '1.3.6.1.4.1.2021.9.1.2',
|
||||
'device_name': '1.3.6.1.4.1.2021.9.1.3',
|
||||
'size': '1.3.6.1.4.1.2021.9.1.6',
|
||||
'used': '1.3.6.1.4.1.2021.9.1.8',
|
||||
'percent': '1.3.6.1.4.1.2021.9.1.9'}
|
||||
|
||||
|
||||
class Plugin(GlancesPlugin):
|
||||
|
||||
"""Glances' file system plugin.
|
||||
|
||||
stats is a list
|
||||
"""
|
||||
|
||||
def __init__(self, args=None):
|
||||
"""Init the plugin."""
|
||||
GlancesPlugin.__init__(self, args=args)
|
||||
|
||||
# We want to display the stat in the curse interface
|
||||
self.display_curse = True
|
||||
# Set the message position
|
||||
# It is NOT the curse position but the Glances column/line
|
||||
# Enter -1 to right align
|
||||
self.column_curse = 0
|
||||
# Enter -1 to diplay bottom
|
||||
self.line_curse = 4
|
||||
|
||||
# Init the stats
|
||||
self.reset()
|
||||
|
||||
def reset(self):
|
||||
"""Reset/init the stats."""
|
||||
self.stats = []
|
||||
|
||||
def update(self):
|
||||
"""Update the FS stats using the input method."""
|
||||
# Reset the list
|
||||
self.reset()
|
||||
|
||||
if self.get_input() == 'local':
|
||||
# Update stats using the standard system lib
|
||||
|
||||
# Grab the stats using the PsUtil disk_partitions
|
||||
# If 'all'=False return physical devices only (e.g. hard disks, cd-rom drives, USB keys)
|
||||
# and ignore all others (e.g. memory partitions such as /dev/shm)
|
||||
try:
|
||||
fs_stat = psutil.disk_partitions(all=False)
|
||||
except UnicodeDecodeError:
|
||||
return self.stats
|
||||
|
||||
# Loop over fs
|
||||
for fs in range(len(fs_stat)):
|
||||
fs_current = {}
|
||||
fs_current['device_name'] = fs_stat[fs].device
|
||||
fs_current['fs_type'] = fs_stat[fs].fstype
|
||||
fs_current['mnt_point'] = fs_stat[fs].mountpoint
|
||||
# Grab the disk usage
|
||||
try:
|
||||
fs_usage = psutil.disk_usage(fs_current['mnt_point'])
|
||||
except OSError:
|
||||
# Correct issue #346
|
||||
# Disk is ejected during the command
|
||||
continue
|
||||
fs_current['size'] = fs_usage.total
|
||||
fs_current['used'] = fs_usage.used
|
||||
# fs_current['avail'] = fs_usage.free
|
||||
fs_current['percent'] = fs_usage.percent
|
||||
self.stats.append(fs_current)
|
||||
|
||||
elif self.get_input() == 'snmp':
|
||||
# Update stats using SNMP
|
||||
|
||||
# SNMP bulk command to get all file system in one shot
|
||||
fs_stat = self.set_stats_snmp(snmp_oid=snmp_oid, bulk=True)
|
||||
|
||||
# Loop over fs
|
||||
for fs in fs_stat:
|
||||
fs_current = {}
|
||||
fs_current['device_name'] = fs_stat[fs]['device_name']
|
||||
fs_current['mnt_point'] = fs
|
||||
fs_current['size'] = int(fs_stat[fs]['size']) * 1024
|
||||
fs_current['used'] = int(fs_stat[fs]['used']) * 1024
|
||||
fs_current['percent'] = float(fs_stat[fs]['percent'])
|
||||
self.stats.append(fs_current)
|
||||
|
||||
return self.stats
|
||||
|
||||
def msg_curse(self, args=None):
|
||||
"""Return the dict to display in the curse interface."""
|
||||
# Init the return message
|
||||
ret = []
|
||||
|
||||
# Only process if stats exist and display plugin enable...
|
||||
if self.stats == [] or args.disable_fs:
|
||||
return ret
|
||||
|
||||
# Build the string message
|
||||
# Header
|
||||
msg = '{0:9}'.format(_("FILE SYS"))
|
||||
ret.append(self.curse_add_line(msg, "TITLE"))
|
||||
msg = '{0:>7}'.format(_("Used"))
|
||||
ret.append(self.curse_add_line(msg))
|
||||
msg = '{0:>7}'.format(_("Total"))
|
||||
ret.append(self.curse_add_line(msg))
|
||||
|
||||
# Disk list (sorted by name)
|
||||
for i in sorted(self.stats, key=lambda fs: fs['mnt_point']):
|
||||
# New line
|
||||
ret.append(self.curse_new_line())
|
||||
if len(i['mnt_point']) + len(i['device_name'].split('/')[-1]) <= 6:
|
||||
# If possible concatenate mode info... Glances touch inside :)
|
||||
mnt_point = i['mnt_point'] + ' (' + i['device_name'].split('/')[-1] + ')'
|
||||
elif len(i['mnt_point']) > 9:
|
||||
# Cut mount point name if it is too long
|
||||
mnt_point = '_' + i['mnt_point'][-8:]
|
||||
else:
|
||||
mnt_point = i['mnt_point']
|
||||
msg = '{0:9}'.format(mnt_point)
|
||||
ret.append(self.curse_add_line(msg))
|
||||
msg = '{0:>7}'.format(self.auto_unit(i['used']))
|
||||
ret.append(self.curse_add_line(msg, self.get_alert(i['used'], max=i['size'])))
|
||||
msg = '{0:>7}'.format(self.auto_unit(i['size']))
|
||||
ret.append(self.curse_add_line(msg))
|
||||
|
||||
return ret
|
134
glances/plugins/glances_hddtemp.py
Normal file
@ -0,0 +1,134 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
#
|
||||
# This file is part of Glances.
|
||||
#
|
||||
# Copyright (C) 2014 Nicolargo <nicolas@nicolargo.com>
|
||||
#
|
||||
# Glances is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU Lesser General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# Glances is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU Lesser General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU Lesser General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
"""HDD temperature plugin."""
|
||||
|
||||
# Import system libs
|
||||
import socket
|
||||
|
||||
# Import Glances libs
|
||||
from glances.plugins.glances_plugin import GlancesPlugin
|
||||
|
||||
|
||||
class Plugin(GlancesPlugin):
|
||||
|
||||
"""Glances' HDD temperature sensors plugin.
|
||||
|
||||
stats is a list
|
||||
"""
|
||||
|
||||
def __init__(self, args=None):
|
||||
"""Init the plugin."""
|
||||
GlancesPlugin.__init__(self, args=args)
|
||||
|
||||
# Init the sensor class
|
||||
self.glancesgrabhddtemp = GlancesGrabHDDTemp()
|
||||
|
||||
# We do not want to display the stat in a dedicated area
|
||||
# The HDD temp is displayed within the sensors plugin
|
||||
self.display_curse = False
|
||||
|
||||
# Init stats
|
||||
self.reset()
|
||||
|
||||
def reset(self):
|
||||
"""Reset/init the stats."""
|
||||
self.stats = []
|
||||
|
||||
def update(self):
|
||||
"""Update HDD stats using the input method."""
|
||||
# Reset stats
|
||||
self.reset()
|
||||
|
||||
if self.get_input() == 'local':
|
||||
# Update stats using the standard system lib
|
||||
self.stats = self.glancesgrabhddtemp.get()
|
||||
|
||||
else:
|
||||
# Update stats using SNMP
|
||||
# Not available for the moment
|
||||
pass
|
||||
|
||||
return self.stats
|
||||
|
||||
|
||||
class GlancesGrabHDDTemp(object):
|
||||
|
||||
"""Get hddtemp stats using a socket connection."""
|
||||
|
||||
def __init__(self, host='127.0.0.1', port=7634):
|
||||
"""Init hddtemp stats."""
|
||||
self.host = host
|
||||
self.port = port
|
||||
self.cache = ""
|
||||
self.reset()
|
||||
|
||||
def reset(self):
|
||||
"""Reset/init the stats."""
|
||||
self.hddtemp_list = []
|
||||
|
||||
def __update__(self):
|
||||
"""Update the stats."""
|
||||
# Reset the list
|
||||
self.reset()
|
||||
|
||||
# Fetch the data
|
||||
data = self.fetch()
|
||||
|
||||
# Exit if no data
|
||||
if data == "":
|
||||
return
|
||||
|
||||
# Safety check to avoid malformed data
|
||||
# Considering the size of "|/dev/sda||0||" as the minimum
|
||||
if len(data) < 14:
|
||||
data = self.cache if len(self.cache) > 0 else self.fetch()
|
||||
self.cache = data
|
||||
|
||||
try:
|
||||
fields = data.split(b'|')
|
||||
except TypeError:
|
||||
fields = ""
|
||||
devices = (len(fields) - 1) // 5
|
||||
for item in range(devices):
|
||||
offset = item * 5
|
||||
hddtemp_current = {}
|
||||
device = fields[offset + 1].split(b'/dev/')[-1]
|
||||
temperature = fields[offset + 3]
|
||||
hddtemp_current['label'] = device.decode('utf-8')
|
||||
hddtemp_current['value'] = temperature.decode('utf-8')
|
||||
self.hddtemp_list.append(hddtemp_current)
|
||||
|
||||
def fetch(self):
|
||||
"""Fetch the data from hddtemp daemon."""
|
||||
# Taking care of sudden deaths/stops of hddtemp daemon
|
||||
try:
|
||||
sck = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
||||
sck.connect((self.host, self.port))
|
||||
data = sck.recv(4096)
|
||||
sck.close()
|
||||
except socket.error:
|
||||
data = ""
|
||||
|
||||
return data
|
||||
|
||||
def get(self):
|
||||
"""Get HDDs list."""
|
||||
self.__update__()
|
||||
return self.hddtemp_list
|
119
glances/plugins/glances_help.py
Normal file
@ -0,0 +1,119 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
#
|
||||
# This file is part of Glances.
|
||||
#
|
||||
# Copyright (C) 2014 Nicolargo <nicolas@nicolargo.com>
|
||||
#
|
||||
# Glances is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU Lesser General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# Glances is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU Lesser General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU Lesser General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
"""
|
||||
Help plugin.
|
||||
|
||||
Just a stupid plugin to display the help screen.
|
||||
"""
|
||||
|
||||
# Import Glances libs
|
||||
from glances.core.glances_globals import appname, psutil_version, version
|
||||
from glances.plugins.glances_plugin import GlancesPlugin
|
||||
|
||||
|
||||
class Plugin(GlancesPlugin):
|
||||
|
||||
"""Glances' help plugin."""
|
||||
|
||||
def __init__(self, args=None):
|
||||
"""Init the plugin."""
|
||||
GlancesPlugin.__init__(self, args=args)
|
||||
|
||||
# We want to display the stat in the curse interface
|
||||
self.display_curse = True
|
||||
# Set the message position
|
||||
# It is NOT the curse position but the Glances column/line
|
||||
# Enter -1 to right align
|
||||
self.column_curse = 0
|
||||
# Enter -1 to diplay bottom
|
||||
self.line_curse = 0
|
||||
|
||||
def update(self):
|
||||
"""No stats. It is just a plugin to display the help."""
|
||||
pass
|
||||
|
||||
def msg_curse(self, args=None):
|
||||
"""Return the list to display in the curse interface."""
|
||||
# Init the return message
|
||||
ret = []
|
||||
|
||||
# Build the string message
|
||||
# Header
|
||||
msg = '{0} {1}'.format(appname.title(), version)
|
||||
ret.append(self.curse_add_line(msg, "TITLE"))
|
||||
msg = _(" with psutil {0}").format(psutil_version)
|
||||
ret.append(self.curse_add_line(msg))
|
||||
ret.append(self.curse_new_line())
|
||||
|
||||
# Keys
|
||||
msg_col = ' {0:1} {1:35}'
|
||||
msg_col2 = ' {0:1} {1:35}'
|
||||
|
||||
ret.append(self.curse_new_line())
|
||||
msg = msg_col.format(_("a"), _("Sort processes automatically"))
|
||||
ret.append(self.curse_add_line(msg))
|
||||
msg = msg_col2.format(_("b"), _("Bytes or bits for network I/O"))
|
||||
ret.append(self.curse_add_line(msg))
|
||||
ret.append(self.curse_new_line())
|
||||
msg = msg_col.format(_("c"), _("Sort processes by CPU%"))
|
||||
ret.append(self.curse_add_line(msg))
|
||||
msg = msg_col2.format(_("l"), _("Show/hide logs (alerts)"))
|
||||
ret.append(self.curse_add_line(msg))
|
||||
ret.append(self.curse_new_line())
|
||||
msg = msg_col.format(_("m"), _("Sort processes by MEM%"))
|
||||
ret.append(self.curse_add_line(msg))
|
||||
msg = msg_col2.format(_("w"), _("Delete warning alerts"))
|
||||
ret.append(self.curse_add_line(msg))
|
||||
ret.append(self.curse_new_line())
|
||||
msg = msg_col.format(_("p"), _("Sort processes by name"))
|
||||
ret.append(self.curse_add_line(msg))
|
||||
msg = msg_col2.format(_("x"), _("Delete warning and critical alerts"))
|
||||
ret.append(self.curse_add_line(msg))
|
||||
ret.append(self.curse_new_line())
|
||||
msg = msg_col.format(_("i"), _("Sort processes by I/O rate"))
|
||||
ret.append(self.curse_add_line(msg))
|
||||
msg = msg_col2.format(_("1"), _("Global CPU or per-CPU stats"))
|
||||
ret.append(self.curse_add_line(msg))
|
||||
ret.append(self.curse_new_line())
|
||||
msg = msg_col.format(_("d"), _("Show/hide disk I/O stats"))
|
||||
ret.append(self.curse_add_line(msg))
|
||||
msg = msg_col2.format(_("h"), _("Show/hide this help screen"))
|
||||
ret.append(self.curse_add_line(msg))
|
||||
ret.append(self.curse_new_line())
|
||||
msg = msg_col.format(_("f"), _("Show/hide file system stats"))
|
||||
ret.append(self.curse_add_line(msg))
|
||||
msg = msg_col2.format(_("t"), _("View network I/O as combination"))
|
||||
ret.append(self.curse_add_line(msg))
|
||||
ret.append(self.curse_new_line())
|
||||
msg = msg_col.format(_("n"), _("Show/hide network stats"))
|
||||
ret.append(self.curse_add_line(msg))
|
||||
msg = msg_col2.format(_("u"), _("View cumulative network I/O"))
|
||||
ret.append(self.curse_add_line(msg))
|
||||
ret.append(self.curse_new_line())
|
||||
msg = msg_col.format(_("s"), _("Show/hide sensors stats"))
|
||||
ret.append(self.curse_add_line(msg))
|
||||
msg = msg_col2.format(_("z"), _("Enable/disable processes stats"))
|
||||
ret.append(self.curse_add_line(msg))
|
||||
ret.append(self.curse_new_line())
|
||||
msg = msg_col.format(_("q"), _("Quit (Esc and Ctrl-C also work)"))
|
||||
ret.append(self.curse_add_line(msg))
|
||||
|
||||
# Return the message with decoration
|
||||
return ret
|
145
glances/plugins/glances_load.py
Normal file
@ -0,0 +1,145 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
#
|
||||
# This file is part of Glances.
|
||||
#
|
||||
# Copyright (C) 2014 Nicolargo <nicolas@nicolargo.com>
|
||||
#
|
||||
# Glances is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU Lesser General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# Glances is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU Lesser General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU Lesser General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
"""Load plugin."""
|
||||
|
||||
# Import system libs
|
||||
import os
|
||||
|
||||
# Import Glances libs
|
||||
from glances.plugins.glances_core import Plugin as CorePlugin
|
||||
from glances.plugins.glances_plugin import GlancesPlugin
|
||||
|
||||
# SNMP OID
|
||||
# 1 minute Load: .1.3.6.1.4.1.2021.10.1.3.1
|
||||
# 5 minute Load: .1.3.6.1.4.1.2021.10.1.3.2
|
||||
# 15 minute Load: .1.3.6.1.4.1.2021.10.1.3.3
|
||||
snmp_oid = {'min1': '1.3.6.1.4.1.2021.10.1.3.1',
|
||||
'min5': '1.3.6.1.4.1.2021.10.1.3.2',
|
||||
'min15': '1.3.6.1.4.1.2021.10.1.3.3'}
|
||||
|
||||
|
||||
class Plugin(GlancesPlugin):
|
||||
|
||||
"""Glances' load plugin.
|
||||
|
||||
stats is a dict
|
||||
"""
|
||||
|
||||
def __init__(self, args=None):
|
||||
"""Init the plugin."""
|
||||
GlancesPlugin.__init__(self, args=args)
|
||||
|
||||
# We want to display the stat in the curse interface
|
||||
self.display_curse = True
|
||||
# Set the message position
|
||||
# It is NOT the curse position but the Glances column/line
|
||||
# Enter -1 to right align
|
||||
self.column_curse = 1
|
||||
# Enter -1 to diplay bottom
|
||||
self.line_curse = 1
|
||||
|
||||
# Init stats
|
||||
self.reset()
|
||||
|
||||
def reset(self):
|
||||
"""Reset/init the stats."""
|
||||
self.stats = {}
|
||||
|
||||
def update(self):
|
||||
"""Update load stats."""
|
||||
# Reset stats
|
||||
self.reset()
|
||||
|
||||
# Call CorePlugin in order to display the core number
|
||||
try:
|
||||
nb_log_core = CorePlugin().update()["log"]
|
||||
except Exception:
|
||||
nb_log_core = 0
|
||||
|
||||
if self.get_input() == 'local':
|
||||
# Update stats using the standard system lib
|
||||
|
||||
# Get the load using the os standard lib
|
||||
try:
|
||||
load = os.getloadavg()
|
||||
except (OSError, AttributeError):
|
||||
self.stats = {}
|
||||
else:
|
||||
self.stats = {'min1': load[0],
|
||||
'min5': load[1],
|
||||
'min15': load[2],
|
||||
'cpucore': nb_log_core}
|
||||
elif self.get_input() == 'snmp':
|
||||
# Update stats using SNMP
|
||||
self.stats = self.set_stats_snmp(snmp_oid=snmp_oid)
|
||||
|
||||
self.stats['cpucore'] = nb_log_core
|
||||
|
||||
if self.stats['min1'] == '':
|
||||
self.reset()
|
||||
return self.stats
|
||||
|
||||
for key in self.stats.iterkeys():
|
||||
self.stats[key] = float(self.stats[key])
|
||||
|
||||
return self.stats
|
||||
|
||||
def msg_curse(self, args=None):
|
||||
"""Return the dict to display in the curse interface."""
|
||||
# Init the return message
|
||||
ret = []
|
||||
|
||||
# Only process if stats exist...
|
||||
if self.stats == {}:
|
||||
return ret
|
||||
|
||||
# Build the string message
|
||||
# Header
|
||||
msg = '{0:8}'.format(_("LOAD"))
|
||||
ret.append(self.curse_add_line(msg, "TITLE"))
|
||||
# Core number
|
||||
if self.stats['cpucore'] > 0:
|
||||
msg = _("{0}-core").format(self.stats['cpucore'], '>1')
|
||||
ret.append(self.curse_add_line(msg))
|
||||
# New line
|
||||
ret.append(self.curse_new_line())
|
||||
# 1min load
|
||||
msg = '{0:8}'.format(_("1 min:"))
|
||||
ret.append(self.curse_add_line(msg))
|
||||
msg = '{0:>6.2f}'.format(self.stats['min1'])
|
||||
ret.append(self.curse_add_line(msg))
|
||||
# New line
|
||||
ret.append(self.curse_new_line())
|
||||
# 5min load
|
||||
msg = '{0:8}'.format(_("5 min:"))
|
||||
ret.append(self.curse_add_line(msg))
|
||||
msg = '{0:>6.2f}'.format(self.stats['min5'])
|
||||
ret.append(self.curse_add_line(
|
||||
msg, self.get_alert(self.stats['min5'], max=100 * self.stats['cpucore'])))
|
||||
# New line
|
||||
ret.append(self.curse_new_line())
|
||||
# 15min load
|
||||
msg = '{0:8}'.format(_("15 min:"))
|
||||
ret.append(self.curse_add_line(msg))
|
||||
msg = '{0:>6.2f}'.format(self.stats['min15'])
|
||||
ret.append(self.curse_add_line(
|
||||
msg, self.get_alert_log(self.stats['min15'], max=100 * self.stats['cpucore'])))
|
||||
|
||||
return ret
|
193
glances/plugins/glances_mem.py
Normal file
@ -0,0 +1,193 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
#
|
||||
# This file is part of Glances.
|
||||
#
|
||||
# Copyright (C) 2014 Nicolargo <nicolas@nicolargo.com>
|
||||
#
|
||||
# Glances is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU Lesser General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# Glances is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU Lesser General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU Lesser General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
"""Virtual memory plugin."""
|
||||
|
||||
from glances.plugins.glances_plugin import GlancesPlugin
|
||||
|
||||
import psutil
|
||||
|
||||
# SNMP OID
|
||||
# Total RAM in machine: .1.3.6.1.4.1.2021.4.5.0
|
||||
# Total RAM used: .1.3.6.1.4.1.2021.4.6.0
|
||||
# Total RAM Free: .1.3.6.1.4.1.2021.4.11.0
|
||||
# Total RAM Shared: .1.3.6.1.4.1.2021.4.13.0
|
||||
# Total RAM Buffered: .1.3.6.1.4.1.2021.4.14.0
|
||||
# Total Cached Memory: .1.3.6.1.4.1.2021.4.15.0
|
||||
snmp_oid = {'total': '1.3.6.1.4.1.2021.4.5.0',
|
||||
# 'used': '1.3.6.1.4.1.2021.4.6.0',
|
||||
'free': '1.3.6.1.4.1.2021.4.11.0',
|
||||
'shared': '1.3.6.1.4.1.2021.4.13.0',
|
||||
'buffers': '1.3.6.1.4.1.2021.4.14.0',
|
||||
'cached': '1.3.6.1.4.1.2021.4.15.0'}
|
||||
|
||||
|
||||
class Plugin(GlancesPlugin):
|
||||
|
||||
"""Glances' memory plugin.
|
||||
|
||||
stats is a dict
|
||||
"""
|
||||
|
||||
def __init__(self, args=None):
|
||||
"""Init the plugin."""
|
||||
GlancesPlugin.__init__(self, args=args)
|
||||
|
||||
# We want to display the stat in the curse interface
|
||||
self.display_curse = True
|
||||
# Set the message position
|
||||
# It is NOT the curse position but the Glances column/line
|
||||
# Enter -1 to right align
|
||||
self.column_curse = 2
|
||||
# Enter -1 to diplay bottom
|
||||
self.line_curse = 1
|
||||
|
||||
# Init the stats
|
||||
self.reset()
|
||||
|
||||
def reset(self):
|
||||
"""Reset/init the stats."""
|
||||
self.stats = {}
|
||||
|
||||
def update(self):
|
||||
"""Update RAM memory stats using the input method."""
|
||||
# Reset stats
|
||||
self.reset()
|
||||
|
||||
if self.get_input() == 'local':
|
||||
# Update stats using the standard system lib
|
||||
# Grab MEM using the PSUtil virtual_memory method
|
||||
vm_stats = psutil.virtual_memory()
|
||||
|
||||
# Get all the memory stats (copy/paste of the PsUtil documentation)
|
||||
# total: total physical memory available.
|
||||
# available: the actual amount of available memory that can be given instantly to processes that request more memory in bytes; this is calculated by summing different memory values depending on the platform (e.g. free + buffers + cached on Linux) and it is supposed to be used to monitor actual memory usage in a cross platform fashion.
|
||||
# percent: the percentage usage calculated as (total - available) / total * 100.
|
||||
# used: memory used, calculated differently depending on the platform and designed for informational purposes only.
|
||||
# free: memory not being used at all (zeroed) that is readily available; note that this doesn’t reflect the actual memory available (use ‘available’ instead).
|
||||
# Platform-specific fields:
|
||||
# active: (UNIX): memory currently in use or very recently used, and so it is in RAM.
|
||||
# inactive: (UNIX): memory that is marked as not used.
|
||||
# buffers: (Linux, BSD): cache for things like file system metadata.
|
||||
# cached: (Linux, BSD): cache for various things.
|
||||
# wired: (BSD, OSX): memory that is marked to always stay in RAM. It is never moved to disk.
|
||||
# shared: (BSD): memory that may be simultaneously accessed by multiple processes.
|
||||
self.stats = {}
|
||||
for mem in ['total', 'available', 'percent', 'used', 'free',
|
||||
'active', 'inactive', 'buffers', 'cached',
|
||||
'wired', 'shared']:
|
||||
if hasattr(vm_stats, mem):
|
||||
self.stats[mem] = getattr(vm_stats, mem)
|
||||
|
||||
# Use the 'free'/htop calculation
|
||||
# free=available+buffer+cached
|
||||
self.stats['free'] = self.stats['available']
|
||||
if hasattr(self.stats, 'buffers'):
|
||||
self.stats['free'] += self.stats['buffers']
|
||||
if hasattr(self.stats, 'cached'):
|
||||
self.stats['free'] += self.stats['cached']
|
||||
# used=total-free
|
||||
self.stats['used'] = self.stats['total'] - self.stats['free']
|
||||
elif self.get_input() == 'snmp':
|
||||
# Update stats using SNMP
|
||||
self.stats = self.set_stats_snmp(snmp_oid=snmp_oid)
|
||||
|
||||
if self.stats['total'] == '':
|
||||
self.reset()
|
||||
return self.stats
|
||||
|
||||
for key in self.stats.iterkeys():
|
||||
if self.stats[key] != '':
|
||||
self.stats[key] = float(self.stats[key]) * 1024
|
||||
|
||||
# Use the 'free'/htop calculation
|
||||
self.stats['free'] = self.stats['free'] - self.stats['total'] + (self.stats['buffers'] + self.stats['cached'])
|
||||
|
||||
# used=total-free
|
||||
self.stats['used'] = self.stats['total'] - self.stats['free']
|
||||
|
||||
# percent: the percentage usage calculated as (total - available) / total * 100.
|
||||
self.stats['percent'] = float((self.stats['total'] - self.stats['free']) / self.stats['total'] * 100)
|
||||
|
||||
return self.stats
|
||||
|
||||
def msg_curse(self, args=None):
|
||||
"""Return the dict to display in the curse interface."""
|
||||
# Init the return message
|
||||
ret = []
|
||||
|
||||
# Only process if stats exist...
|
||||
if self.stats == {}:
|
||||
return ret
|
||||
|
||||
# Build the string message
|
||||
# Header
|
||||
msg = '{0:5} '.format(_("MEM"))
|
||||
ret.append(self.curse_add_line(msg, "TITLE"))
|
||||
# Percent memory usage
|
||||
msg = '{0:>7.1%}'.format(self.stats['percent'] / 100)
|
||||
ret.append(self.curse_add_line(msg))
|
||||
# Active memory usage
|
||||
if 'active' in self.stats:
|
||||
msg = ' {0:9}'.format(_("active:"))
|
||||
ret.append(self.curse_add_line(msg, optional=True))
|
||||
msg = '{0:>7}'.format(self.auto_unit(self.stats['active']))
|
||||
ret.append(self.curse_add_line(msg, optional=True))
|
||||
# New line
|
||||
ret.append(self.curse_new_line())
|
||||
# Total memory usage
|
||||
msg = '{0:6}'.format(_("total:"))
|
||||
ret.append(self.curse_add_line(msg))
|
||||
msg = '{0:>7}'.format(self.auto_unit(self.stats['total']))
|
||||
ret.append(self.curse_add_line(msg))
|
||||
# Inactive memory usage
|
||||
if 'inactive' in self.stats:
|
||||
msg = ' {0:9}'.format(_("inactive:"))
|
||||
ret.append(self.curse_add_line(msg, optional=True))
|
||||
msg = '{0:>7}'.format(self.auto_unit(self.stats['inactive']))
|
||||
ret.append(self.curse_add_line(msg, optional=True))
|
||||
# New line
|
||||
ret.append(self.curse_new_line())
|
||||
# Used memory usage
|
||||
msg = '{0:6}'.format(_("used:"))
|
||||
ret.append(self.curse_add_line(msg))
|
||||
msg = '{0:>7}'.format(self.auto_unit(self.stats['used']))
|
||||
ret.append(self.curse_add_line(
|
||||
msg, self.get_alert_log(self.stats['used'], max=self.stats['total'])))
|
||||
# Buffers memory usage
|
||||
if 'buffers' in self.stats:
|
||||
msg = ' {0:9}'.format(_("buffers:"))
|
||||
ret.append(self.curse_add_line(msg, optional=True))
|
||||
msg = '{0:>7}'.format(self.auto_unit(self.stats['buffers']))
|
||||
ret.append(self.curse_add_line(msg, optional=True))
|
||||
# New line
|
||||
ret.append(self.curse_new_line())
|
||||
# Free memory usage
|
||||
msg = '{0:6}'.format(_("free:"))
|
||||
ret.append(self.curse_add_line(msg))
|
||||
msg = '{0:>7}'.format(self.auto_unit(self.stats['free']))
|
||||
ret.append(self.curse_add_line(msg))
|
||||
# Cached memory usage
|
||||
if 'cached' in self.stats:
|
||||
msg = ' {0:9}'.format(_("cached:"))
|
||||
ret.append(self.curse_add_line(msg, optional=True))
|
||||
msg = '{0:>7}'.format(self.auto_unit(self.stats['cached']))
|
||||
ret.append(self.curse_add_line(msg, optional=True))
|
||||
|
||||
return ret
|
140
glances/plugins/glances_memswap.py
Normal file
@ -0,0 +1,140 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
#
|
||||
# This file is part of Glances.
|
||||
#
|
||||
# Copyright (C) 2014 Nicolargo <nicolas@nicolargo.com>
|
||||
#
|
||||
# Glances is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU Lesser General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# Glances is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU Lesser General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU Lesser General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
"""Swap memory plugin."""
|
||||
|
||||
from glances.plugins.glances_plugin import GlancesPlugin
|
||||
|
||||
import psutil
|
||||
|
||||
# SNMP OID
|
||||
# Total Swap Size: .1.3.6.1.4.1.2021.4.3.0
|
||||
# Available Swap Space: .1.3.6.1.4.1.2021.4.4.0
|
||||
snmp_oid = {'total': '1.3.6.1.4.1.2021.4.3.0',
|
||||
'free': '1.3.6.1.4.1.2021.4.4.0'}
|
||||
|
||||
|
||||
class Plugin(GlancesPlugin):
|
||||
|
||||
"""Glances' swap memory plugin.
|
||||
|
||||
stats is a dict
|
||||
"""
|
||||
|
||||
def __init__(self, args=None):
|
||||
"""Init the plugin."""
|
||||
GlancesPlugin.__init__(self, args=args)
|
||||
|
||||
# We want to display the stat in the curse interface
|
||||
self.display_curse = True
|
||||
# Set the message position
|
||||
# It is NOT the curse position but the Glances column/line
|
||||
# Enter -1 to right align
|
||||
self.column_curse = 3
|
||||
# Enter -1 to diplay bottom
|
||||
self.line_curse = 1
|
||||
|
||||
# Init the stats
|
||||
self.reset()
|
||||
|
||||
def reset(self):
|
||||
"""Reset/init the stats."""
|
||||
self.stats = {}
|
||||
|
||||
def update(self):
|
||||
"""Update swap memory stats using the input method."""
|
||||
# Reset stats
|
||||
self.reset()
|
||||
|
||||
if self.get_input() == 'local':
|
||||
# Update stats using the standard system lib
|
||||
# Grab SWAP using the PSUtil swap_memory method
|
||||
sm_stats = psutil.swap_memory()
|
||||
|
||||
# Get all the swap stats (copy/paste of the PsUtil documentation)
|
||||
# total: total swap memory in bytes
|
||||
# used: used swap memory in bytes
|
||||
# free: free swap memory in bytes
|
||||
# percent: the percentage usage
|
||||
# sin: the number of bytes the system has swapped in from disk (cumulative)
|
||||
# sout: the number of bytes the system has swapped out from disk (cumulative)
|
||||
for swap in ['total', 'used', 'free', 'percent',
|
||||
'sin', 'sout']:
|
||||
if hasattr(sm_stats, swap):
|
||||
self.stats[swap] = getattr(sm_stats, swap)
|
||||
elif self.get_input() == 'snmp':
|
||||
# Update stats using SNMP
|
||||
self.stats = self.set_stats_snmp(snmp_oid=snmp_oid)
|
||||
|
||||
if self.stats['total'] == '':
|
||||
self.reset()
|
||||
return self.stats
|
||||
|
||||
for key in self.stats.iterkeys():
|
||||
if self.stats[key] != '':
|
||||
self.stats[key] = float(self.stats[key]) * 1024
|
||||
|
||||
# used=total-free
|
||||
self.stats['used'] = self.stats['total'] - self.stats['free']
|
||||
|
||||
# percent: the percentage usage calculated as (total - available) / total * 100.
|
||||
self.stats['percent'] = float((self.stats['total'] - self.stats['free']) / self.stats['total'] * 100)
|
||||
|
||||
return self.stats
|
||||
|
||||
def msg_curse(self, args=None):
|
||||
"""Return the dict to display in the curse interface."""
|
||||
# Init the return message
|
||||
ret = []
|
||||
|
||||
# Only process if stats exist...
|
||||
if self.stats == {}:
|
||||
return ret
|
||||
|
||||
# Build the string message
|
||||
# Header
|
||||
msg = '{0:7} '.format(_("SWAP"))
|
||||
ret.append(self.curse_add_line(msg, "TITLE"))
|
||||
# Percent memory usage
|
||||
msg = '{0:>6.1%}'.format(self.stats['percent'] / 100)
|
||||
ret.append(self.curse_add_line(msg))
|
||||
# New line
|
||||
ret.append(self.curse_new_line())
|
||||
# Total memory usage
|
||||
msg = '{0:8}'.format(_("total:"))
|
||||
ret.append(self.curse_add_line(msg))
|
||||
msg = '{0:>6}'.format(self.auto_unit(self.stats['total']))
|
||||
ret.append(self.curse_add_line(msg))
|
||||
# New line
|
||||
ret.append(self.curse_new_line())
|
||||
# Used memory usage
|
||||
msg = '{0:8}'.format(_("used:"))
|
||||
ret.append(self.curse_add_line(msg))
|
||||
msg = '{0:>6}'.format(self.auto_unit(self.stats['used']))
|
||||
ret.append(self.curse_add_line(
|
||||
msg, self.get_alert_log(self.stats['used'], max=self.stats['total'])))
|
||||
# New line
|
||||
ret.append(self.curse_new_line())
|
||||
# Free memory usage
|
||||
msg = '{0:8}'.format(_("free:"))
|
||||
ret.append(self.curse_add_line(msg))
|
||||
msg = '{0:>6}'.format(self.auto_unit(self.stats['free']))
|
||||
ret.append(self.curse_add_line(msg))
|
||||
|
||||
return ret
|
125
glances/plugins/glances_monitor.py
Normal file
@ -0,0 +1,125 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
#
|
||||
# This file is part of Glances.
|
||||
#
|
||||
# Copyright (C) 2014 Nicolargo <nicolas@nicolargo.com>
|
||||
#
|
||||
# Glances is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU Lesser General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# Glances is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU Lesser General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU Lesser General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
"""Monitor plugin."""
|
||||
|
||||
# Import Glances lib
|
||||
from glances.core.glances_monitor_list import MonitorList as glancesMonitorList
|
||||
from glances.plugins.glances_plugin import GlancesPlugin
|
||||
|
||||
|
||||
class Plugin(GlancesPlugin):
|
||||
|
||||
"""Glances' monitor plugin."""
|
||||
|
||||
def __init__(self, args=None):
|
||||
"""Init the plugin."""
|
||||
GlancesPlugin.__init__(self, args=args)
|
||||
|
||||
# We want to display the stat in the curse interface
|
||||
self.display_curse = True
|
||||
# Set the message position
|
||||
# It is NOT the curse position but the Glances column/line
|
||||
# Enter -1 to right align
|
||||
self.column_curse = 1
|
||||
# Enter -1 to diplay bottom
|
||||
self.line_curse = 3
|
||||
|
||||
# Init stats
|
||||
self.glances_monitors = None
|
||||
self.stats = []
|
||||
|
||||
def load_limits(self, config):
|
||||
"""Load the monitored list from the conf file."""
|
||||
# print "DEBUG: Monitor plugin load config file %s" % config
|
||||
self.glances_monitors = glancesMonitorList(config)
|
||||
|
||||
def update(self):
|
||||
"""Update the monitored list."""
|
||||
if self.get_input() == 'local':
|
||||
# Monitor list only available in a full Glances environment
|
||||
# Check if the glances_monitor instance is init
|
||||
if self.glances_monitors is None:
|
||||
return self.stats
|
||||
|
||||
# Update the monitored list (result of command)
|
||||
self.glances_monitors.update()
|
||||
|
||||
# Put it on the stats var
|
||||
self.stats = self.glances_monitors.get()
|
||||
else:
|
||||
pass
|
||||
|
||||
return self.stats
|
||||
|
||||
def get_alert(self, nbprocess=0, countmin=None, countmax=None, header="", log=False):
|
||||
"""Return the alert status relative to the process number."""
|
||||
if nbprocess is None:
|
||||
return 'OK'
|
||||
if countmin is None:
|
||||
countmin = nbprocess
|
||||
if countmax is None:
|
||||
countmax = nbprocess
|
||||
if nbprocess > 0:
|
||||
if int(countmin) <= int(nbprocess) <= int(countmax):
|
||||
return 'OK'
|
||||
else:
|
||||
return 'WARNING'
|
||||
else:
|
||||
if int(countmin) == 0:
|
||||
return 'OK'
|
||||
else:
|
||||
return 'CRITICAL'
|
||||
|
||||
def msg_curse(self, args=None):
|
||||
"""Return the dict to display in the curse interface."""
|
||||
# Init the return message
|
||||
ret = []
|
||||
|
||||
# Only process if stats exist and display plugin enable...
|
||||
if self.stats == [] or args.disable_process:
|
||||
return ret
|
||||
|
||||
# Build the string message
|
||||
for m in self.stats:
|
||||
msg = '{0:<16} '.format(m['description'])
|
||||
ret.append(self.curse_add_line(
|
||||
msg, self.get_alert(m['count'], m['countmin'], m['countmax'])))
|
||||
msg = '{0:<3} '.format(m['count'] if m['count'] > 1 else '')
|
||||
ret.append(self.curse_add_line(msg))
|
||||
msg = '{0:13} '.format(_("RUNNING") if m['count'] >= 1 else _("NOT RUNNING"))
|
||||
ret.append(self.curse_add_line(msg))
|
||||
# Decode to UTF8 (only for Python 3)
|
||||
try:
|
||||
msg = m['result'].decode('utf-8') if m['count'] >= 1 else ''
|
||||
except (UnicodeError, AttributeError):
|
||||
try:
|
||||
msg = m['result'] if m['count'] >= 1 else ''
|
||||
except UnicodeError:
|
||||
msg = m['result'].encode('utf-8') if m['count'] >= 1 else ''
|
||||
ret.append(self.curse_add_line(msg, optional=True, splittable=True))
|
||||
ret.append(self.curse_new_line())
|
||||
|
||||
# Delete the last empty line
|
||||
try:
|
||||
ret.pop()
|
||||
except IndexError:
|
||||
pass
|
||||
|
||||
return ret
|
251
glances/plugins/glances_network.py
Normal file
@ -0,0 +1,251 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
#
|
||||
# This file is part of Glances.
|
||||
#
|
||||
# Copyright (C) 2014 Nicolargo <nicolas@nicolargo.com>
|
||||
#
|
||||
# Glances is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU Lesser General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# Glances is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU Lesser General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU Lesser General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
"""Network plugin."""
|
||||
|
||||
from glances.core.glances_timer import getTimeSinceLastUpdate
|
||||
from glances.plugins.glances_plugin import GlancesPlugin
|
||||
|
||||
import psutil
|
||||
|
||||
# SNMP OID
|
||||
# http://www.net-snmp.org/docs/mibs/interfaces.html
|
||||
# Dict key = interface_name
|
||||
snmp_oid = {'interface_name': '1.3.6.1.2.1.2.2.1.2',
|
||||
'cumulative_rx': '1.3.6.1.2.1.2.2.1.10',
|
||||
'cumulative_tx': '1.3.6.1.2.1.2.2.1.16'}
|
||||
|
||||
|
||||
class Plugin(GlancesPlugin):
|
||||
|
||||
"""Glances' network Plugin.
|
||||
|
||||
stats is a list
|
||||
"""
|
||||
|
||||
def __init__(self, args=None):
|
||||
"""Init the plugin."""
|
||||
GlancesPlugin.__init__(self, args=args)
|
||||
|
||||
# We want to display the stat in the curse interface
|
||||
self.display_curse = True
|
||||
# Set the message position
|
||||
# It is NOT the curse position but the Glances column/line
|
||||
# Enter -1 to right align
|
||||
self.column_curse = 0
|
||||
# Enter -1 to diplay bottom
|
||||
self.line_curse = 2
|
||||
|
||||
# Init the stats
|
||||
self.reset()
|
||||
|
||||
def reset(self):
|
||||
"""Reset/init the stats."""
|
||||
self.stats = []
|
||||
|
||||
def update(self):
|
||||
"""Update network stats using the input method.
|
||||
|
||||
Stats is a list of dict (one dict per interface)
|
||||
"""
|
||||
# Reset stats
|
||||
self.reset()
|
||||
|
||||
if self.get_input() == 'local':
|
||||
# Update stats using the standard system lib
|
||||
|
||||
# Grab network interface stat using the PsUtil net_io_counter method
|
||||
try:
|
||||
netiocounters = psutil.net_io_counters(pernic=True)
|
||||
except UnicodeDecodeError:
|
||||
return self.stats
|
||||
|
||||
# Previous network interface stats are stored in the network_old variable
|
||||
if not hasattr(self, 'network_old'):
|
||||
# First call, we init the network_old var
|
||||
try:
|
||||
self.network_old = netiocounters
|
||||
except (IOError, UnboundLocalError):
|
||||
pass
|
||||
else:
|
||||
# By storing time data we enable Rx/s and Tx/s calculations in the
|
||||
# XML/RPC API, which would otherwise be overly difficult work
|
||||
# for users of the API
|
||||
time_since_update = getTimeSinceLastUpdate('net')
|
||||
|
||||
# Loop over interfaces
|
||||
network_new = netiocounters
|
||||
for net in network_new:
|
||||
try:
|
||||
# Try necessary to manage dynamic network interface
|
||||
netstat = {}
|
||||
netstat['interface_name'] = net
|
||||
netstat['time_since_update'] = time_since_update
|
||||
netstat['cumulative_rx'] = network_new[net].bytes_recv
|
||||
netstat['rx'] = (network_new[net].bytes_recv -
|
||||
self.network_old[net].bytes_recv)
|
||||
netstat['cumulative_tx'] = network_new[net].bytes_sent
|
||||
netstat['tx'] = (network_new[net].bytes_sent -
|
||||
self.network_old[net].bytes_sent)
|
||||
netstat['cumulative_cx'] = (netstat['cumulative_rx'] +
|
||||
netstat['cumulative_tx'])
|
||||
netstat['cx'] = netstat['rx'] + netstat['tx']
|
||||
except KeyError:
|
||||
continue
|
||||
else:
|
||||
self.stats.append(netstat)
|
||||
|
||||
# Save stats to compute next bitrate
|
||||
self.network_old = network_new
|
||||
|
||||
elif self.get_input() == 'snmp':
|
||||
# Update stats using SNMP
|
||||
|
||||
# SNMP bulk command to get all network interface in one shot
|
||||
netiocounters = self.set_stats_snmp(snmp_oid=snmp_oid, bulk=True)
|
||||
|
||||
# Previous network interface stats are stored in the network_old variable
|
||||
if not hasattr(self, 'network_old'):
|
||||
# First call, we init the network_old var
|
||||
try:
|
||||
self.network_old = netiocounters
|
||||
except (IOError, UnboundLocalError):
|
||||
pass
|
||||
else:
|
||||
# See description in the 'local' block
|
||||
time_since_update = getTimeSinceLastUpdate('net')
|
||||
|
||||
# Loop over interfaces
|
||||
network_new = netiocounters
|
||||
|
||||
for net in network_new:
|
||||
try:
|
||||
# Try necessary to manage dynamic network interface
|
||||
netstat = {}
|
||||
netstat['interface_name'] = net
|
||||
netstat['time_since_update'] = time_since_update
|
||||
netstat['cumulative_rx'] = float(network_new[net]['cumulative_rx'])
|
||||
netstat['rx'] = (float(network_new[net]['cumulative_rx']) -
|
||||
float(self.network_old[net]['cumulative_rx']))
|
||||
netstat['cumulative_tx'] = float(network_new[net]['cumulative_tx'])
|
||||
netstat['tx'] = (float(network_new[net]['cumulative_tx']) -
|
||||
float(self.network_old[net]['cumulative_tx']))
|
||||
netstat['cumulative_cx'] = (netstat['cumulative_rx'] +
|
||||
netstat['cumulative_tx'])
|
||||
netstat['cx'] = netstat['rx'] + netstat['tx']
|
||||
except KeyError:
|
||||
continue
|
||||
else:
|
||||
self.stats.append(netstat)
|
||||
|
||||
# Save stats to compute next bitrate
|
||||
self.network_old = network_new
|
||||
|
||||
return self.stats
|
||||
|
||||
def msg_curse(self, args=None):
|
||||
"""Return the dict to display in the curse interface."""
|
||||
# !!! TODO: Add alert on network interface bitrate
|
||||
|
||||
# Init the return message
|
||||
ret = []
|
||||
|
||||
# Only process if stats exist and display plugin enable...
|
||||
if self.stats == [] or args.disable_network:
|
||||
return ret
|
||||
|
||||
# Build the string message
|
||||
# Header
|
||||
msg = '{0:9}'.format(_("NETWORK"))
|
||||
ret.append(self.curse_add_line(msg, "TITLE"))
|
||||
if args.network_cumul:
|
||||
# Cumulative stats
|
||||
if args.network_sum:
|
||||
# Sum stats
|
||||
msg = '{0:>14}'.format(_("Rx+Tx"))
|
||||
ret.append(self.curse_add_line(msg))
|
||||
else:
|
||||
# Rx/Tx stats
|
||||
msg = '{0:>7}'.format(_("Rx"))
|
||||
ret.append(self.curse_add_line(msg))
|
||||
msg = '{0:>7}'.format(_("Tx"))
|
||||
ret.append(self.curse_add_line(msg))
|
||||
else:
|
||||
# Bitrate stats
|
||||
if args.network_sum:
|
||||
# Sum stats
|
||||
msg = '{0:>14}'.format(_("Rx+Tx/s"))
|
||||
ret.append(self.curse_add_line(msg))
|
||||
else:
|
||||
msg = '{0:>7}'.format(_("Rx/s"))
|
||||
ret.append(self.curse_add_line(msg))
|
||||
msg = '{0:>7}'.format(_("Tx/s"))
|
||||
ret.append(self.curse_add_line(msg))
|
||||
# Interface list (sorted by name)
|
||||
for i in sorted(self.stats, key=lambda network: network['interface_name']):
|
||||
# Do not display hidden interfaces
|
||||
if self.is_hide(i['interface_name']):
|
||||
continue
|
||||
# Format stats
|
||||
ifname = i['interface_name'].split(':')[0]
|
||||
if len(ifname) > 9:
|
||||
# Cut interface name if it is too long
|
||||
ifname = '_' + ifname[-8:]
|
||||
if args.byte:
|
||||
# Bytes per second (for dummy)
|
||||
if args.network_cumul:
|
||||
rx = self.auto_unit(int(i['cumulative_rx']))
|
||||
tx = self.auto_unit(int(i['cumulative_tx']))
|
||||
sx = self.auto_unit(int(i['cumulative_tx'])
|
||||
+ int(i['cumulative_tx']))
|
||||
else:
|
||||
rx = self.auto_unit(int(i['rx'] // i['time_since_update']))
|
||||
tx = self.auto_unit(int(i['tx'] // i['time_since_update']))
|
||||
sx = self.auto_unit(int(i['rx'] // i['time_since_update'])
|
||||
+ int(i['tx'] // i['time_since_update']))
|
||||
else:
|
||||
# Bits per second (for real network administrator | Default)
|
||||
if args.network_cumul:
|
||||
rx = self.auto_unit(int(i['cumulative_rx'] * 8)) + "b"
|
||||
tx = self.auto_unit(int(i['cumulative_tx'] * 8)) + "b"
|
||||
sx = self.auto_unit(int(i['cumulative_rx'] * 8)
|
||||
+ int(i['cumulative_tx'] * 8)) + "b"
|
||||
else:
|
||||
rx = self.auto_unit(int(i['rx'] // i['time_since_update'] * 8)) + "b"
|
||||
tx = self.auto_unit(int(i['tx'] // i['time_since_update'] * 8)) + "b"
|
||||
sx = self.auto_unit(int(i['rx'] // i['time_since_update'] * 8) +
|
||||
int(i['tx'] // i['time_since_update'] * 8)) + "b"
|
||||
# New line
|
||||
ret.append(self.curse_new_line())
|
||||
msg = '{0:9}'.format(ifname)
|
||||
ret.append(self.curse_add_line(msg))
|
||||
if args.network_sum:
|
||||
msg = '{0:>14}'.format(sx)
|
||||
ret.append(self.curse_add_line(msg))
|
||||
else:
|
||||
msg = '{0:>7}'.format(rx)
|
||||
ret.append(self.curse_add_line(
|
||||
msg, self.get_alert(int(i['rx'] // i['time_since_update'] * 8),
|
||||
header=ifname + '_rx')))
|
||||
msg = '{0:>7}'.format(tx)
|
||||
ret.append(self.curse_add_line(
|
||||
msg, self.get_alert(int(i['tx'] // i['time_since_update'] * 8),
|
||||
header=ifname + '_tx')))
|
||||
|
||||
return ret
|
64
glances/plugins/glances_now.py
Normal file
@ -0,0 +1,64 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
#
|
||||
# This file is part of Glances.
|
||||
#
|
||||
# Copyright (C) 2014 Nicolargo <nicolas@nicolargo.com>
|
||||
#
|
||||
# Glances is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU Lesser General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# Glances is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU Lesser General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU Lesser General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
# Import system libs
|
||||
from datetime import datetime
|
||||
|
||||
# Import Glances libs
|
||||
from glances.plugins.glances_plugin import GlancesPlugin
|
||||
|
||||
|
||||
class Plugin(GlancesPlugin):
|
||||
|
||||
"""Plugin to get the current date/time.
|
||||
|
||||
stats is (string)
|
||||
"""
|
||||
|
||||
def __init__(self, args=None):
|
||||
"""Init the plugin."""
|
||||
GlancesPlugin.__init__(self, args=args)
|
||||
|
||||
# We want to display the stat in the curse interface
|
||||
self.display_curse = True
|
||||
# Set the message position
|
||||
# It is NOT the curse position but the Glances column/line
|
||||
# Enter -1 to right align
|
||||
self.column_curse = 0
|
||||
# Enter -1 to diplay bottom
|
||||
self.line_curse = -1
|
||||
|
||||
def update(self):
|
||||
"""Update current date/time."""
|
||||
# Had to convert it to string because datetime is not JSON serializable
|
||||
self.stats = datetime.now().strftime(_("%Y-%m-%d %H:%M:%S"))
|
||||
|
||||
return self.stats
|
||||
|
||||
def msg_curse(self, args=None):
|
||||
"""Return the string to display in the curse interface."""
|
||||
# Init the return message
|
||||
ret = []
|
||||
|
||||
# Build the string message
|
||||
# 23 is the padding for the process list
|
||||
msg = '{0:23}'.format(self.stats)
|
||||
ret.append(self.curse_add_line(msg))
|
||||
|
||||
return ret
|
187
glances/plugins/glances_percpu.py
Normal file
@ -0,0 +1,187 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
#
|
||||
# This file is part of Glances.
|
||||
#
|
||||
# Copyright (C) 2014 Nicolargo <nicolas@nicolargo.com>
|
||||
#
|
||||
# Glances is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU Lesser General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# Glances is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU Lesser General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU Lesser General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
"""Per-CPU plugin."""
|
||||
|
||||
# Import Glances libs
|
||||
from glances.plugins.glances_plugin import GlancesPlugin
|
||||
|
||||
# Check for psutil already done in the glances_core script
|
||||
import psutil
|
||||
|
||||
|
||||
class Plugin(GlancesPlugin):
|
||||
|
||||
"""Glances' per-CPU plugin.
|
||||
|
||||
stats is a list
|
||||
"""
|
||||
|
||||
def __init__(self, args=None):
|
||||
"""Init the plugin."""
|
||||
GlancesPlugin.__init__(self, args=args)
|
||||
|
||||
# We want to display the stat in the curse interface
|
||||
self.display_curse = True
|
||||
# Set the message position
|
||||
# It is NOT the curse position but the Glances column/line
|
||||
# Enter -1 to right align
|
||||
self.column_curse = 0
|
||||
# Enter -1 to diplay bottom
|
||||
self.line_curse = 1
|
||||
|
||||
# Init stats
|
||||
self.reset()
|
||||
self.percputime_total_new = []
|
||||
self.percputime_new = []
|
||||
|
||||
def reset(self):
|
||||
"""Reset/init the stats."""
|
||||
self.stats = []
|
||||
|
||||
def update(self):
|
||||
"""Update per-CPU stats using the input method."""
|
||||
# Reset stats
|
||||
self.reset()
|
||||
|
||||
if self.get_input() == 'local':
|
||||
# Update stats using the standard system lib
|
||||
|
||||
# Grab CPU using the PSUtil cpu_times method
|
||||
# Per-CPU
|
||||
percputime = psutil.cpu_times(percpu=True)
|
||||
percputime_total = []
|
||||
for i in range(len(percputime)):
|
||||
percputime_total.append(percputime[i].user +
|
||||
percputime[i].system +
|
||||
percputime[i].idle)
|
||||
|
||||
# Only available on some OS
|
||||
for i in range(len(percputime)):
|
||||
if hasattr(percputime[i], 'nice'):
|
||||
percputime_total[i] += percputime[i].nice
|
||||
for i in range(len(percputime)):
|
||||
if hasattr(percputime[i], 'iowait'):
|
||||
percputime_total[i] += percputime[i].iowait
|
||||
for i in range(len(percputime)):
|
||||
if hasattr(percputime[i], 'irq'):
|
||||
percputime_total[i] += percputime[i].irq
|
||||
for i in range(len(percputime)):
|
||||
if hasattr(percputime[i], 'softirq'):
|
||||
percputime_total[i] += percputime[i].softirq
|
||||
for i in range(len(percputime)):
|
||||
if hasattr(percputime[i], 'steal'):
|
||||
percputime_total[i] += percputime[i].steal
|
||||
if not hasattr(self, 'percputime_old'):
|
||||
self.percputime_old = percputime
|
||||
self.percputime_total_old = percputime_total
|
||||
else:
|
||||
self.percputime_new = percputime
|
||||
self.percputime_total_new = percputime_total
|
||||
perpercent = []
|
||||
try:
|
||||
for i in range(len(self.percputime_new)):
|
||||
perpercent.append(100 / (self.percputime_total_new[i] -
|
||||
self.percputime_total_old[i]))
|
||||
cpu = {'user': (self.percputime_new[i].user -
|
||||
self.percputime_old[i].user) * perpercent[i],
|
||||
'system': (self.percputime_new[i].system -
|
||||
self.percputime_old[i].system) * perpercent[i],
|
||||
'idle': (self.percputime_new[i].idle -
|
||||
self.percputime_old[i].idle) * perpercent[i]}
|
||||
if hasattr(self.percputime_new[i], 'nice'):
|
||||
cpu['nice'] = (self.percputime_new[i].nice -
|
||||
self.percputime_old[i].nice) * perpercent[i]
|
||||
if hasattr(self.percputime_new[i], 'iowait'):
|
||||
cpu['iowait'] = (self.percputime_new[i].iowait -
|
||||
self.percputime_old[i].iowait) * perpercent[i]
|
||||
if hasattr(self.percputime_new[i], 'irq'):
|
||||
cpu['irq'] = (self.percputime_new[i].irq -
|
||||
self.percputime_old[i].irq) * perpercent[i]
|
||||
if hasattr(self.percputime_new[i], 'softirq'):
|
||||
cpu['softirq'] = (self.percputime_new[i].softirq -
|
||||
self.percputime_old[i].softirq) * perpercent[i]
|
||||
if hasattr(self.percputime_new[i], 'steal'):
|
||||
cpu['steal'] = (self.percputime_new[i].steal -
|
||||
self.percputime_old[i].steal) * perpercent[i]
|
||||
self.stats.append(cpu)
|
||||
self.percputime_old = self.percputime_new
|
||||
self.percputime_total_old = self.percputime_total_new
|
||||
except Exception:
|
||||
self.reset()
|
||||
|
||||
else:
|
||||
# Update stats using SNMP
|
||||
pass
|
||||
|
||||
return self.stats
|
||||
|
||||
def msg_curse(self, args=None):
|
||||
"""Return the dict to display in the curse interface."""
|
||||
# Init the return message
|
||||
ret = []
|
||||
|
||||
# No per CPU stat ? Exit...
|
||||
if self.stats == []:
|
||||
msg = _("PER CPU not available")
|
||||
ret.append(self.curse_add_line(msg, "TITLE"))
|
||||
return ret
|
||||
|
||||
# Build the string message
|
||||
# Header
|
||||
msg = '{0:8}'.format(_("PER CPU"))
|
||||
ret.append(self.curse_add_line(msg, "TITLE"))
|
||||
|
||||
# Total CPU usage
|
||||
for cpu in self.stats:
|
||||
msg = ' {0:>6.1%}'.format((100 - cpu['idle']) / 100)
|
||||
ret.append(self.curse_add_line(msg))
|
||||
|
||||
# User CPU
|
||||
if 'user' in self.stats[0]:
|
||||
# New line
|
||||
ret.append(self.curse_new_line())
|
||||
msg = '{0:8}'.format(_("user:"))
|
||||
ret.append(self.curse_add_line(msg))
|
||||
for cpu in self.stats:
|
||||
msg = ' {0:>6.1%}'.format(cpu['user'] / 100)
|
||||
ret.append(self.curse_add_line(msg, self.get_alert(cpu['user'], header="user")))
|
||||
|
||||
# System CPU
|
||||
if 'user' in self.stats[0]:
|
||||
# New line
|
||||
ret.append(self.curse_new_line())
|
||||
msg = '{0:8}'.format(_("system:"))
|
||||
ret.append(self.curse_add_line(msg))
|
||||
for cpu in self.stats:
|
||||
msg = ' {0:>6.1%}'.format(cpu['system'] / 100)
|
||||
ret.append(self.curse_add_line(msg, self.get_alert(cpu['system'], header="system")))
|
||||
|
||||
# Idle CPU
|
||||
if 'user' in self.stats[0]:
|
||||
# New line
|
||||
ret.append(self.curse_new_line())
|
||||
msg = '{0:8}'.format(_("idle:"))
|
||||
ret.append(self.curse_add_line(msg))
|
||||
for cpu in self.stats:
|
||||
msg = ' {0:>6.1%}'.format(cpu['idle'] / 100)
|
||||
ret.append(self.curse_add_line(msg))
|
||||
|
||||
# Return the message with decoration
|
||||
return ret
|
355
glances/plugins/glances_plugin.py
Normal file
@ -0,0 +1,355 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
#
|
||||
# This file is part of Glances.
|
||||
#
|
||||
# Copyright (C) 2014 Nicolargo <nicolas@nicolargo.com>
|
||||
#
|
||||
# Glances is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU Lesser General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# Glances is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU Lesser General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU Lesser General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
"""
|
||||
I am your father...
|
||||
|
||||
...for all Glances plugins.
|
||||
"""
|
||||
|
||||
# Import system libs
|
||||
import json
|
||||
|
||||
# Import Glances lib
|
||||
from glances.core.glances_globals import glances_logs
|
||||
|
||||
|
||||
class GlancesPlugin(object):
|
||||
|
||||
"""Main class for Glances' plugin."""
|
||||
|
||||
def __init__(self, args=None):
|
||||
"""Init the plugin of plugins class."""
|
||||
# Plugin name (= module name without glances_)
|
||||
self.plugin_name = self.__class__.__module__[len('glances_'):]
|
||||
|
||||
# Init the args
|
||||
self.args = args
|
||||
|
||||
# Init the input method
|
||||
self.input_method = 'local'
|
||||
|
||||
# Init the stats list
|
||||
self.stats = None
|
||||
|
||||
# Init the limits dictionnary
|
||||
self.limits = dict()
|
||||
|
||||
def __repr__(self):
|
||||
"""Return the raw stats."""
|
||||
return self.stats
|
||||
|
||||
def __str__(self):
|
||||
"""Return the human-readable stats."""
|
||||
return str(self.stats)
|
||||
|
||||
def set_input(self, input_method):
|
||||
"""Set the input method.
|
||||
|
||||
* local: system local grab (psutil or direct access)
|
||||
* snmp: Client server mode via SNMP
|
||||
* glances: Client server mode via Glances API
|
||||
"""
|
||||
self.input_method = input_method
|
||||
return self.input_method
|
||||
|
||||
def get_input(self):
|
||||
"""Get the input method."""
|
||||
return self.input_method
|
||||
|
||||
def set_stats(self, input_stats):
|
||||
"""Set the stats to input_stats."""
|
||||
self.stats = input_stats
|
||||
return self.stats
|
||||
|
||||
def set_stats_snmp(self, bulk=False, snmp_oid={}):
|
||||
"""Update stats using SNMP.
|
||||
|
||||
If bulk=True, use a bulk request instead of a get request.
|
||||
"""
|
||||
from glances.core.glances_snmp import GlancesSNMPClient
|
||||
|
||||
# Init the SNMP request
|
||||
clientsnmp = GlancesSNMPClient(host=self.args.client,
|
||||
port=self.args.snmp_port,
|
||||
version=self.args.snmp_version,
|
||||
community=self.args.snmp_community)
|
||||
|
||||
# Process the SNMP request
|
||||
ret = {}
|
||||
if bulk:
|
||||
# Bulk request
|
||||
snmpresult = clientsnmp.getbulk_by_oid(0, 10, *snmp_oid.values())
|
||||
|
||||
# Build the internal dict with the SNMP result
|
||||
# key is the first item in the snmp_oid
|
||||
index = 1
|
||||
for item in snmpresult:
|
||||
item_stats = {}
|
||||
item_key = None
|
||||
for key in snmp_oid.iterkeys():
|
||||
oid = snmp_oid[key] + '.' + str(index)
|
||||
if oid in item:
|
||||
if item_key is None:
|
||||
item_key = item[oid]
|
||||
else:
|
||||
item_stats[key] = item[oid]
|
||||
if item_stats != {}:
|
||||
ret[item_key] = item_stats
|
||||
index += 1
|
||||
else:
|
||||
# Simple get request
|
||||
snmpresult = clientsnmp.get_by_oid(*snmp_oid.values())
|
||||
|
||||
# Build the internal dict with the SNMP result
|
||||
for key in snmp_oid.iterkeys():
|
||||
ret[key] = snmpresult[snmp_oid[key]]
|
||||
|
||||
return ret
|
||||
|
||||
def get_raw(self):
|
||||
"""Return the stats object."""
|
||||
return self.stats
|
||||
|
||||
def get_stats(self):
|
||||
"""Return the stats object in JSON format for the XML-RPC API."""
|
||||
return json.dumps(self.stats)
|
||||
|
||||
def load_limits(self, config):
|
||||
"""Load the limits from the configuration file."""
|
||||
if (hasattr(config, 'has_section') and
|
||||
config.has_section(self.plugin_name)):
|
||||
# print "Load limits for %s" % self.plugin_name
|
||||
for s, v in config.items(self.plugin_name):
|
||||
# Read limits
|
||||
# print "\t%s = %s" % (self.plugin_name + '_' + s, v)
|
||||
try:
|
||||
self.limits[self.plugin_name + '_' + s] = config.get_option(self.plugin_name, s)
|
||||
except ValueError:
|
||||
self.limits[self.plugin_name + '_' + s] = config.get_raw_option(self.plugin_name, s).split(",")
|
||||
|
||||
def set_limits(self, input_limits):
|
||||
"""Set the limits to input_limits."""
|
||||
self.limits = input_limits
|
||||
return self.limits
|
||||
|
||||
def get_limits(self):
|
||||
"""Return the limits object."""
|
||||
return self.limits
|
||||
|
||||
def get_alert(self, current=0, min=0, max=100, header="", log=False):
|
||||
"""Return the alert status relative to a current value.
|
||||
|
||||
Use this function for minor stats.
|
||||
|
||||
If current < CAREFUL of max then alert = OK
|
||||
If current > CAREFUL of max then alert = CAREFUL
|
||||
If current > WARNING of max then alert = WARNING
|
||||
If current > CRITICAL of max then alert = CRITICAL
|
||||
|
||||
If defined 'header' is added between the plugin name and the status.
|
||||
Only useful for stats with several alert status.
|
||||
|
||||
If log=True than return the logged status.
|
||||
"""
|
||||
# Compute the %
|
||||
try:
|
||||
value = (current * 100) / max
|
||||
except ZeroDivisionError:
|
||||
return 'DEFAULT'
|
||||
except TypeError:
|
||||
return 'DEFAULT'
|
||||
|
||||
# Manage limits
|
||||
ret = 'OK'
|
||||
try:
|
||||
if value > self.__get_limit_critical(header=header):
|
||||
ret = 'CRITICAL'
|
||||
elif value > self.__get_limit_warning(header=header):
|
||||
ret = 'WARNING'
|
||||
elif value > self.__get_limit_careful(header=header):
|
||||
ret = 'CAREFUL'
|
||||
elif current < min:
|
||||
ret = 'CAREFUL'
|
||||
except KeyError:
|
||||
return 'DEFAULT'
|
||||
|
||||
# Manage log (if needed)
|
||||
log_str = ""
|
||||
if log:
|
||||
# Add _LOG to the return string
|
||||
# So stats will be highlited with a specific color
|
||||
log_str = "_LOG"
|
||||
# Get the stat_name = plugin_name (+ header)
|
||||
if header == "":
|
||||
stat_name = self.plugin_name
|
||||
else:
|
||||
stat_name = self.plugin_name + '_' + header
|
||||
# Add the log to the list
|
||||
glances_logs.add(ret, stat_name.upper(), value, [])
|
||||
|
||||
# Default is ok
|
||||
return ret + log_str
|
||||
|
||||
def get_alert_log(self, current=0, min=0, max=100, header=""):
|
||||
"""Get the alert log."""
|
||||
return self.get_alert(current, min, max, header, log=True)
|
||||
|
||||
def __get_limit_critical(self, header=""):
|
||||
if header == "":
|
||||
return self.limits[self.plugin_name + '_' + 'critical']
|
||||
else:
|
||||
return self.limits[self.plugin_name + '_' + header + '_' + 'critical']
|
||||
|
||||
def __get_limit_warning(self, header=""):
|
||||
if header == "":
|
||||
return self.limits[self.plugin_name + '_' + 'warning']
|
||||
else:
|
||||
return self.limits[self.plugin_name + '_' + header + '_' + 'warning']
|
||||
|
||||
def __get_limit_careful(self, header=""):
|
||||
if header == "":
|
||||
return self.limits[self.plugin_name + '_' + 'careful']
|
||||
else:
|
||||
return self.limits[self.plugin_name + '_' + header + '_' + 'careful']
|
||||
|
||||
def get_hide(self, header=""):
|
||||
"""Return the hide configuration list key for the current plugin."""
|
||||
if header == "":
|
||||
try:
|
||||
return self.limits[self.plugin_name + '_' + 'hide']
|
||||
except KeyError:
|
||||
return []
|
||||
else:
|
||||
try:
|
||||
return self.limits[self.plugin_name + '_' + header + '_' + 'hide']
|
||||
except KeyError:
|
||||
return []
|
||||
|
||||
def is_hide(self, value, header=""):
|
||||
"""Return True if the value is in the hide configuration list."""
|
||||
return value in self.get_hide(header=header)
|
||||
|
||||
def msg_curse(self, args):
|
||||
"""Return default string to display in the curse interface."""
|
||||
return [self.curse_add_line(str(self.stats))]
|
||||
|
||||
def get_stats_display(self, args=None):
|
||||
"""Return a dict with all the information needed to display the stat.
|
||||
|
||||
key | description
|
||||
----------------------------
|
||||
display | Display the stat (True or False)
|
||||
msgdict | Message to display (list of dict [{ 'msg': msg, 'decoration': decoration } ... ])
|
||||
column | column number
|
||||
line | Line number
|
||||
"""
|
||||
display_curse = False
|
||||
column_curse = -1
|
||||
line_curse = -1
|
||||
|
||||
if hasattr(self, 'display_curse'):
|
||||
display_curse = self.display_curse
|
||||
if hasattr(self, 'column_curse'):
|
||||
column_curse = self.column_curse
|
||||
if hasattr(self, 'line_curse'):
|
||||
line_curse = self.line_curse
|
||||
|
||||
return {'display': display_curse,
|
||||
'msgdict': self.msg_curse(args),
|
||||
'column': column_curse,
|
||||
'line': line_curse}
|
||||
|
||||
def curse_add_line(self, msg, decoration="DEFAULT", optional=False, splittable=False):
|
||||
"""Return a dict with: { 'msg': msg, 'decoration': decoration, 'optional': False }.
|
||||
|
||||
Where:
|
||||
msg: string
|
||||
decoration:
|
||||
DEFAULT: no decoration
|
||||
UNDERLINE: underline
|
||||
BOLD: bold
|
||||
TITLE: for stat title
|
||||
PROCESS: for process name
|
||||
STATUS: for process status
|
||||
NICE: for process niceness
|
||||
OK: Value is OK and non logged
|
||||
OK_LOG: Value is OK and logged
|
||||
CAREFUL: Value is CAREFUL and non logged
|
||||
CAREFUL_LOG: Value is CAREFUL and logged
|
||||
WARNING: Value is WARINING and non logged
|
||||
WARNING_LOG: Value is WARINING and logged
|
||||
CRITICAL: Value is CRITICAL and non logged
|
||||
CRITICAL_LOG: Value is CRITICAL and logged
|
||||
optional: True if the stat is optional (display only if space is available)
|
||||
spittable: Line can be splitted to fit on the screen (default is not)
|
||||
"""
|
||||
return {'msg': msg, 'decoration': decoration, 'optional': optional, 'splittable': splittable}
|
||||
|
||||
def curse_new_line(self):
|
||||
"""Go to a new line."""
|
||||
return self.curse_add_line('\n')
|
||||
|
||||
def auto_unit(self, number, low_precision=False):
|
||||
"""Make a nice human-readable string out of number.
|
||||
|
||||
Number of decimal places increases as quantity approaches 1.
|
||||
|
||||
examples:
|
||||
CASE: 613421788 RESULT: 585M low_precision: 585M
|
||||
CASE: 5307033647 RESULT: 4.94G low_precision: 4.9G
|
||||
CASE: 44968414685 RESULT: 41.9G low_precision: 41.9G
|
||||
CASE: 838471403472 RESULT: 781G low_precision: 781G
|
||||
CASE: 9683209690677 RESULT: 8.81T low_precision: 8.8T
|
||||
CASE: 1073741824 RESULT: 1024M low_precision: 1024M
|
||||
CASE: 1181116006 RESULT: 1.10G low_precision: 1.1G
|
||||
|
||||
'low_precision=True' returns less decimal places potentially
|
||||
sacrificing precision for more readability.
|
||||
"""
|
||||
symbols = ('K', 'M', 'G', 'T', 'P', 'E', 'Z', 'Y')
|
||||
prefix = {
|
||||
'Y': 1208925819614629174706176,
|
||||
'Z': 1180591620717411303424,
|
||||
'E': 1152921504606846976,
|
||||
'P': 1125899906842624,
|
||||
'T': 1099511627776,
|
||||
'G': 1073741824,
|
||||
'M': 1048576,
|
||||
'K': 1024
|
||||
}
|
||||
|
||||
for symbol in reversed(symbols):
|
||||
value = float(number) / prefix[symbol]
|
||||
if value > 1:
|
||||
decimal_precision = 0
|
||||
if value < 10:
|
||||
decimal_precision = 2
|
||||
elif value < 100:
|
||||
decimal_precision = 1
|
||||
if low_precision:
|
||||
if symbol in 'MK':
|
||||
decimal_precision = 0
|
||||
else:
|
||||
decimal_precision = min(1, decimal_precision)
|
||||
elif symbol in 'K':
|
||||
decimal_precision = 0
|
||||
return '{0:.{decimal}f}{symbol}'.format(
|
||||
value, decimal=decimal_precision, symbol=symbol)
|
||||
return '{0!s}'.format(number)
|
130
glances/plugins/glances_processcount.py
Normal file
@ -0,0 +1,130 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
#
|
||||
# This file is part of Glances.
|
||||
#
|
||||
# Copyright (C) 2014 Nicolargo <nicolas@nicolargo.com>
|
||||
#
|
||||
# Glances is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU Lesser General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# Glances is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU Lesser General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU Lesser General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
"""Process count plugin."""
|
||||
|
||||
# Import Glances libs
|
||||
from glances.core.glances_globals import glances_processes
|
||||
from glances.plugins.glances_plugin import GlancesPlugin
|
||||
|
||||
|
||||
class Plugin(GlancesPlugin):
|
||||
|
||||
"""Glances' processes plugin.
|
||||
|
||||
stats is a list
|
||||
"""
|
||||
|
||||
def __init__(self, args=None):
|
||||
"""Init the plugin."""
|
||||
GlancesPlugin.__init__(self, args=args)
|
||||
|
||||
# We want to display the stat in the curse interface
|
||||
self.display_curse = True
|
||||
# Set the message position
|
||||
# It is NOT the curse position but the Glances column/line
|
||||
# Enter -1 to right align
|
||||
self.column_curse = 1
|
||||
# Enter -1 to diplay bottom
|
||||
self.line_curse = 2
|
||||
|
||||
# Note: 'glances_processes' is already init in the glances_processes.py script
|
||||
|
||||
def reset(self):
|
||||
"""Reset/init the stats."""
|
||||
self.stats = {}
|
||||
|
||||
def update(self):
|
||||
"""Update processes stats using the input method."""
|
||||
# Reset stats
|
||||
self.reset()
|
||||
|
||||
if self.get_input() == 'local':
|
||||
# Update stats using the standard system lib
|
||||
# Here, update is call for processcount AND processlist
|
||||
glances_processes.update()
|
||||
|
||||
# Return the processes count
|
||||
self.stats = glances_processes.getcount()
|
||||
elif self.get_input() == 'snmp':
|
||||
# Update stats using SNMP
|
||||
# !!! TODO
|
||||
pass
|
||||
|
||||
return self.stats
|
||||
|
||||
def msg_curse(self, args=None):
|
||||
"""Return the dict to display in the curse interface."""
|
||||
# Init the return message
|
||||
ret = []
|
||||
|
||||
# Only process if stats exist and display plugin enable...
|
||||
# if self.stats == {} or args.disable_process:
|
||||
# return ret
|
||||
|
||||
if args.disable_process:
|
||||
msg = _("PROCESSES DISABLED (press 'z' to display)")
|
||||
ret.append(self.curse_add_line(msg))
|
||||
return ret
|
||||
|
||||
if self.stats == {}:
|
||||
return ret
|
||||
|
||||
# Build the string message
|
||||
# Header
|
||||
msg = _("TASKS ")
|
||||
ret.append(self.curse_add_line(msg, "TITLE"))
|
||||
# Compute processes
|
||||
other = self.stats['total']
|
||||
msg = str(self.stats['total'])
|
||||
ret.append(self.curse_add_line(msg))
|
||||
|
||||
if 'thread' in self.stats:
|
||||
msg = _(" ({0} thr),").format(self.stats['thread'])
|
||||
ret.append(self.curse_add_line(msg))
|
||||
|
||||
if 'running' in self.stats:
|
||||
other -= self.stats['running']
|
||||
msg = _(" {0} run,").format(self.stats['running'])
|
||||
ret.append(self.curse_add_line(msg))
|
||||
|
||||
if 'sleeping' in self.stats:
|
||||
other -= self.stats['sleeping']
|
||||
msg = _(" {0} slp,").format(self.stats['sleeping'])
|
||||
ret.append(self.curse_add_line(msg))
|
||||
|
||||
msg = _(" {0} oth ").format(other)
|
||||
ret.append(self.curse_add_line(msg))
|
||||
|
||||
# Display sort information
|
||||
try:
|
||||
args.process_sorted_by
|
||||
except AttributeError:
|
||||
args.process_sorted_by = glances_processes.getsortkey()
|
||||
if args.process_sorted_by == 'auto':
|
||||
msg = _("sorted automatically")
|
||||
ret.append(self.curse_add_line(msg))
|
||||
msg = _(" by {0}").format(glances_processes.getsortkey())
|
||||
ret.append(self.curse_add_line(msg))
|
||||
else:
|
||||
msg = _("sorted by {0}").format(args.process_sorted_by)
|
||||
ret.append(self.curse_add_line(msg))
|
||||
|
||||
# Return the message with decoration
|
||||
return ret
|
255
glances/plugins/glances_processlist.py
Normal file
@ -0,0 +1,255 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
#
|
||||
# This file is part of Glances.
|
||||
#
|
||||
# Copyright (C) 2014 Nicolargo <nicolas@nicolargo.com>
|
||||
#
|
||||
# Glances is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU Lesser General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# Glances is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU Lesser General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU Lesser General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
"""Process list plugin."""
|
||||
|
||||
# Import sys libs
|
||||
import os
|
||||
from datetime import timedelta
|
||||
|
||||
# Import Glances libs
|
||||
from glances.core.glances_globals import glances_processes
|
||||
from glances.plugins.glances_plugin import GlancesPlugin
|
||||
|
||||
|
||||
class Plugin(GlancesPlugin):
|
||||
|
||||
"""Glances' processes plugin.
|
||||
|
||||
stats is a list
|
||||
"""
|
||||
|
||||
def __init__(self, args=None):
|
||||
"""Init the plugin."""
|
||||
GlancesPlugin.__init__(self, args=args)
|
||||
|
||||
# We want to display the stat in the curse interface
|
||||
self.display_curse = True
|
||||
# Set the message position
|
||||
# It is NOT the curse position but the Glances column/line
|
||||
# Enter -1 to right align
|
||||
self.column_curse = 1
|
||||
# Enter -1 to diplay bottom
|
||||
self.line_curse = 4
|
||||
|
||||
# Note: 'glances_processes' is already init in the glances_processes.py script
|
||||
|
||||
def reset(self):
|
||||
"""Reset/init the stats."""
|
||||
self.stats = []
|
||||
|
||||
def update(self):
|
||||
"""Update processes stats using the input method."""
|
||||
# Reset stats
|
||||
self.reset()
|
||||
|
||||
if self.get_input() == 'local':
|
||||
# Update stats using the standard system lib
|
||||
# Note: Update is done in the processcount plugin
|
||||
# Just return the processes list
|
||||
self.stats = glances_processes.getlist()
|
||||
elif self.get_input() == 'snmp':
|
||||
# Update stats using SNMP
|
||||
# !!! TODO
|
||||
pass
|
||||
|
||||
return self.stats
|
||||
|
||||
def msg_curse(self, args=None):
|
||||
"""Return the dict to display in the curse interface."""
|
||||
# Init the return message
|
||||
ret = []
|
||||
|
||||
# Only process if stats exist and display plugin enable...
|
||||
if self.stats == [] or args.disable_process:
|
||||
return ret
|
||||
|
||||
# Compute the sort key
|
||||
try:
|
||||
args.process_sorted_by
|
||||
except AttributeError:
|
||||
args.process_sorted_by = glances_processes.getsortkey()
|
||||
if args.process_sorted_by == 'auto':
|
||||
process_sort_key = glances_processes.getsortkey()
|
||||
else:
|
||||
process_sort_key = args.process_sorted_by
|
||||
sort_style = 'SORT'
|
||||
|
||||
# Header
|
||||
msg = '{0:>6}'.format(_("CPU%"))
|
||||
ret.append(self.curse_add_line(msg, sort_style if process_sort_key == 'cpu_percent' else 'DEFAULT'))
|
||||
msg = '{0:>6}'.format(_("MEM%"))
|
||||
ret.append(self.curse_add_line(msg, sort_style if process_sort_key == 'memory_percent' else 'DEFAULT'))
|
||||
msg = '{0:>6}'.format(_("VIRT"))
|
||||
ret.append(self.curse_add_line(msg, optional=True))
|
||||
msg = '{0:>6}'.format(_("RES"))
|
||||
ret.append(self.curse_add_line(msg, optional=True))
|
||||
msg = '{0:>6}'.format(_("PID"))
|
||||
ret.append(self.curse_add_line(msg))
|
||||
msg = ' {0:10}'.format(_("USER"))
|
||||
ret.append(self.curse_add_line(msg))
|
||||
msg = '{0:>4}'.format(_("NI"))
|
||||
ret.append(self.curse_add_line(msg))
|
||||
msg = '{0:>2}'.format(_("S"))
|
||||
ret.append(self.curse_add_line(msg))
|
||||
msg = '{0:>9}'.format(_("TIME+"))
|
||||
ret.append(self.curse_add_line(msg, optional=True))
|
||||
msg = '{0:>6}'.format(_("IOR/s"))
|
||||
ret.append(self.curse_add_line(msg, sort_style if process_sort_key == 'io_counters' else 'DEFAULT', optional=True))
|
||||
msg = '{0:>6}'.format(_("IOW/s"))
|
||||
ret.append(self.curse_add_line(msg, sort_style if process_sort_key == 'io_counters' else 'DEFAULT', optional=True))
|
||||
msg = ' {0:8}'.format(_("Command"))
|
||||
ret.append(self.curse_add_line(msg))
|
||||
|
||||
# Trying to display proc time
|
||||
tag_proc_time = True
|
||||
|
||||
# Loop over processes (sorted by the sort key previously compute)
|
||||
for p in self.sortlist(process_sort_key):
|
||||
ret.append(self.curse_new_line())
|
||||
# CPU
|
||||
msg = '{0:>6.1f}'.format(p['cpu_percent'])
|
||||
ret.append(self.curse_add_line(msg,
|
||||
self.get_alert(p['cpu_percent'], header="cpu")))
|
||||
# MEM
|
||||
msg = '{0:>6.1f}'.format(p['memory_percent'])
|
||||
ret.append(self.curse_add_line(msg,
|
||||
self.get_alert(p['memory_percent'], header="mem")))
|
||||
# VMS
|
||||
msg = '{0:>6}'.format(self.auto_unit(p['memory_info'][1], low_precision=False))
|
||||
ret.append(self.curse_add_line(msg, optional=True))
|
||||
# RSS
|
||||
msg = '{0:>6}'.format(self.auto_unit(p['memory_info'][0], low_precision=False))
|
||||
ret.append(self.curse_add_line(msg, optional=True))
|
||||
# PID
|
||||
msg = '{0:>6}'.format(p['pid'])
|
||||
ret.append(self.curse_add_line(msg))
|
||||
# USER
|
||||
msg = ' {0:9}'.format(p['username'][:9])
|
||||
ret.append(self.curse_add_line(msg))
|
||||
# NICE
|
||||
nice = p['nice']
|
||||
msg = '{0:>5}'.format(nice)
|
||||
if nice != 0:
|
||||
ret.append(self.curse_add_line(msg, decoration='NICE'))
|
||||
else:
|
||||
ret.append(self.curse_add_line(msg))
|
||||
# STATUS
|
||||
status = p['status']
|
||||
msg = '{0:>2}'.format(status)
|
||||
if status == 'R':
|
||||
ret.append(self.curse_add_line(msg, decoration='STATUS'))
|
||||
else:
|
||||
ret.append(self.curse_add_line(msg))
|
||||
# TIME+
|
||||
if tag_proc_time:
|
||||
try:
|
||||
dtime = timedelta(seconds=sum(p['cpu_times']))
|
||||
except Exception:
|
||||
# Catched on some Amazon EC2 server
|
||||
# See https://github.com/nicolargo/glances/issues/87
|
||||
tag_proc_time = False
|
||||
else:
|
||||
msg = '{0}:{1}.{2}'.format(str(dtime.seconds // 60 % 60),
|
||||
str(dtime.seconds % 60).zfill(2),
|
||||
str(dtime.microseconds)[:2].zfill(2))
|
||||
else:
|
||||
msg = ' '
|
||||
msg = '{0:>9}'.format(msg)
|
||||
ret.append(self.curse_add_line(msg, optional=True))
|
||||
# IO read/write
|
||||
if 'io_counters' in p:
|
||||
# IO read
|
||||
io_rs = (p['io_counters'][0] - p['io_counters'][2]) / p['time_since_update']
|
||||
if io_rs == 0:
|
||||
msg = '{0:>6}'.format("0")
|
||||
else:
|
||||
msg = '{0:>6}'.format(self.auto_unit(io_rs, low_precision=False))
|
||||
ret.append(self.curse_add_line(msg, optional=True))
|
||||
# IO write
|
||||
io_ws = (p['io_counters'][1] - p['io_counters'][3]) / p['time_since_update']
|
||||
if io_ws == 0:
|
||||
msg = '{0:>6}'.format("0")
|
||||
else:
|
||||
msg = '{0:>6}'.format(self.auto_unit(io_ws, low_precision=False))
|
||||
ret.append(self.curse_add_line(msg, optional=True))
|
||||
else:
|
||||
msg = '{0:>6}'.format("?")
|
||||
ret.append(self.curse_add_line(msg, optional=True))
|
||||
ret.append(self.curse_add_line(msg, optional=True))
|
||||
# Command line
|
||||
# If no command line for the process is available, fallback to
|
||||
# the bare process name instead
|
||||
cmdline = p['cmdline']
|
||||
if cmdline == "":
|
||||
msg = ' {0}'.format(p['name'])
|
||||
ret.append(self.curse_add_line(msg, splittable=True))
|
||||
else:
|
||||
try:
|
||||
cmd = cmdline.split()[0]
|
||||
args = ' '.join(cmdline.split()[1:])
|
||||
path, basename = os.path.split(cmd)
|
||||
if os.path.isdir(path):
|
||||
msg = ' {0}'.format(path) + os.sep
|
||||
ret.append(self.curse_add_line(msg, splittable=True))
|
||||
ret.append(self.curse_add_line(basename, decoration='PROCESS', splittable=True))
|
||||
else:
|
||||
msg = ' {0}'.format(basename)
|
||||
ret.append(self.curse_add_line(msg, decoration='PROCESS', splittable=True))
|
||||
msg = " {0}".format(args)
|
||||
ret.append(self.curse_add_line(msg, splittable=True))
|
||||
except UnicodeEncodeError:
|
||||
ret.append(self.curse_add_line("", splittable=True))
|
||||
|
||||
# Return the message with decoration
|
||||
return ret
|
||||
|
||||
def sortlist(self, sortedby=None):
|
||||
"""Return the stats sorted by sortedby variable."""
|
||||
if sortedby is None:
|
||||
# No need to sort...
|
||||
return self.stats
|
||||
|
||||
sortedreverse = True
|
||||
if sortedby == 'name':
|
||||
sortedreverse = False
|
||||
|
||||
if sortedby == 'io_counters':
|
||||
# Specific case for io_counters
|
||||
# Sum of io_r + io_w
|
||||
try:
|
||||
# Sort process by IO rate (sum IO read + IO write)
|
||||
listsorted = sorted(self.stats,
|
||||
key=lambda process: process[sortedby][0] -
|
||||
process[sortedby][2] + process[sortedby][1] -
|
||||
process[sortedby][3],
|
||||
reverse=sortedreverse)
|
||||
except Exception:
|
||||
listsorted = sorted(self.stats,
|
||||
key=lambda process: process['cpu_percent'],
|
||||
reverse=sortedreverse)
|
||||
else:
|
||||
# Others sorts
|
||||
listsorted = sorted(self.stats,
|
||||
key=lambda process: process[sortedby],
|
||||
reverse=sortedreverse)
|
||||
|
||||
self.stats = listsorted
|
||||
|
||||
return self.stats
|
57
glances/plugins/glances_psutilversion.py
Normal file
@ -0,0 +1,57 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
#
|
||||
# This file is part of Glances.
|
||||
#
|
||||
# Copyright (C) 2014 Nicolargo <nicolas@nicolargo.com>
|
||||
#
|
||||
# Glances is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU Lesser General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# Glances is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU Lesser General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU Lesser General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
from glances.plugins.glances_plugin import GlancesPlugin
|
||||
|
||||
from psutil import __version__ as __psutil_version
|
||||
|
||||
|
||||
class Plugin(GlancesPlugin):
|
||||
|
||||
"""Get the psutil version for client/server purposes.
|
||||
|
||||
stats is a tuple
|
||||
"""
|
||||
|
||||
def __init__(self, args=None):
|
||||
"""Init the plugin."""
|
||||
GlancesPlugin.__init__(self, args=args)
|
||||
|
||||
self.reset()
|
||||
|
||||
def reset(self):
|
||||
"""Reset/init the stats."""
|
||||
self.stats = None
|
||||
|
||||
def update(self):
|
||||
"""Update the stats."""
|
||||
# Reset stats
|
||||
self.reset()
|
||||
|
||||
# Return PsUtil version as a tuple
|
||||
if self.get_input() == 'local':
|
||||
# PsUtil version only available in local
|
||||
try:
|
||||
self.stats = tuple([int(num) for num in __psutil_version.split('.')])
|
||||
except NameError:
|
||||
pass
|
||||
else:
|
||||
pass
|
||||
|
||||
return self.stats
|
188
glances/plugins/glances_sensors.py
Normal file
@ -0,0 +1,188 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
#
|
||||
# This file is part of Glances.
|
||||
#
|
||||
# Copyright (C) 2014 Nicolargo <nicolas@nicolargo.com>
|
||||
#
|
||||
# Glances is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU Lesser General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# Glances is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU Lesser General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU Lesser General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
"""Sensors plugin."""
|
||||
|
||||
# Sensors library (optional; Linux-only)
|
||||
# Py3Sensors: https://bitbucket.org/gleb_zhulik/py3sensors
|
||||
try:
|
||||
import sensors
|
||||
except ImportError:
|
||||
pass
|
||||
|
||||
# Import Glances lib
|
||||
from glances.core.glances_globals import is_py3
|
||||
from glances.plugins.glances_batpercent import Plugin as BatPercentPlugin
|
||||
from glances.plugins.glances_hddtemp import Plugin as HddTempPlugin
|
||||
from glances.plugins.glances_plugin import GlancesPlugin
|
||||
|
||||
|
||||
class Plugin(GlancesPlugin):
|
||||
|
||||
"""Glances' sensors plugin.
|
||||
|
||||
The stats list includes both sensors and hard disks stats, if any.
|
||||
The sensors are already grouped by chip type and then sorted by name.
|
||||
The hard disks are already sorted by name.
|
||||
"""
|
||||
|
||||
def __init__(self, args=None):
|
||||
"""Init the plugin."""
|
||||
GlancesPlugin.__init__(self, args=args)
|
||||
|
||||
# Init the sensor class
|
||||
self.glancesgrabsensors = GlancesGrabSensors()
|
||||
|
||||
# Instance for the HDDTemp Plugin in order to display the hard disks temperatures
|
||||
self.hddtemp_plugin = HddTempPlugin()
|
||||
|
||||
# Instance for the BatPercent in order to display the batteries capacities
|
||||
self.batpercent_plugin = BatPercentPlugin()
|
||||
|
||||
# We want to display the stat in the curse interface
|
||||
self.display_curse = True
|
||||
# Set the message position
|
||||
# It is NOT the curse position but the Glances column/line
|
||||
# Enter -1 to right align
|
||||
self.column_curse = 0
|
||||
# Enter -1 to diplay bottom
|
||||
self.line_curse = 5
|
||||
|
||||
# Init the stats
|
||||
self.reset()
|
||||
|
||||
def reset(self):
|
||||
"""Reset/init the stats."""
|
||||
self.stats = []
|
||||
|
||||
def update(self):
|
||||
"""Update sensors stats using the input method."""
|
||||
# Reset the stats
|
||||
self.reset()
|
||||
|
||||
if self.get_input() == 'local':
|
||||
# Update stats using the standard system lib
|
||||
self.stats = self.__set_type(self.glancesgrabsensors.get(), 'temperature_core')
|
||||
# Append HDD temperature
|
||||
hddtemp = self.__set_type(self.hddtemp_plugin.update(), 'temperature_hdd')
|
||||
self.stats.extend(hddtemp)
|
||||
# Append Batteries %
|
||||
batpercent = self.__set_type(self.batpercent_plugin.update(), 'battery')
|
||||
self.stats.extend(batpercent)
|
||||
elif self.get_input() == 'snmp':
|
||||
# Update stats using SNMP
|
||||
# No standard: http://www.net-snmp.org/wiki/index.php/Net-SNMP_and_lm-sensors_on_Ubuntu_10.04
|
||||
pass
|
||||
|
||||
return self.stats
|
||||
|
||||
def __set_type(self, stats, sensor_type):
|
||||
"""Set the plugin type.
|
||||
|
||||
3 types of stats is possible in the sensors plugin:
|
||||
- Core temperature
|
||||
- HDD temperature
|
||||
- Battery capacity
|
||||
"""
|
||||
for i in stats:
|
||||
i.update({'type': sensor_type})
|
||||
return stats
|
||||
|
||||
def msg_curse(self, args=None):
|
||||
"""Return the dict to display in the curse interface."""
|
||||
# Init the return message
|
||||
ret = []
|
||||
|
||||
# Only process if stats exist and display plugin enable...
|
||||
if self.stats == [] or args.disable_sensors:
|
||||
return ret
|
||||
|
||||
# Build the string message
|
||||
# Header
|
||||
msg = '{0:18}'.format(_("SENSORS"))
|
||||
ret.append(self.curse_add_line(msg, "TITLE"))
|
||||
if is_py3:
|
||||
msg = '{0:>5}'.format(_("°C"))
|
||||
else:
|
||||
msg = '{0:>6}'.format(_("°C"))
|
||||
ret.append(self.curse_add_line(msg))
|
||||
|
||||
for item in self.stats:
|
||||
# New line
|
||||
ret.append(self.curse_new_line())
|
||||
msg = '{0:18}'.format(item['label'][:18])
|
||||
ret.append(self.curse_add_line(msg))
|
||||
msg = '{0:>5}'.format(item['value'])
|
||||
if item['type'] == 'battery':
|
||||
try:
|
||||
ret.append(self.curse_add_line(msg, self.get_alert(100 - item['value'], header=item['type'])))
|
||||
except TypeError:
|
||||
pass
|
||||
else:
|
||||
ret.append(self.curse_add_line(msg, self.get_alert(item['value'], header=item['type'])))
|
||||
|
||||
return ret
|
||||
|
||||
|
||||
class GlancesGrabSensors(object):
|
||||
|
||||
"""Get sensors stats using the py3sensors library."""
|
||||
|
||||
def __init__(self):
|
||||
"""Init sensors stats."""
|
||||
try:
|
||||
sensors.init()
|
||||
except Exception:
|
||||
self.initok = False
|
||||
else:
|
||||
self.initok = True
|
||||
|
||||
# Init the stats
|
||||
self.reset()
|
||||
|
||||
def reset(self):
|
||||
"""Reset/init the stats."""
|
||||
self.sensors_list = []
|
||||
|
||||
def __update__(self):
|
||||
"""Update the stats."""
|
||||
# Reset the list
|
||||
self.reset()
|
||||
|
||||
# grab only temperature stats
|
||||
if self.initok:
|
||||
for chip in sensors.iter_detected_chips():
|
||||
for feature in chip:
|
||||
sensors_current = {}
|
||||
if feature.name.startswith(b'temp'):
|
||||
sensors_current['label'] = feature.label
|
||||
sensors_current['value'] = int(feature.get_value())
|
||||
self.sensors_list.append(sensors_current)
|
||||
|
||||
return self.sensors_list
|
||||
|
||||
def get(self):
|
||||
"""Get sensors list."""
|
||||
self.__update__()
|
||||
return self.sensors_list
|
||||
|
||||
def quit(self):
|
||||
"""End of connection."""
|
||||
if self.initok:
|
||||
sensors.cleanup()
|
134
glances/plugins/glances_system.py
Normal file
@ -0,0 +1,134 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
#
|
||||
# This file is part of Glances.
|
||||
#
|
||||
# Copyright (C) 2014 Nicolargo <nicolas@nicolargo.com>
|
||||
#
|
||||
# Glances is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU Lesser General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# Glances is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU Lesser General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU Lesser General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
"""System plugin."""
|
||||
|
||||
# Import system libs
|
||||
import os
|
||||
import platform
|
||||
|
||||
# Import Glances libs
|
||||
from glances.plugins.glances_plugin import GlancesPlugin
|
||||
|
||||
# SNMP OID
|
||||
snmp_oid = {'hostname': '1.3.6.1.2.1.1.5.0',
|
||||
'os_name': '1.3.6.1.2.1.1.1.0'}
|
||||
|
||||
|
||||
class Plugin(GlancesPlugin):
|
||||
|
||||
"""Glances' host/system plugin.
|
||||
|
||||
stats is a dict
|
||||
"""
|
||||
|
||||
def __init__(self, args=None):
|
||||
"""Init the plugin."""
|
||||
GlancesPlugin.__init__(self, args=args)
|
||||
|
||||
# We want to display the stat in the curse interface
|
||||
self.display_curse = True
|
||||
# Set the message position
|
||||
# It is NOT the curse position but the Glances column/line
|
||||
# Enter -1 to right align
|
||||
self.column_curse = 0
|
||||
# Enter -1 to diplay bottom
|
||||
self.line_curse = 0
|
||||
|
||||
# Init the stats
|
||||
self.reset()
|
||||
|
||||
def reset(self):
|
||||
"""Reset/init the stats."""
|
||||
self.stats = {}
|
||||
|
||||
def update(self):
|
||||
"""Update the host/system info using the input method.
|
||||
|
||||
Return the stats (dict)
|
||||
"""
|
||||
# Reset stats
|
||||
self.reset()
|
||||
|
||||
if self.get_input() == 'local':
|
||||
# Update stats using the standard system lib
|
||||
self.stats['os_name'] = platform.system()
|
||||
self.stats['hostname'] = platform.node()
|
||||
self.stats['platform'] = platform.architecture()[0]
|
||||
is_archlinux = os.path.exists(os.path.join("/", "etc", "arch-release"))
|
||||
if self.stats['os_name'] == "Linux":
|
||||
if is_archlinux:
|
||||
self.stats['linux_distro'] = "Arch Linux"
|
||||
else:
|
||||
linux_distro = platform.linux_distribution()
|
||||
self.stats['linux_distro'] = ' '.join(linux_distro[:2])
|
||||
self.stats['os_version'] = platform.release()
|
||||
elif self.stats['os_name'] == "FreeBSD":
|
||||
self.stats['os_version'] = platform.release()
|
||||
elif self.stats['os_name'] == "Darwin":
|
||||
self.stats['os_version'] = platform.mac_ver()[0]
|
||||
elif self.stats['os_name'] == "Windows":
|
||||
os_version = platform.win32_ver()
|
||||
self.stats['os_version'] = ' '.join(os_version[::2])
|
||||
else:
|
||||
self.stats['os_version'] = ""
|
||||
elif self.get_input() == 'snmp':
|
||||
# Update stats using SNMP
|
||||
self.stats = self.set_stats_snmp(snmp_oid=snmp_oid)
|
||||
|
||||
return self.stats
|
||||
|
||||
def msg_curse(self, args=None):
|
||||
"""Return the string to display in the curse interface."""
|
||||
# Init the return message
|
||||
ret = []
|
||||
|
||||
# Build the string message
|
||||
if args.client:
|
||||
# Client mode
|
||||
if args.cs_status.lower() == "connected":
|
||||
msg = _("Connected to ")
|
||||
ret.append(self.curse_add_line(msg, 'OK'))
|
||||
elif args.cs_status.lower() == "snmp":
|
||||
msg = _("SNMP from ")
|
||||
ret.append(self.curse_add_line(msg, 'OK'))
|
||||
elif args.cs_status.lower() == "disconnected":
|
||||
msg = _("Disconnected from ")
|
||||
ret.append(self.curse_add_line(msg, 'CRITICAL'))
|
||||
|
||||
# Hostname is mandatory
|
||||
msg = self.stats['hostname']
|
||||
ret.append(self.curse_add_line(msg, "TITLE"))
|
||||
# System info
|
||||
if self.stats['os_name'] == "Linux":
|
||||
msg = ' ({0} {1} / {2} {3})'.format(self.stats['linux_distro'],
|
||||
self.stats['platform'],
|
||||
self.stats['os_name'],
|
||||
self.stats['os_version'])
|
||||
else:
|
||||
try:
|
||||
msg = ' ({0} {1} {2})'.format(self.stats['os_name'],
|
||||
self.stats['os_version'],
|
||||
self.stats['platform'])
|
||||
except:
|
||||
msg = ' ({0})'.format(self.stats['os_name'])
|
||||
ret.append(self.curse_add_line(msg, optional=True))
|
||||
|
||||
# Return the message with decoration
|
||||
return ret
|
93
glances/plugins/glances_uptime.py
Normal file
@ -0,0 +1,93 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
#
|
||||
# This file is part of Glances.
|
||||
#
|
||||
# Copyright (C) 2014 Nicolargo <nicolas@nicolargo.com>
|
||||
#
|
||||
# Glances is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU Lesser General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# Glances is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU Lesser General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU Lesser General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
"""Uptime plugin."""
|
||||
|
||||
# Import system libs
|
||||
from datetime import datetime, timedelta
|
||||
|
||||
# Import Glances libs
|
||||
from glances.plugins.glances_plugin import GlancesPlugin
|
||||
|
||||
# Check for psutil already done in the glances_core script
|
||||
import psutil
|
||||
|
||||
# SNMP OID
|
||||
snmp_oid = {'_uptime': '1.3.6.1.2.1.1.3.0'}
|
||||
|
||||
|
||||
class Plugin(GlancesPlugin):
|
||||
|
||||
"""Glances' uptime plugin.
|
||||
|
||||
stats is date (string)
|
||||
"""
|
||||
|
||||
def __init__(self, args=None):
|
||||
"""Init the plugin."""
|
||||
GlancesPlugin.__init__(self, args=args)
|
||||
|
||||
# We want to display the stat in the curse interface
|
||||
self.display_curse = True
|
||||
# Set the message position
|
||||
# It is NOT the curse position but the Glances column/line
|
||||
# Enter -1 to right align
|
||||
self.column_curse = -1
|
||||
# Enter -1 to diplay bottom
|
||||
self.line_curse = 0
|
||||
# Init the stats
|
||||
self.reset()
|
||||
|
||||
def reset(self):
|
||||
"""Reset/init the stats."""
|
||||
self.stats = {}
|
||||
|
||||
def update(self):
|
||||
"""Update uptime stat using the input method."""
|
||||
# Reset stats
|
||||
self.reset()
|
||||
|
||||
if self.get_input() == 'local':
|
||||
# Update stats using the standard system lib
|
||||
uptime = datetime.now() - datetime.fromtimestamp(psutil.boot_time())
|
||||
|
||||
# Convert uptime to string (because datetime is not JSONifi)
|
||||
self.stats = str(uptime).split('.')[0]
|
||||
elif self.get_input() == 'snmp':
|
||||
# Update stats using SNMP
|
||||
uptime = self.set_stats_snmp(snmp_oid=snmp_oid)['_uptime']
|
||||
try:
|
||||
# In hundredths of seconds
|
||||
self.stats = str(timedelta(seconds=int(uptime) / 100))
|
||||
except:
|
||||
pass
|
||||
|
||||
# Return the result
|
||||
return self.stats
|
||||
|
||||
def msg_curse(self, args=None):
|
||||
"""Return the string to display in the curse interface."""
|
||||
# Init the return message
|
||||
ret = []
|
||||
|
||||
# Add the line with decoration
|
||||
ret.append(self.curse_add_line(_("Uptime: {0}").format(self.stats)))
|
||||
|
||||
# Return the message with decoration
|
||||
return ret
|
@ -1,126 +0,0 @@
|
||||
#!/usr/bin/env python
|
||||
# -*- coding: utf-8 -*-
|
||||
#
|
||||
# Glances unitary test
|
||||
#
|
||||
# Copyright (C) 2012 Nicolargo <nicolas@nicolargo.com>
|
||||
#
|
||||
# Glances is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU Lesser General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# Glances is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU Lesser General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU Lesser General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
|
||||
# import os
|
||||
# import time
|
||||
# import signal
|
||||
import unittest
|
||||
import multiprocessing
|
||||
|
||||
from glances import glances
|
||||
|
||||
|
||||
class TestGlancesStat(unittest.TestCase):
|
||||
|
||||
def setUp(self):
|
||||
self.stats = glances.GlancesStats()
|
||||
self.stats.update()
|
||||
|
||||
def test_Glances_getSystem(self):
|
||||
self.stats.update()
|
||||
system = self.stats.getSystem()
|
||||
#~ print("System info: %s" % system)
|
||||
self.assertTrue(type(system) == dict)
|
||||
self.assertTrue(len(system) > 1)
|
||||
|
||||
def test_Glances_getCore(self):
|
||||
self.stats.update()
|
||||
core = self.stats.getCore()
|
||||
#~ print("CPU Core number: %s" % core)
|
||||
self.assertTrue(type(core) == int)
|
||||
self.assertEqual(core, multiprocessing.cpu_count())
|
||||
|
||||
def test_Glances_getCpu(self):
|
||||
self.stats.update()
|
||||
cpu = self.stats.getCpu()
|
||||
#~ print("CPU stat %s:" % cpu)
|
||||
self.assertTrue(type(cpu) == dict)
|
||||
self.assertTrue(len(cpu) > 1)
|
||||
|
||||
def test_Glances_getPerCpu(self):
|
||||
self.stats.update()
|
||||
percpu = self.stats.getPerCpu()
|
||||
#~ print("PerCPU stat %s:" % percpu)
|
||||
self.assertTrue(type(percpu) == list)
|
||||
self.assertEqual(len(percpu), multiprocessing.cpu_count())
|
||||
|
||||
def test_Glances_getMem(self):
|
||||
self.stats.update()
|
||||
mem = self.stats.getMem()
|
||||
#~ print("Mem stat %s:" % mem)
|
||||
self.assertTrue(type(mem) == dict)
|
||||
self.assertTrue(len(mem) > 2)
|
||||
|
||||
def test_Glances_getMemSwap(self):
|
||||
self.stats.update()
|
||||
memswap = self.stats.getMemSwap()
|
||||
#~ print("MemSwap stat %s:" % memswap)
|
||||
self.assertTrue(type(memswap) == dict)
|
||||
self.assertTrue(len(memswap) > 2)
|
||||
|
||||
def test_Glances_getNetwork(self):
|
||||
self.stats.update()
|
||||
net = self.stats.getNetwork()
|
||||
#~ print("Network stat %s:" % net)
|
||||
self.assertTrue(type(net) == list)
|
||||
self.assertTrue(len(net) > 0)
|
||||
|
||||
def test_Glances_getDiskIO(self):
|
||||
self.stats.update()
|
||||
diskio = self.stats.getDiskIO()
|
||||
#~ print("DiskIO stat %s:" % diskio)
|
||||
self.assertTrue(type(diskio) == list)
|
||||
self.assertTrue(len(diskio) > 0)
|
||||
|
||||
def test_Glances_getFs(self):
|
||||
self.stats.update()
|
||||
fs = self.stats.getFs()
|
||||
#~ print("File system stat %s:" % fs)
|
||||
self.assertTrue(type(fs) == list)
|
||||
self.assertTrue(len(fs) > 0)
|
||||
|
||||
def test_Glances_getProcess(self):
|
||||
self.stats.update()
|
||||
pc = self.stats.getProcessCount()
|
||||
pl = self.stats.getProcessList()
|
||||
#~ print("Processes stat %s:" % pc)
|
||||
#~ print("Processes list %s:" % pl)
|
||||
self.assertTrue(type(pc) == dict)
|
||||
self.assertTrue(len(pc) > 2)
|
||||
self.assertTrue(type(pl) == list)
|
||||
self.assertTrue(len(pl) > 0)
|
||||
|
||||
def test_Glances_getSensors(self):
|
||||
self.stats.update()
|
||||
sensors = self.stats.getSensors()
|
||||
#~ print("Optionnal sensors stat %s:" % sensors)
|
||||
self.assertTrue(type(sensors) == list)
|
||||
#~ self.assertTrue(len(sensors) > 0)
|
||||
|
||||
def test_Glances_getHDDTemp(self):
|
||||
self.stats.update()
|
||||
hddtemp = self.stats.getHDDTemp()
|
||||
#~ print("Optionnal hddtemp stat %s:" % hddtemp)
|
||||
self.assertTrue(type(hddtemp) == list)
|
||||
#~ self.assertTrue(len(hddtemp) > 0)
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
@ -31,7 +31,7 @@ exit
|
||||
}
|
||||
|
||||
function gen_pot() {
|
||||
xgettext --language=Python --keyword=_ --output=${ROOT}i18n/glances.pot ${ROOT}glances/glances.py
|
||||
xgettext --language=Python --keyword=_ --output=${ROOT}i18n/glances.pot `find ${ROOT}glances/ -name "*.py"`
|
||||
}
|
||||
|
||||
OPERATION="$1"
|
||||
|
@ -1,14 +1,21 @@
|
||||
# German translations for GLANCES package
|
||||
# Copyright (C) 2013 THE PACKAGE'S COPYRIGHT HOLDER
|
||||
# German translations for GLANCES package.
|
||||
# Copyright (C) 2014 THE GLANCES'S COPYRIGHT HOLDER
|
||||
# This file is distributed under the same license as the GLANCES package.
|
||||
# David Tiersch <d.tiersch@gmail.com>, 2013.
|
||||
# David Tiersch <d.tiersch@gmail.com>, 2014.
|
||||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
<<<<<<< HEAD
|
||||
"Project-Id-Version: GLANCES 1.7.6\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2014-03-27 18:39+0100\n"
|
||||
"PO-Revision-Date: 2014-03-27 19:07+0100\n"
|
||||
=======
|
||||
"Project-Id-Version: GLANCES 2.0_RC4\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2014-06-03 16:21+0200\n"
|
||||
"PO-Revision-Date: 2014-06-03 16:33+0100\n"
|
||||
>>>>>>> release/v2.0
|
||||
"Last-Translator: David Tiersch <d.tiersch@gmail.com>\n"
|
||||
"Language-Team: German\n"
|
||||
"Language: de\n"
|
||||
@ -16,6 +23,7 @@ msgstr ""
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
|
||||
<<<<<<< HEAD
|
||||
"X-Generator: Poedit 1.6.4\n"
|
||||
|
||||
#: glances/glances.py:405
|
||||
@ -393,9 +401,374 @@ msgid "m"
|
||||
msgstr "m"
|
||||
|
||||
#: glances/glances.py:3967
|
||||
msgid "Sort processes by MEM%"
|
||||
msgstr "Prozesse nach MEM% sortieren"
|
||||
=======
|
||||
"X-Generator: Poedit 1.5.4\n"
|
||||
"X-Poedit-Basepath: ~/dev/glances\n"
|
||||
|
||||
#: glances/__init__.py:105
|
||||
msgid "Error: The server version is not compatible with the client"
|
||||
msgstr "Fehler: Die Server-Version ist mit dem Client nicht kompatibel"
|
||||
|
||||
#: glances/__init__.py:124
|
||||
#, python-brace-format
|
||||
msgid "Glances server is running on {0}:{1}"
|
||||
msgstr "Glances-Server läuft auf {0}:{1}"
|
||||
|
||||
#: glances/core/glances_stats.py:264
|
||||
#, python-brace-format
|
||||
msgid "Error: Update {0} failed: {1}"
|
||||
msgstr "Fehler: Aktualisierung {0} ist fehlgeschlagen: {1}"
|
||||
|
||||
#: glances/core/glances_client.py:62
|
||||
#, python-brace-format
|
||||
msgid "Error: Couldn't create socket {0}: {1}"
|
||||
msgstr "Fehler: Konnte Socket {0} nicht erzeugen: {1}"
|
||||
|
||||
#: glances/core/glances_client.py:100
|
||||
msgid "Error: Connection to server failed: Bad password"
|
||||
msgstr "Fehler: Verbindung zum Server fehlgeschlagen: Falsches Passwort"
|
||||
|
||||
#: glances/core/glances_client.py:102
|
||||
#, python-brace-format
|
||||
msgid "Error: Connection to server failed: {0}"
|
||||
msgstr "Fehler: Verbindung zum Server fehlgeschlagen: {0}"
|
||||
|
||||
#: glances/core/glances_client.py:110
|
||||
msgid "Info: Connection to Glances server failed. Trying fallback to SNMP..."
|
||||
msgstr ""
|
||||
"Info: Verbindung zum Glances-Server fehlgeschlagen. Versuche Fallback zu "
|
||||
"SNMP..."
|
||||
|
||||
#: glances/core/glances_client.py:118
|
||||
msgid "Error: Connection to SNMP server failed"
|
||||
msgstr "Fehler: Verbindung zum SNMP-Server fehlgeschlagen"
|
||||
|
||||
#: glances/core/glances_client.py:147
|
||||
#, python-brace-format
|
||||
msgid "Error: Unknown server mode: {0}"
|
||||
msgstr "Fehler: Unbekannter Servers-Modus: {0}"
|
||||
|
||||
#: glances/core/glances_config.py:71
|
||||
#, python-brace-format
|
||||
msgid "Error: Cannot decode configuration file '{0}': {1}"
|
||||
msgstr "Fehler: Kann Konfigurationsdatei '{0}' nicht lesen: {1}"
|
||||
|
||||
#: glances/core/glances_main.py:65
|
||||
msgid "display network rate in byte per second"
|
||||
msgstr "Netzwerkgeschwindigkeit anzeigen in Byte/Sekunde"
|
||||
|
||||
#: glances/core/glances_main.py:67
|
||||
msgid "bind server to the given IPv4/IPv6 address or hostname"
|
||||
msgstr "Server auf gegebene IPv4/IPv6-Adresse oder Hostnamen festlegen"
|
||||
|
||||
#: glances/core/glances_main.py:69
|
||||
msgid "connect to a Glances server by IPv4/IPv6 address or hostname"
|
||||
msgstr "Zu einem Glances-Server mit IPv4/IPv6-Adresse oder Hostnamen verbinden"
|
||||
|
||||
#: glances/core/glances_main.py:71
|
||||
msgid "path to the configuration file"
|
||||
msgstr "Pfad zur Konfigurationsdatei"
|
||||
|
||||
#: glances/core/glances_main.py:74
|
||||
msgid "disable bold mode in the terminal"
|
||||
msgstr "Fett-Modus im Terminal deaktivieren"
|
||||
|
||||
#: glances/core/glances_main.py:76
|
||||
msgid "disable disk I/O module"
|
||||
msgstr "Disk-I/O-Modul deaktivieren"
|
||||
|
||||
#: glances/core/glances_main.py:78
|
||||
msgid "disable filesystem module"
|
||||
msgstr "Dateisystem-Modul deaktivieren"
|
||||
|
||||
#: glances/core/glances_main.py:80
|
||||
msgid "disable network module"
|
||||
msgstr "Netzwerk-Modul deaktivieren"
|
||||
|
||||
#: glances/core/glances_main.py:82
|
||||
msgid "disable sensors module"
|
||||
msgstr "Sensor-Modul deaktivieren"
|
||||
|
||||
#: glances/core/glances_main.py:84
|
||||
msgid "disable process module"
|
||||
msgstr "Prozess-Modul deaktivieren"
|
||||
|
||||
#: glances/core/glances_main.py:86
|
||||
msgid "disable log module"
|
||||
msgstr "Log-Modul deaktivieren"
|
||||
|
||||
#: glances/core/glances_main.py:89
|
||||
msgid "export stats to a CSV file"
|
||||
msgstr "Exportiere Daten zu CSV-Datei"
|
||||
|
||||
#: glances/core/glances_main.py:92
|
||||
#, python-brace-format
|
||||
msgid "define the client/server TCP port [default: {0}]"
|
||||
msgstr "Client-/Server-TCP-Port festlegen [default: {0}]"
|
||||
|
||||
#: glances/core/glances_main.py:94
|
||||
msgid "define password from the command line"
|
||||
msgstr "Passwort auf Kommandozeile bestimmen"
|
||||
|
||||
#: glances/core/glances_main.py:96
|
||||
msgid "define a client/server password from the prompt or file"
|
||||
msgstr "Client-/Server-Passwort über Prompt oder Datei festlegen"
|
||||
|
||||
#: glances/core/glances_main.py:98
|
||||
msgid "run Glances in server mode"
|
||||
msgstr "Glances im Server-Modus ausführen"
|
||||
|
||||
#: glances/core/glances_main.py:100
|
||||
msgid "SNMP community"
|
||||
msgstr "SNMP-Community"
|
||||
|
||||
#: glances/core/glances_main.py:102
|
||||
msgid "SNMP port"
|
||||
msgstr "SNMP-Port"
|
||||
|
||||
#: glances/core/glances_main.py:104
|
||||
msgid "SNMP version (1, 2c or 3)"
|
||||
msgstr "SNMP-Version (1, 2c oder 3)"
|
||||
|
||||
#: glances/core/glances_main.py:106
|
||||
msgid "SNMP username (only for SNMPv3)"
|
||||
msgstr "SNMP-Benutzername (nur für SNMPv3)"
|
||||
|
||||
#: glances/core/glances_main.py:108
|
||||
msgid "SNMP authentication key (only for SNMPv3)"
|
||||
msgstr "SNMP-Authentifizierungs-Schlüssel (nur für SNMPv3)"
|
||||
|
||||
#: glances/core/glances_main.py:110
|
||||
#, python-brace-format
|
||||
msgid "set refresh time in seconds [default: {0} sec]"
|
||||
msgstr "Aktualisierungszeit in Sekunden [default: {0} Sek]"
|
||||
|
||||
#: glances/core/glances_main.py:112
|
||||
msgid "run Glances in web server mode"
|
||||
msgstr "Glances im Webserver-Modus starten"
|
||||
|
||||
#: glances/core/glances_main.py:115
|
||||
msgid "start Glances in per CPU mode"
|
||||
msgstr "Glances im pro-CPU-Modus starten"
|
||||
|
||||
#: glances/core/glances_main.py:145
|
||||
msgid "Define the password for the Glances server"
|
||||
msgstr "Passwort für Glances-Server festlegen"
|
||||
|
||||
#: glances/core/glances_main.py:149
|
||||
msgid "Enter the Glances server password"
|
||||
msgstr "Passwort für Glances-Server eingeben"
|
||||
|
||||
#: glances/core/glances_monitor_list.py:74
|
||||
#, python-brace-format
|
||||
msgid "Error: Cannot read monitored list: {0}"
|
||||
msgstr "Fehler: Kann Überwachungs-Liste nicht lesen: {0}"
|
||||
|
||||
#: glances/core/glances_monitor_list.py:143
|
||||
msgid "Error: "
|
||||
msgstr "Fehler: "
|
||||
|
||||
#: glances/core/glances_monitor_list.py:145
|
||||
msgid "Cannot execute command"
|
||||
msgstr "Kann Befehl nicht ausführen"
|
||||
|
||||
#: glances/core/glances_password.py:111
|
||||
#, python-brace-format
|
||||
msgid "Info: Read password from file: {0}"
|
||||
msgstr "Info: Passwort gelesen aus Datei {0}"
|
||||
|
||||
#: glances/core/glances_password.py:120
|
||||
msgid "Password: "
|
||||
msgstr "Passwort:"
|
||||
|
||||
#: glances/core/glances_password.py:124
|
||||
msgid "Password (confirm): "
|
||||
msgstr "Passwort (wiederholen):"
|
||||
|
||||
#: glances/core/glances_password.py:127
|
||||
msgid "Error: Sorry, but passwords did not match..."
|
||||
msgstr "Fehler: Passwörter stimmen nicht überein..."
|
||||
|
||||
#: glances/core/glances_password.py:138
|
||||
msgid "Do you want to save the password? [Yes/No]: "
|
||||
msgstr "Willst du das Passwort speichern? [Ja/Nein]"
|
||||
|
||||
#: glances/core/glances_password.py:139
|
||||
msgid "Y"
|
||||
msgstr "J"
|
||||
|
||||
#: glances/core/glances_password.py:154
|
||||
#, python-brace-format
|
||||
msgid "Warning: Cannot create Glances directory: {0}"
|
||||
msgstr "Warnung: Kann Glances-Ordner nicht erzeugen: {0}"
|
||||
|
||||
#: glances/core/glances_server.py:115
|
||||
#, python-brace-format
|
||||
msgid "Error: Couldn't open socket: {0}"
|
||||
msgstr "Fehler: Kann Socket nicht öffnen: {0}"
|
||||
|
||||
#: glances/core/glances_server.py:205
|
||||
#, python-brace-format
|
||||
msgid "Error: Cannot start Glances server: {0}"
|
||||
msgstr "Fehler: Kann Glances-Server nicht starten: {0}"
|
||||
|
||||
#: glances/outputs/glances_curses.py:61
|
||||
msgid "Error: Cannot init the curses library.\n"
|
||||
msgstr "Fehler: Kann curses-Bibliothek nicht initialisieren.\n"
|
||||
|
||||
#: glances/outputs/glances_csv.py:48
|
||||
#, python-brace-format
|
||||
msgid "Error: Cannot create the CSV file: {0}"
|
||||
msgstr "Fehler: Kann CSV-Datei nicht erzeugen: {0}"
|
||||
|
||||
#: glances/outputs/glances_csv.py:51
|
||||
#, python-brace-format
|
||||
msgid "Stats dumped to CSV file: {0}"
|
||||
msgstr "Daten nach CSV-Datei gespeichert: {0}"
|
||||
|
||||
#: glances/plugins/glances_uptime.py:95
|
||||
#, python-brace-format
|
||||
msgid "Uptime: {0}"
|
||||
msgstr "Betriebszeit: {0}"
|
||||
|
||||
#: glances/plugins/glances_alert.py:78
|
||||
msgid "No warning or critical alert detected"
|
||||
msgstr "Keine (kritische) Warnung entdeckt"
|
||||
|
||||
#: glances/plugins/glances_alert.py:82
|
||||
msgid "Warning or critical alerts"
|
||||
msgstr "(Kritische) Warnungen"
|
||||
|
||||
#: glances/plugins/glances_alert.py:86
|
||||
#, python-brace-format
|
||||
msgid " (lasts {0} entries)"
|
||||
msgstr " (letzte {0} Einträge)"
|
||||
|
||||
#: glances/plugins/glances_alert.py:88
|
||||
msgid " (one entry)"
|
||||
msgstr " (ein Eintrag)"
|
||||
|
||||
#: glances/plugins/glances_alert.py:102
|
||||
msgid " (ongoing)"
|
||||
msgstr "(laufend)"
|
||||
|
||||
#: glances/plugins/glances_alert.py:108
|
||||
#, python-brace-format
|
||||
msgid "{0} on {1}"
|
||||
msgstr "{0} auf {1}"
|
||||
|
||||
#: glances/plugins/glances_alert.py:117
|
||||
#, python-brace-format
|
||||
msgid " (Min:{0:.1f} Mean:{1:.1f} Max:{2:.1f})"
|
||||
msgstr " (Min:{0:.1f} Mittel:{1:.1f} Max:{2:.1f})"
|
||||
|
||||
#: glances/plugins/glances_batpercent.py:107
|
||||
msgid "Battery (%)"
|
||||
msgstr "Batterie (%)"
|
||||
|
||||
#: glances/plugins/glances_cpu.py:123
|
||||
msgid "CPU"
|
||||
msgstr "CPU"
|
||||
|
||||
#: glances/plugins/glances_cpu.py:130
|
||||
msgid "nice:"
|
||||
msgstr "nice:"
|
||||
|
||||
#: glances/plugins/glances_cpu.py:138 glances/plugins/glances_percpu.py:168
|
||||
msgid "user:"
|
||||
msgstr "Benutzer:"
|
||||
|
||||
#: glances/plugins/glances_cpu.py:144
|
||||
msgid "irq:"
|
||||
msgstr "IRQ:"
|
||||
|
||||
#: glances/plugins/glances_cpu.py:152 glances/plugins/glances_percpu.py:178
|
||||
msgid "system:"
|
||||
msgstr "System:"
|
||||
|
||||
#: glances/plugins/glances_cpu.py:158
|
||||
msgid "iowait:"
|
||||
msgstr "IOWait:"
|
||||
|
||||
#: glances/plugins/glances_cpu.py:166 glances/plugins/glances_percpu.py:188
|
||||
msgid "idle:"
|
||||
msgstr "Inaktiv:"
|
||||
|
||||
#: glances/plugins/glances_cpu.py:172
|
||||
msgid "steal:"
|
||||
msgstr "Steal:"
|
||||
|
||||
#: glances/plugins/glances_diskio.py:134
|
||||
msgid "DISK I/O"
|
||||
msgstr "DISK I/O"
|
||||
|
||||
#: glances/plugins/glances_diskio.py:136
|
||||
msgid "R/s"
|
||||
msgstr "R/s"
|
||||
|
||||
#: glances/plugins/glances_diskio.py:138
|
||||
msgid "W/s"
|
||||
msgstr "W/s"
|
||||
|
||||
#: glances/plugins/glances_fs.py:142
|
||||
msgid "FILE SYS"
|
||||
msgstr "DATEISYSTEM"
|
||||
|
||||
#: glances/plugins/glances_fs.py:144
|
||||
msgid "Used"
|
||||
msgstr "Belegt"
|
||||
|
||||
#: glances/plugins/glances_fs.py:146
|
||||
msgid "Total"
|
||||
msgstr "Gesamt"
|
||||
|
||||
#: glances/plugins/glances_help.py:68
|
||||
#, python-brace-format
|
||||
msgid " with psutil {0}"
|
||||
msgstr " mit psutil {0}"
|
||||
|
||||
#: glances/plugins/glances_help.py:77
|
||||
msgid "a"
|
||||
msgstr "a"
|
||||
|
||||
#: glances/plugins/glances_help.py:77
|
||||
msgid "Sort processes automatically"
|
||||
msgstr "Prozesse automatisch sortieren"
|
||||
|
||||
#: glances/plugins/glances_help.py:79
|
||||
msgid "b"
|
||||
msgstr "b"
|
||||
|
||||
#: glances/plugins/glances_help.py:79
|
||||
msgid "Bytes or bits for network I/O"
|
||||
msgstr "Bytes oder Bits für Netzwerk I/O"
|
||||
|
||||
#: glances/plugins/glances_help.py:82
|
||||
msgid "c"
|
||||
msgstr "c"
|
||||
|
||||
#: glances/plugins/glances_help.py:82
|
||||
msgid "Sort processes by CPU%"
|
||||
msgstr "Prozesse nach CPU% sortieren"
|
||||
|
||||
#: glances/plugins/glances_help.py:84
|
||||
msgid "l"
|
||||
msgstr "l"
|
||||
|
||||
#: glances/plugins/glances_help.py:84
|
||||
msgid "Show/hide logs (alerts)"
|
||||
msgstr "Logs (Warnungen) zeigen/verstecken"
|
||||
|
||||
#: glances/plugins/glances_help.py:87
|
||||
msgid "m"
|
||||
msgstr "m"
|
||||
|
||||
#: glances/plugins/glances_help.py:87
|
||||
>>>>>>> release/v2.0
|
||||
msgid "Sort processes by MEM%"
|
||||
msgstr "Prozesse nach RAM% sortieren"
|
||||
|
||||
<<<<<<< HEAD
|
||||
#: glances/glances.py:3968
|
||||
msgid "p"
|
||||
msgstr "p"
|
||||
@ -799,45 +1172,332 @@ msgstr "Fehler: Die Server-Version ist nicht kompatibel"
|
||||
|
||||
#~ msgid "Can not grab data..."
|
||||
#~ msgstr "Kann nicht auf Daten zugreifen"
|
||||
=======
|
||||
#: glances/plugins/glances_help.py:89
|
||||
msgid "w"
|
||||
msgstr "w"
|
||||
|
||||
#~ msgid "Can not execute command"
|
||||
#~ msgstr "Kann Befehl nicht ausführen"
|
||||
#: glances/plugins/glances_help.py:89
|
||||
msgid "Delete warning alerts"
|
||||
msgstr "Warnungen entfernen"
|
||||
|
||||
#~ msgid "Connected to"
|
||||
#~ msgstr "Verbunden zu"
|
||||
#: glances/plugins/glances_help.py:92
|
||||
msgid "p"
|
||||
msgstr "p"
|
||||
|
||||
#~ msgid "Disconnected from"
|
||||
#~ msgstr "Getrennt von"
|
||||
#: glances/plugins/glances_help.py:92
|
||||
msgid "Sort processes by name"
|
||||
msgstr "Prozesse nach Name sortieren"
|
||||
|
||||
#~ msgid "Glances version"
|
||||
#~ msgstr "Glances Version"
|
||||
#: glances/plugins/glances_help.py:94
|
||||
msgid "x"
|
||||
msgstr "x"
|
||||
|
||||
#~ msgid ""
|
||||
#~ "\t-B @IP|host\tBind server to the given IPv4/IPv6 address or hostname"
|
||||
#~ msgstr ""
|
||||
#~ "\t-B @IP|host\tBinde Server an die gegebene IPv4/IPv6 Adresse oder "
|
||||
#~ "Hostnamen"
|
||||
#: glances/plugins/glances_help.py:94
|
||||
msgid "Delete warning and critical alerts"
|
||||
msgstr "(Kritische) Warnungen entfernen"
|
||||
|
||||
#~ msgid ""
|
||||
#~ "\t-c @IP|host\tConnect to a Glances server by IPv4/IPv6 address or "
|
||||
#~ "hostname"
|
||||
#~ msgstr ""
|
||||
#~ "\t-c @IP|host\tVerbinde zu einem Glances-Sserver mit IPv4/IPv6 Adresse "
|
||||
#~ "oder Hostnamen"
|
||||
#: glances/plugins/glances_help.py:97
|
||||
msgid "i"
|
||||
msgstr "i"
|
||||
|
||||
#~ msgid "\t-C file\t\tPath to the configuration file"
|
||||
#~ msgstr "\t-C file\t\tPfad zur Konfigurations-Datei"
|
||||
#: glances/plugins/glances_help.py:97
|
||||
msgid "Sort processes by I/O rate"
|
||||
msgstr "Prozesse nach I/O-Geschwindigkeit sortieren"
|
||||
|
||||
#~ msgid "\t-f file\t\tSet the HTML output folder or CSV file"
|
||||
#~ msgstr "\t-f file\t\tSetze Ordner für HTML-Ausgabe oder CSV-Datei"
|
||||
#: glances/plugins/glances_help.py:99
|
||||
msgid "1"
|
||||
msgstr "1"
|
||||
|
||||
#~ msgid "\t-o output\tDefine additional output (available: HTML or CSV)"
|
||||
#~ msgstr ""
|
||||
#~ "\t-o output\tDefiniere zusätzliche Ausgabe (verfügbar: HTML oder CSV)"
|
||||
#: glances/plugins/glances_help.py:99
|
||||
msgid "Global CPU or per-CPU stats"
|
||||
msgstr "Globale oder pro-CPU-Daten"
|
||||
|
||||
#~ msgid "\t-P password\tDefine a client/server password"
|
||||
#~ msgstr "\t-P password\tDefiniere ein Client/Server-Passwort"
|
||||
#: glances/plugins/glances_help.py:102
|
||||
msgid "d"
|
||||
msgstr "d"
|
||||
|
||||
#~ msgid "\t-t seconds\tSet refresh time in seconds (default: %d sec)"
|
||||
#~ msgstr ""
|
||||
#~ "\t-t seconds\tSetze Aktualisierungszeit in Sekunden (Standard: %d sek)"
|
||||
#: glances/plugins/glances_help.py:102
|
||||
msgid "Show/hide disk I/O stats"
|
||||
msgstr "I/O-Daten zeigen/verstecken"
|
||||
|
||||
#: glances/plugins/glances_help.py:104
|
||||
msgid "h"
|
||||
msgstr "h"
|
||||
|
||||
#: glances/plugins/glances_help.py:104
|
||||
msgid "Show/hide this help screen"
|
||||
msgstr "Diese Hilfe zeigen/verstecken"
|
||||
|
||||
#: glances/plugins/glances_help.py:107
|
||||
msgid "f"
|
||||
msgstr "f"
|
||||
|
||||
#: glances/plugins/glances_help.py:107
|
||||
msgid "Show/hide file system stats"
|
||||
msgstr "Zeige/Verstecke Dateisystem-Daten"
|
||||
|
||||
#: glances/plugins/glances_help.py:109
|
||||
msgid "t"
|
||||
msgstr "t"
|
||||
|
||||
#: glances/plugins/glances_help.py:109
|
||||
msgid "View network I/O as combination"
|
||||
msgstr "Netzwerk-I/O kombiniert zeigen"
|
||||
|
||||
#: glances/plugins/glances_help.py:112
|
||||
msgid "n"
|
||||
msgstr "n"
|
||||
|
||||
#: glances/plugins/glances_help.py:112
|
||||
msgid "Show/hide network stats"
|
||||
msgstr "Netzwerk-Daten zeigen/verstecken"
|
||||
|
||||
#: glances/plugins/glances_help.py:114
|
||||
msgid "u"
|
||||
msgstr "u"
|
||||
|
||||
#: glances/plugins/glances_help.py:114
|
||||
msgid "View cumulative network I/O"
|
||||
msgstr "kumulative Netzwerk-I/O zeigen"
|
||||
|
||||
#: glances/plugins/glances_help.py:117
|
||||
msgid "s"
|
||||
msgstr "s"
|
||||
|
||||
#: glances/plugins/glances_help.py:117
|
||||
msgid "Show/hide sensors stats"
|
||||
msgstr "Sensor-Daten zeigen/verstecken"
|
||||
|
||||
#: glances/plugins/glances_help.py:119
|
||||
msgid "z"
|
||||
msgstr "z"
|
||||
|
||||
#: glances/plugins/glances_help.py:119
|
||||
msgid "Enable/disable processes stats"
|
||||
msgstr "Prozess-Daten aktivieren/deaktivieren"
|
||||
|
||||
#: glances/plugins/glances_help.py:122
|
||||
msgid "q"
|
||||
msgstr "q"
|
||||
|
||||
#: glances/plugins/glances_help.py:122
|
||||
msgid "Quit (Esc and Ctrl-C also work)"
|
||||
msgstr "Beenden (auch Esc und Strg+C)"
|
||||
|
||||
#: glances/plugins/glances_load.py:123
|
||||
msgid "LOAD"
|
||||
msgstr "LAST"
|
||||
|
||||
#: glances/plugins/glances_load.py:127
|
||||
#, python-brace-format
|
||||
msgid "{0}-core"
|
||||
msgstr "{0}-Kern"
|
||||
|
||||
#: glances/plugins/glances_load.py:132
|
||||
msgid "1 min:"
|
||||
msgstr "1 Min:"
|
||||
|
||||
#: glances/plugins/glances_load.py:139
|
||||
msgid "5 min:"
|
||||
msgstr "5 Min:"
|
||||
|
||||
#: glances/plugins/glances_load.py:147
|
||||
msgid "15 min:"
|
||||
msgstr "15 Min:"
|
||||
|
||||
#: glances/plugins/glances_mem.py:148
|
||||
msgid "MEM"
|
||||
msgstr "RAM"
|
||||
|
||||
#: glances/plugins/glances_mem.py:155
|
||||
msgid "active:"
|
||||
msgstr "aktiv:"
|
||||
|
||||
#: glances/plugins/glances_mem.py:162 glances/plugins/glances_memswap.py:127
|
||||
msgid "total:"
|
||||
msgstr "gesamt:"
|
||||
|
||||
#: glances/plugins/glances_mem.py:168
|
||||
msgid "inactive:"
|
||||
msgstr "inaktiv:"
|
||||
|
||||
#: glances/plugins/glances_mem.py:175 glances/plugins/glances_memswap.py:134
|
||||
msgid "used:"
|
||||
msgstr "benutzt:"
|
||||
|
||||
#: glances/plugins/glances_mem.py:182
|
||||
msgid "buffers:"
|
||||
msgstr "Puffer:"
|
||||
|
||||
#: glances/plugins/glances_mem.py:189 glances/plugins/glances_memswap.py:142
|
||||
msgid "free:"
|
||||
msgstr "frei:"
|
||||
|
||||
#: glances/plugins/glances_mem.py:195
|
||||
msgid "cached:"
|
||||
msgstr "cached:"
|
||||
|
||||
#: glances/plugins/glances_memswap.py:119
|
||||
msgid "SWAP"
|
||||
msgstr "SWAP"
|
||||
|
||||
#: glances/plugins/glances_monitor.py:111
|
||||
msgid "RUNNING"
|
||||
msgstr "LAUFEND"
|
||||
|
||||
#: glances/plugins/glances_monitor.py:111
|
||||
msgid "NOT RUNNING"
|
||||
msgstr "NICHT LAUFEND"
|
||||
|
||||
#: glances/plugins/glances_network.py:183
|
||||
msgid "NETWORK"
|
||||
msgstr "NETZWERK"
|
||||
|
||||
#: glances/plugins/glances_network.py:189
|
||||
msgid "Rx+Tx"
|
||||
msgstr "Rx+Tx"
|
||||
|
||||
#: glances/plugins/glances_network.py:193
|
||||
msgid "Rx"
|
||||
msgstr "Rx"
|
||||
|
||||
#: glances/plugins/glances_network.py:195
|
||||
msgid "Tx"
|
||||
msgstr "Tx"
|
||||
|
||||
#: glances/plugins/glances_network.py:201
|
||||
msgid "Rx+Tx/s"
|
||||
msgstr "Rx+Tx/s"
|
||||
|
||||
#: glances/plugins/glances_network.py:204
|
||||
msgid "Rx/s"
|
||||
msgstr "Rx/s"
|
||||
|
||||
#: glances/plugins/glances_network.py:206
|
||||
msgid "Tx/s"
|
||||
msgstr "Tx/s"
|
||||
|
||||
#: glances/plugins/glances_now.py:52
|
||||
msgid "%Y-%m-%d %H:%M:%S"
|
||||
msgstr "%d.%m.%Y %H:%M:%S"
|
||||
|
||||
#: glances/plugins/glances_percpu.py:150
|
||||
msgid "PER CPU not available"
|
||||
msgstr "PRO-CPU nicht möglich"
|
||||
|
||||
#: glances/plugins/glances_percpu.py:156
|
||||
msgid "PER CPU"
|
||||
msgstr "PRO CPU"
|
||||
|
||||
#: glances/plugins/glances_processcount.py:87
|
||||
msgid "PROCESSES DISABLED (press 'z' to display)"
|
||||
msgstr "PROZESS DEAKTIVIERT (drücke 'z' zum anzeigen)"
|
||||
|
||||
#: glances/plugins/glances_processcount.py:96
|
||||
msgid "TASKS "
|
||||
msgstr "PROZESSE "
|
||||
|
||||
#: glances/plugins/glances_processcount.py:104
|
||||
#, python-brace-format
|
||||
msgid " ({0} thr),"
|
||||
msgstr " ({0} thr),"
|
||||
|
||||
#: glances/plugins/glances_processcount.py:109
|
||||
#, python-brace-format
|
||||
msgid " {0} run,"
|
||||
msgstr " {0} run,"
|
||||
|
||||
#: glances/plugins/glances_processcount.py:114
|
||||
#, python-brace-format
|
||||
msgid " {0} slp,"
|
||||
msgstr " {0} slp,"
|
||||
|
||||
#: glances/plugins/glances_processcount.py:117
|
||||
#, python-brace-format
|
||||
msgid " {0} oth "
|
||||
msgstr " {0} oth "
|
||||
|
||||
#: glances/plugins/glances_processcount.py:126
|
||||
msgid "sorted automatically"
|
||||
msgstr "automatisch sortiert"
|
||||
|
||||
#: glances/plugins/glances_processcount.py:128
|
||||
#, python-brace-format
|
||||
msgid " by {0}"
|
||||
msgstr " nach {0}"
|
||||
|
||||
#: glances/plugins/glances_processcount.py:131
|
||||
#, python-brace-format
|
||||
msgid "sorted by {0}"
|
||||
msgstr "sortiert nach {0}"
|
||||
|
||||
#: glances/plugins/glances_processlist.py:100
|
||||
msgid "CPU%"
|
||||
msgstr "CPU %"
|
||||
|
||||
#: glances/plugins/glances_processlist.py:102
|
||||
msgid "MEM%"
|
||||
msgstr "RAM%"
|
||||
|
||||
#: glances/plugins/glances_processlist.py:104
|
||||
msgid "VIRT"
|
||||
msgstr "VIRT"
|
||||
|
||||
#: glances/plugins/glances_processlist.py:106
|
||||
msgid "RES"
|
||||
msgstr "RES"
|
||||
|
||||
#: glances/plugins/glances_processlist.py:108
|
||||
msgid "PID"
|
||||
msgstr "PID"
|
||||
|
||||
#: glances/plugins/glances_processlist.py:110
|
||||
msgid "USER"
|
||||
msgstr "BENUTZER"
|
||||
>>>>>>> release/v2.0
|
||||
|
||||
#: glances/plugins/glances_processlist.py:112
|
||||
msgid "NI"
|
||||
msgstr "NI"
|
||||
|
||||
#: glances/plugins/glances_processlist.py:114
|
||||
msgid "S"
|
||||
msgstr "S"
|
||||
|
||||
#: glances/plugins/glances_processlist.py:116
|
||||
msgid "TIME+"
|
||||
msgstr "ZEIT+"
|
||||
|
||||
#: glances/plugins/glances_processlist.py:118
|
||||
msgid "IOR/s"
|
||||
msgstr "IOR/s"
|
||||
|
||||
#: glances/plugins/glances_processlist.py:120
|
||||
msgid "IOW/s"
|
||||
msgstr "IOW/s"
|
||||
|
||||
#: glances/plugins/glances_processlist.py:122
|
||||
msgid "Command"
|
||||
msgstr "Befehl"
|
||||
|
||||
#: glances/plugins/glances_sensors.py:121
|
||||
msgid "SENSORS"
|
||||
msgstr "SENSOREN"
|
||||
|
||||
#: glances/plugins/glances_sensors.py:124
|
||||
#: glances/plugins/glances_sensors.py:126
|
||||
msgid "°C"
|
||||
msgstr "°C"
|
||||
|
||||
#: glances/plugins/glances_system.py:111
|
||||
msgid "Connected to "
|
||||
msgstr "Verbunden mit "
|
||||
|
||||
#: glances/plugins/glances_system.py:114
|
||||
msgid "SNMP from "
|
||||
msgstr "SNMP von "
|
||||
|
||||
#: glances/plugins/glances_system.py:117
|
||||
msgid "Disconnected from "
|
||||
msgstr "Getrennt von "
|
||||
|
@ -1,905 +0,0 @@
|
||||
# Spanish translations for GLANCES package.
|
||||
# Copyright (C) 2012 THE PACKAGE'S COPYRIGHT HOLDER
|
||||
# This file is distributed under the same license as the GLANCES package.
|
||||
# Peter Fontaine <jeanbob@jeanbob.eu>, 2012.
|
||||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: GLANCES 1.3.5\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2013-12-23 01:08+0100\n"
|
||||
"PO-Revision-Date: 2012-01-12 19:07+0100\n"
|
||||
"Last-Translator: Sebastián Moreno <smoreno@inconcertcc.com>\n"
|
||||
"Language-Team: Spanish\n"
|
||||
"Language: \n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
|
||||
|
||||
#: glances/glances.py:398
|
||||
#, python-format
|
||||
msgid "Error decoding config file '%s': %s"
|
||||
msgstr ""
|
||||
|
||||
#: glances/glances.py:1107
|
||||
msgid "hddtemp error"
|
||||
msgstr ""
|
||||
|
||||
#: glances/glances.py:1939
|
||||
msgid "Error: Cannot init the curses library.\n"
|
||||
msgstr ""
|
||||
|
||||
#: glances/glances.py:2500
|
||||
msgid "{0} {1} with {2} {3} on {4}"
|
||||
msgstr ""
|
||||
|
||||
#: glances/glances.py:2505
|
||||
msgid "{0} {1} {2} on {3}"
|
||||
msgstr ""
|
||||
|
||||
#: glances/glances.py:2550
|
||||
msgid "PerCPU"
|
||||
msgstr ""
|
||||
|
||||
#: glances/glances.py:2556 glances/glances.py:2610 glances/glances.py:2906
|
||||
#: glances/glances.py:3067 glances/glances.py:3463
|
||||
msgid "Compute data..."
|
||||
msgstr ""
|
||||
|
||||
#: glances/glances.py:2560 glances/glances.py:2620
|
||||
msgid "user:"
|
||||
msgstr ""
|
||||
|
||||
#: glances/glances.py:2562 glances/glances.py:2629
|
||||
msgid "system:"
|
||||
msgstr ""
|
||||
|
||||
#: glances/glances.py:2565 glances/glances.py:2657
|
||||
msgid "iowait:"
|
||||
msgstr ""
|
||||
|
||||
#: glances/glances.py:2568 glances/glances.py:2636
|
||||
msgid "idle:"
|
||||
msgstr ""
|
||||
|
||||
#: glances/glances.py:2604
|
||||
msgid "CPU"
|
||||
msgstr ""
|
||||
|
||||
#: glances/glances.py:2648
|
||||
msgid "nice:"
|
||||
msgstr ""
|
||||
|
||||
#: glances/glances.py:2667
|
||||
msgid "irq:"
|
||||
msgstr ""
|
||||
|
||||
#: glances/glances.py:2689 glances/glances.py:3678
|
||||
msgid "Load"
|
||||
msgstr "Carga"
|
||||
|
||||
#: glances/glances.py:2693
|
||||
msgid "-core"
|
||||
msgstr ""
|
||||
|
||||
#: glances/glances.py:2697
|
||||
msgid "1 min:"
|
||||
msgstr "1 minuto:"
|
||||
|
||||
#: glances/glances.py:2704
|
||||
msgid "5 min:"
|
||||
msgstr ""
|
||||
|
||||
#: glances/glances.py:2714
|
||||
msgid "15 min:"
|
||||
msgstr ""
|
||||
|
||||
#: glances/glances.py:2746
|
||||
msgid "Mem"
|
||||
msgstr "Mem"
|
||||
|
||||
#: glances/glances.py:2756 glances/glances.py:2842
|
||||
msgid "total:"
|
||||
msgstr ""
|
||||
|
||||
#: glances/glances.py:2765 glances/glances.py:2852
|
||||
msgid "used:"
|
||||
msgstr ""
|
||||
|
||||
#: glances/glances.py:2773 glances/glances.py:2861
|
||||
msgid "free:"
|
||||
msgstr ""
|
||||
|
||||
#: glances/glances.py:2786
|
||||
msgid "active:"
|
||||
msgstr ""
|
||||
|
||||
#: glances/glances.py:2794
|
||||
msgid "inactive:"
|
||||
msgstr ""
|
||||
|
||||
#: glances/glances.py:2804
|
||||
msgid "buffers:"
|
||||
msgstr ""
|
||||
|
||||
#: glances/glances.py:2812
|
||||
msgid "cached:"
|
||||
msgstr ""
|
||||
|
||||
#: glances/glances.py:2830
|
||||
msgid "Swap"
|
||||
msgstr "Intercambio"
|
||||
|
||||
#: glances/glances.py:2878
|
||||
msgid "Network"
|
||||
msgstr ""
|
||||
|
||||
#: glances/glances.py:2901 glances/glances.py:3062
|
||||
msgid "Cannot grab data..."
|
||||
msgstr ""
|
||||
|
||||
#: glances/glances.py:2989
|
||||
msgid "Sensors"
|
||||
msgstr ""
|
||||
|
||||
#: glances/glances.py:2992 glances/glances.py:3025
|
||||
msgid "°C"
|
||||
msgstr ""
|
||||
|
||||
#: glances/glances.py:3022
|
||||
msgid "HDD Temp"
|
||||
msgstr ""
|
||||
|
||||
#: glances/glances.py:3051
|
||||
msgid "Disk I/O"
|
||||
msgstr "Lectura/Escritura a disco"
|
||||
|
||||
#: glances/glances.py:3055
|
||||
msgid "In/s"
|
||||
msgstr ""
|
||||
|
||||
#: glances/glances.py:3057
|
||||
msgid "Out/s"
|
||||
msgstr ""
|
||||
|
||||
#: glances/glances.py:3103
|
||||
msgid "Mount"
|
||||
msgstr "Montaje"
|
||||
|
||||
#: glances/glances.py:3107
|
||||
msgid "Used"
|
||||
msgstr "Usado"
|
||||
|
||||
#: glances/glances.py:3109
|
||||
msgid "Total"
|
||||
msgstr "Total"
|
||||
|
||||
#: glances/glances.py:3151
|
||||
msgid "WARNING|CRITICAL logs"
|
||||
msgstr ""
|
||||
|
||||
#: glances/glances.py:3153
|
||||
msgid " (lasts "
|
||||
msgstr ""
|
||||
|
||||
#: glances/glances.py:3154
|
||||
msgid " entries)"
|
||||
msgstr ""
|
||||
|
||||
#: glances/glances.py:3156
|
||||
msgid " (one entry)"
|
||||
msgstr ""
|
||||
|
||||
#: glances/glances.py:3255
|
||||
msgid "Processes (disabled)"
|
||||
msgstr ""
|
||||
|
||||
#: glances/glances.py:3260
|
||||
msgid "Processes"
|
||||
msgstr ""
|
||||
|
||||
#: glances/glances.py:3271
|
||||
msgid "running"
|
||||
msgstr ""
|
||||
|
||||
#: glances/glances.py:3273
|
||||
msgid "sleeping"
|
||||
msgstr ""
|
||||
|
||||
#: glances/glances.py:3275
|
||||
msgid "other"
|
||||
msgstr ""
|
||||
|
||||
#: glances/glances.py:3281
|
||||
msgid "sorted automatically"
|
||||
msgstr ""
|
||||
|
||||
#: glances/glances.py:3283
|
||||
msgid "sorted by "
|
||||
msgstr ""
|
||||
|
||||
#: glances/glances.py:3307
|
||||
msgid "RUNNING"
|
||||
msgstr ""
|
||||
|
||||
#: glances/glances.py:3307
|
||||
msgid "NOT RUNNING"
|
||||
msgstr ""
|
||||
|
||||
#: glances/glances.py:3321
|
||||
msgid "Error: "
|
||||
msgstr ""
|
||||
|
||||
#: glances/glances.py:3323
|
||||
msgid "Cannot execute command"
|
||||
msgstr ""
|
||||
|
||||
#: glances/glances.py:3383
|
||||
msgid "VIRT"
|
||||
msgstr ""
|
||||
|
||||
#: glances/glances.py:3387
|
||||
msgid "RES"
|
||||
msgstr ""
|
||||
|
||||
#: glances/glances.py:3391
|
||||
msgid "CPU%"
|
||||
msgstr ""
|
||||
|
||||
#: glances/glances.py:3396
|
||||
msgid "MEM%"
|
||||
msgstr ""
|
||||
|
||||
#: glances/glances.py:3404
|
||||
msgid "PID"
|
||||
msgstr ""
|
||||
|
||||
#: glances/glances.py:3410
|
||||
msgid "USER"
|
||||
msgstr ""
|
||||
|
||||
#: glances/glances.py:3416
|
||||
msgid "NI"
|
||||
msgstr ""
|
||||
|
||||
#: glances/glances.py:3422
|
||||
msgid "S"
|
||||
msgstr ""
|
||||
|
||||
#: glances/glances.py:3428
|
||||
msgid "TIME+"
|
||||
msgstr ""
|
||||
|
||||
#: glances/glances.py:3434
|
||||
msgid "IOR/s"
|
||||
msgstr ""
|
||||
|
||||
#: glances/glances.py:3439
|
||||
msgid "IOW/s"
|
||||
msgstr ""
|
||||
|
||||
#: glances/glances.py:3457
|
||||
msgid "NAME"
|
||||
msgstr ""
|
||||
|
||||
#: glances/glances.py:3614
|
||||
msgid "Connected to "
|
||||
msgstr ""
|
||||
|
||||
#: glances/glances.py:3617
|
||||
msgid "Disconnected from "
|
||||
msgstr ""
|
||||
|
||||
#: glances/glances.py:3619
|
||||
msgid "Press 'h' for help"
|
||||
msgstr ""
|
||||
|
||||
#: glances/glances.py:3651
|
||||
msgid "Glances {0} with PsUtil {1}"
|
||||
msgstr ""
|
||||
|
||||
#: glances/glances.py:3657
|
||||
msgid "Glances {0}"
|
||||
msgstr ""
|
||||
|
||||
#: glances/glances.py:3664
|
||||
msgid "OK"
|
||||
msgstr ""
|
||||
|
||||
#: glances/glances.py:3667
|
||||
msgid "CAREFUL"
|
||||
msgstr ""
|
||||
|
||||
#: glances/glances.py:3670
|
||||
msgid "WARNING"
|
||||
msgstr ""
|
||||
|
||||
#: glances/glances.py:3673
|
||||
msgid "CRITICAL"
|
||||
msgstr "CRÍTICA "
|
||||
|
||||
#: glances/glances.py:3677
|
||||
msgid "CPU user %"
|
||||
msgstr ""
|
||||
|
||||
#: glances/glances.py:3677
|
||||
msgid "CPU system %"
|
||||
msgstr ""
|
||||
|
||||
#: glances/glances.py:3678
|
||||
msgid "CPU iowait %"
|
||||
msgstr ""
|
||||
|
||||
#: glances/glances.py:3679
|
||||
msgid "RAM memory %"
|
||||
msgstr ""
|
||||
|
||||
#: glances/glances.py:3679
|
||||
msgid "Swap memory %"
|
||||
msgstr ""
|
||||
|
||||
#: glances/glances.py:3680
|
||||
msgid "Temp °C"
|
||||
msgstr ""
|
||||
|
||||
#: glances/glances.py:3680
|
||||
msgid "HDD Temp °C"
|
||||
msgstr ""
|
||||
|
||||
#: glances/glances.py:3681
|
||||
msgid "Filesystem %"
|
||||
msgstr ""
|
||||
|
||||
#: glances/glances.py:3681
|
||||
msgid "CPU process %"
|
||||
msgstr ""
|
||||
|
||||
#: glances/glances.py:3682
|
||||
msgid "MEM process %"
|
||||
msgstr ""
|
||||
|
||||
#: glances/glances.py:3737
|
||||
msgid "a"
|
||||
msgstr ""
|
||||
|
||||
#: glances/glances.py:3737
|
||||
msgid "Sort processes automatically"
|
||||
msgstr ""
|
||||
|
||||
#: glances/glances.py:3738
|
||||
msgid "c"
|
||||
msgstr ""
|
||||
|
||||
#: glances/glances.py:3738
|
||||
msgid "Sort processes by CPU%"
|
||||
msgstr ""
|
||||
|
||||
#: glances/glances.py:3739
|
||||
msgid "m"
|
||||
msgstr ""
|
||||
|
||||
#: glances/glances.py:3739
|
||||
msgid "Sort processes by MEM%"
|
||||
msgstr ""
|
||||
|
||||
#: glances/glances.py:3740
|
||||
msgid "p"
|
||||
msgstr ""
|
||||
|
||||
#: glances/glances.py:3740
|
||||
msgid "Sort processes by name"
|
||||
msgstr ""
|
||||
|
||||
#: glances/glances.py:3741
|
||||
msgid "i"
|
||||
msgstr ""
|
||||
|
||||
#: glances/glances.py:3741
|
||||
msgid "Sort processes by I/O rate"
|
||||
msgstr ""
|
||||
|
||||
#: glances/glances.py:3742
|
||||
msgid "d"
|
||||
msgstr ""
|
||||
|
||||
#: glances/glances.py:3742
|
||||
msgid "Show/hide disk I/O stats"
|
||||
msgstr ""
|
||||
|
||||
#: glances/glances.py:3743
|
||||
msgid "f"
|
||||
msgstr ""
|
||||
|
||||
#: glances/glances.py:3743
|
||||
msgid "Show/hide file system stats"
|
||||
msgstr ""
|
||||
|
||||
#: glances/glances.py:3744
|
||||
msgid "n"
|
||||
msgstr ""
|
||||
|
||||
#: glances/glances.py:3744
|
||||
msgid "Show/hide network stats"
|
||||
msgstr ""
|
||||
|
||||
#: glances/glances.py:3745
|
||||
msgid "s"
|
||||
msgstr ""
|
||||
|
||||
#: glances/glances.py:3745
|
||||
msgid "Show/hide sensors stats"
|
||||
msgstr ""
|
||||
|
||||
#: glances/glances.py:3746
|
||||
msgid "y"
|
||||
msgstr ""
|
||||
|
||||
#: glances/glances.py:3746
|
||||
msgid "Show/hide hddtemp stats"
|
||||
msgstr ""
|
||||
|
||||
#: glances/glances.py:3758
|
||||
msgid "l"
|
||||
msgstr ""
|
||||
|
||||
#: glances/glances.py:3758
|
||||
msgid "Show/hide logs"
|
||||
msgstr ""
|
||||
|
||||
#: glances/glances.py:3759
|
||||
msgid "b"
|
||||
msgstr ""
|
||||
|
||||
#: glances/glances.py:3759
|
||||
msgid "Bytes or bits for network I/O"
|
||||
msgstr ""
|
||||
|
||||
#: glances/glances.py:3760
|
||||
msgid "w"
|
||||
msgstr ""
|
||||
|
||||
#: glances/glances.py:3760
|
||||
msgid "Delete warning logs"
|
||||
msgstr ""
|
||||
|
||||
#: glances/glances.py:3761
|
||||
msgid "x"
|
||||
msgstr ""
|
||||
|
||||
#: glances/glances.py:3761
|
||||
msgid "Delete warning and critical logs"
|
||||
msgstr ""
|
||||
|
||||
#: glances/glances.py:3762
|
||||
msgid "1"
|
||||
msgstr ""
|
||||
|
||||
#: glances/glances.py:3762
|
||||
msgid "Global CPU or per-CPU stats"
|
||||
msgstr ""
|
||||
|
||||
#: glances/glances.py:3763
|
||||
msgid "h"
|
||||
msgstr ""
|
||||
|
||||
#: glances/glances.py:3763
|
||||
msgid "Show/hide this help screen"
|
||||
msgstr ""
|
||||
|
||||
#: glances/glances.py:3764
|
||||
msgid "t"
|
||||
msgstr ""
|
||||
|
||||
#: glances/glances.py:3764
|
||||
msgid "View network I/O as combination"
|
||||
msgstr ""
|
||||
|
||||
#: glances/glances.py:3765
|
||||
msgid "u"
|
||||
msgstr ""
|
||||
|
||||
#: glances/glances.py:3765
|
||||
msgid "View cumulative network I/O"
|
||||
msgstr ""
|
||||
|
||||
#: glances/glances.py:3766
|
||||
msgid "q"
|
||||
msgstr ""
|
||||
|
||||
#: glances/glances.py:3766
|
||||
msgid "Quit (Esc and Ctrl-C also work)"
|
||||
msgstr ""
|
||||
|
||||
#: glances/glances.py:3800 glances/glances.py:4169
|
||||
msgid "%Y-%m-%d %H:%M:%S"
|
||||
msgstr "%d.%m.%Y %H:%M:%S"
|
||||
|
||||
#: glances/glances.py:4053
|
||||
#, python-format
|
||||
msgid "Couldn't open socket: %s"
|
||||
msgstr ""
|
||||
|
||||
#: glances/glances.py:4234
|
||||
msgid "Error: creating client socket"
|
||||
msgstr ""
|
||||
|
||||
#: glances/glances.py:4243
|
||||
msgid "Error: Connection to server failed. Bad password."
|
||||
msgstr ""
|
||||
|
||||
#: glances/glances.py:4246
|
||||
msgid "Error: Connection to server failed. Unknown error."
|
||||
msgstr ""
|
||||
|
||||
#: glances/glances.py:4279
|
||||
msgid "Glances version "
|
||||
msgstr "Versión de Glances"
|
||||
|
||||
#: glances/glances.py:4279
|
||||
msgid " with PsUtil "
|
||||
msgstr ""
|
||||
|
||||
#: glances/glances.py:4284
|
||||
msgid "Usage: glances [options]"
|
||||
msgstr ""
|
||||
|
||||
#: glances/glances.py:4285
|
||||
msgid ""
|
||||
"\n"
|
||||
"Options:"
|
||||
msgstr ""
|
||||
|
||||
#: glances/glances.py:4286
|
||||
msgid "\t-b\t\tDisplay network rate in Byte per second"
|
||||
msgstr ""
|
||||
|
||||
#: glances/glances.py:4287
|
||||
msgid "\t-B @IP|HOST\tBind server to the given IPv4/IPv6 address or hostname"
|
||||
msgstr ""
|
||||
|
||||
#: glances/glances.py:4288
|
||||
msgid ""
|
||||
"\t-c @IP|HOST\tConnect to a Glances server by IPv4/IPv6 address or hostname"
|
||||
msgstr ""
|
||||
|
||||
#: glances/glances.py:4289
|
||||
msgid "\t-C FILE\t\tPath to the configuration file"
|
||||
msgstr ""
|
||||
|
||||
#: glances/glances.py:4290
|
||||
msgid "\t-d\t\tDisable disk I/O module"
|
||||
msgstr ""
|
||||
|
||||
#: glances/glances.py:4291
|
||||
msgid "\t-e\t\tEnable sensors module"
|
||||
msgstr ""
|
||||
|
||||
#: glances/glances.py:4292
|
||||
msgid "\t-f FILE\t\tSet the HTML output folder or CSV file"
|
||||
msgstr ""
|
||||
|
||||
#: glances/glances.py:4293
|
||||
msgid "\t-h\t\tDisplay the help and exit"
|
||||
msgstr ""
|
||||
|
||||
#: glances/glances.py:4294
|
||||
msgid "\t-m\t\tDisable mount module"
|
||||
msgstr ""
|
||||
|
||||
#: glances/glances.py:4295
|
||||
msgid "\t-n\t\tDisable network module"
|
||||
msgstr ""
|
||||
|
||||
#: glances/glances.py:4296
|
||||
msgid "\t-o OUTPUT\tDefine additional output (available: HTML or CSV)"
|
||||
msgstr ""
|
||||
|
||||
#: glances/glances.py:4297
|
||||
#, python-format
|
||||
msgid "\t-p PORT\t\tDefine the client/server TCP port (default: %d)"
|
||||
msgstr ""
|
||||
|
||||
#: glances/glances.py:4299
|
||||
msgid "\t-P PASSWORD\tDefine a client/server password"
|
||||
msgstr ""
|
||||
|
||||
#: glances/glances.py:4300
|
||||
msgid "\t--password\tDefine a client/server password from the prompt"
|
||||
msgstr ""
|
||||
|
||||
#: glances/glances.py:4301
|
||||
msgid "\t-r\t\tDisable process list"
|
||||
msgstr ""
|
||||
|
||||
#: glances/glances.py:4302
|
||||
msgid "\t-s\t\tRun Glances in server mode"
|
||||
msgstr ""
|
||||
|
||||
#: glances/glances.py:4303
|
||||
#, python-format
|
||||
msgid "\t-t SECONDS\tSet refresh time in seconds (default: %d sec)"
|
||||
msgstr ""
|
||||
|
||||
#: glances/glances.py:4305
|
||||
msgid "\t-v\t\tDisplay the version and exit"
|
||||
msgstr ""
|
||||
|
||||
#: glances/glances.py:4306
|
||||
msgid "\t-y\t\tEnable hddtemp module"
|
||||
msgstr ""
|
||||
|
||||
#: glances/glances.py:4307
|
||||
msgid "\t-z\t\tDo not use the bold color attribute"
|
||||
msgstr ""
|
||||
|
||||
#: glances/glances.py:4308
|
||||
msgid "\t-1\t\tStart Glances in per CPU mode"
|
||||
msgstr ""
|
||||
|
||||
#: glances/glances.py:4343
|
||||
msgid "Password: "
|
||||
msgstr ""
|
||||
|
||||
#: glances/glances.py:4345
|
||||
msgid "Password (confirm): "
|
||||
msgstr ""
|
||||
|
||||
#: glances/glances.py:4352
|
||||
msgid "[Warning] Passwords did not match, please try again...\n"
|
||||
msgstr ""
|
||||
|
||||
#: glances/glances.py:4434
|
||||
msgid "Error: -P flag need an argument (password)"
|
||||
msgstr ""
|
||||
|
||||
#: glances/glances.py:4441
|
||||
msgid "Error: -B flag need an argument (bind IP address)"
|
||||
msgstr ""
|
||||
|
||||
#: glances/glances.py:4449
|
||||
msgid "Error: -c flag need an argument (server IP address/name)"
|
||||
msgstr ""
|
||||
|
||||
#: glances/glances.py:4465
|
||||
#, python-format
|
||||
msgid "Error: Unknown output %s"
|
||||
msgstr ""
|
||||
|
||||
#: glances/glances.py:4471
|
||||
msgid "Error: PySensors library not found"
|
||||
msgstr ""
|
||||
|
||||
#: glances/glances.py:4476
|
||||
msgid "Error: Sensors module is only available on Linux"
|
||||
msgstr ""
|
||||
|
||||
#: glances/glances.py:4486
|
||||
msgid "Error: Refresh time should be a positive integer"
|
||||
msgstr ""
|
||||
|
||||
#: glances/glances.py:4512
|
||||
msgid "Error: Cannot use both -s and -c flag"
|
||||
msgstr ""
|
||||
|
||||
#: glances/glances.py:4515
|
||||
msgid "Error: Cannot use both -s and -o flag"
|
||||
msgstr ""
|
||||
|
||||
#: glances/glances.py:4518
|
||||
msgid "Define the password for the Glances server"
|
||||
msgstr ""
|
||||
|
||||
#: glances/glances.py:4522
|
||||
msgid "Error: Cannot use both -c and -o flag"
|
||||
msgstr ""
|
||||
|
||||
#: glances/glances.py:4525
|
||||
msgid "Error: Cannot use both -c and -C flag"
|
||||
msgstr ""
|
||||
|
||||
#: glances/glances.py:4526
|
||||
msgid " Limits are set based on the server ones"
|
||||
msgstr ""
|
||||
|
||||
#: glances/glances.py:4529
|
||||
msgid "Enter the Glances server password"
|
||||
msgstr ""
|
||||
|
||||
#: glances/glances.py:4533
|
||||
msgid "Error: Need Jinja2 library to export into HTML"
|
||||
msgstr ""
|
||||
|
||||
#: glances/glances.py:4534
|
||||
msgid "Try to install the python-jinja2 package"
|
||||
msgstr ""
|
||||
|
||||
#: glances/glances.py:4539
|
||||
msgid ""
|
||||
"Error: HTML export (-o html) need output folder definition (-f <folder>)"
|
||||
msgstr ""
|
||||
|
||||
#: glances/glances.py:4545
|
||||
msgid "Error: Need CSV library to export into CSV"
|
||||
msgstr ""
|
||||
|
||||
#: glances/glances.py:4550
|
||||
msgid "Error: CSV export (-o csv) need output file definition (-f <file>)"
|
||||
msgstr ""
|
||||
|
||||
#: glances/glances.py:4577
|
||||
msgid "Glances server is running on"
|
||||
msgstr ""
|
||||
|
||||
#: glances/glances.py:4599
|
||||
msgid "Error: The server version is not compatible"
|
||||
msgstr ""
|
||||
|
||||
#~ msgid " OK "
|
||||
#~ msgstr " BUENO "
|
||||
|
||||
#~ msgid "CAREFUL "
|
||||
#~ msgstr " CUIDADO "
|
||||
|
||||
#~ msgid "WARNING "
|
||||
#~ msgstr " ATENCIÓN "
|
||||
|
||||
#~ msgid "User:"
|
||||
#~ msgstr "Usuario:"
|
||||
|
||||
#~ msgid "Kernel:"
|
||||
#~ msgstr "Núcleo:"
|
||||
|
||||
#~ msgid "-Core"
|
||||
#~ msgstr "Núcleo"
|
||||
|
||||
#~ msgid "Total:"
|
||||
#~ msgstr "Total:"
|
||||
|
||||
#~ msgid "Used:"
|
||||
#~ msgstr "Usado:"
|
||||
|
||||
#~ msgid "Free:"
|
||||
#~ msgstr "Libre:"
|
||||
|
||||
#~ msgid "Textmode GUI initialization failed, Glances cannot start."
|
||||
#~ msgstr ""
|
||||
#~ "Imposible inizializar la interfaz gráfica de usuario en modo texto. "
|
||||
#~ "Glances no se puede iniciar."
|
||||
|
||||
#~ msgid "Error: Can not init the libstatgrab library.\n"
|
||||
#~ msgstr "Error: No se puede iniciar la biblioteca libstatgrab.\n"
|
||||
|
||||
#~ msgid "Error: Can not init the curses library.\n"
|
||||
#~ msgstr "Error: No se puede iniciar la biblioteca curses.\n"
|
||||
|
||||
#~ msgid "Glances help (press 'h' to hide)"
|
||||
#~ msgstr "Ayuda de Glances (presiona 'h' para ocultar)"
|
||||
|
||||
#~ msgid "'h'\tto display|hide this help message"
|
||||
#~ msgstr "'h'\tpara mostrar/ocultar la ayuda"
|
||||
|
||||
#~ msgid "'a'\tto sort processes automatically"
|
||||
#~ msgstr "'a'\tpara ordenar los procesos automáticamente"
|
||||
|
||||
#~ msgid "'c'\tto sort processes by CPU consumption"
|
||||
#~ msgstr "'c'\tpara ordenar los procesos por consumo del CPU"
|
||||
|
||||
#~ msgid "'d'\tto disable|enable the disk IO stats"
|
||||
#~ msgstr ""
|
||||
#~ "'d'\tpara (des)activar las estadisticas de lectura/escritura a disco"
|
||||
|
||||
#~ msgid "'f'\tto disable|enable the file system stats"
|
||||
#~ msgstr "'f'\tpara (des)activar estadisticas del sistema de archivos"
|
||||
|
||||
#~ msgid "'m'\tto sort processes by process size"
|
||||
#~ msgstr "'m'\tpara ordenar los procesos para tamaño de proceso "
|
||||
|
||||
#~ msgid "'n'\tto disable|enable the network interfaces stats"
|
||||
#~ msgstr "'n'\tpara (des)activar el estado de las interfaces de red."
|
||||
|
||||
#~ msgid "'q'\tto exit Glances"
|
||||
#~ msgstr "'q'\tpara salir Glances"
|
||||
|
||||
#~ msgid "Glances v"
|
||||
#~ msgstr "Glances v"
|
||||
|
||||
#~ msgid " running on "
|
||||
#~ msgstr " que se ejecutan en "
|
||||
|
||||
#~ msgid "Cpu"
|
||||
#~ msgstr "Cpu"
|
||||
|
||||
#~ msgid "Idle:"
|
||||
#~ msgstr "Ocioso:"
|
||||
|
||||
#~ msgid "5 mins:"
|
||||
#~ msgstr "5 minutos:"
|
||||
|
||||
#~ msgid "15 mins:"
|
||||
#~ msgstr "15 minutos:"
|
||||
|
||||
#~ msgid "Mem MB"
|
||||
#~ msgstr "Mem Mb"
|
||||
|
||||
#~ msgid "Real"
|
||||
#~ msgstr "Real"
|
||||
|
||||
#~ msgid "Net rate"
|
||||
#~ msgstr "Red ratio"
|
||||
|
||||
#~ msgid "In/ps"
|
||||
#~ msgstr "Ent/ps"
|
||||
|
||||
#~ msgid "Out/ps"
|
||||
#~ msgstr "Sal/ps"
|
||||
|
||||
#~ msgid "Process"
|
||||
#~ msgstr "Proceso"
|
||||
|
||||
#~ msgid "Running"
|
||||
#~ msgstr "Funcionando"
|
||||
|
||||
#~ msgid "Sleeping"
|
||||
#~ msgstr "Durmiendo"
|
||||
|
||||
#~ msgid "Other"
|
||||
#~ msgstr "Otro"
|
||||
|
||||
#~ msgid "Number:"
|
||||
#~ msgstr "Número:"
|
||||
|
||||
#~ msgid "Size MB"
|
||||
#~ msgstr "Tamaño en Mb"
|
||||
|
||||
#~ msgid "Res MB"
|
||||
#~ msgstr "Res Mb"
|
||||
|
||||
#~ msgid "Name"
|
||||
#~ msgstr "Designación"
|
||||
|
||||
#~ msgid "Usage: glances.py [-t|--time sec] [-h|--help] [-v|--version]"
|
||||
#~ msgstr "Utilización: glances.py [-t|--time sec] [-h|--help] [-v|--version]"
|
||||
|
||||
#~ msgid "\t-h:\tDisplay the syntax and exit"
|
||||
#~ msgstr "\t-h:\tMostrar la sintaxis y salir"
|
||||
|
||||
#~ msgid "\t-t sec:\tSet the refresh time in second default is 1"
|
||||
#~ msgstr "\t-t sec:\tEstablecer el tiempo de actualización en segundos"
|
||||
|
||||
#~ msgid "\t-v:\tDisplay the version and exit"
|
||||
#~ msgstr "\t-v:\tMostrar la versión y salir"
|
||||
|
||||
#~ msgid "When Glances is running, you can press:"
|
||||
#~ msgstr "Cuando Glances se esté ejecutando, puede pulsar:"
|
||||
|
||||
#~ msgid ""
|
||||
#~ "'a' to set the automatic mode. The processes are sorted automatically"
|
||||
#~ msgstr ""
|
||||
#~ "'a' para establecer el modo automático. Los procesos se ordenan "
|
||||
#~ "automáticamente"
|
||||
|
||||
#~ msgid "'c' to sort the processes list by CPU consumption"
|
||||
#~ msgstr "'c' para ordenar la lista de procesos por el consumo de CPU"
|
||||
|
||||
#~ msgid "'d' to disable or enable the disk IO stats"
|
||||
#~ msgstr ""
|
||||
#~ "'d' para (des)activar las estadísticas del Lectura/Escritura a disco"
|
||||
|
||||
#~ msgid "'f' to disable or enable the file system stats"
|
||||
#~ msgstr "'f' para (des)activar las estadísticas del sistemas de archivos"
|
||||
|
||||
#~ msgid "'h' to hide or show the help message"
|
||||
#~ msgstr "'h' para ocultar o mostrar el mensaje de ayuda"
|
||||
|
||||
#~ msgid "'m' to sort the processes list by process size"
|
||||
#~ msgstr "'m' para ordenar la lista de procesos por tamaño de proceso"
|
||||
|
||||
#~ msgid "'n' to disable or enable the network interfaces stats"
|
||||
#~ msgstr "'n' para (des)activar las estadísticas del interfaces de red"
|
||||
|
||||
#~ msgid "'q' to exit"
|
||||
#~ msgstr "'q' para salir"
|
||||
|
||||
#~ msgid "Error: Refresh time should be a positive non-null integer"
|
||||
#~ msgstr "Error: tiempo de actualización debe ser un entero positivo no nulo"
|