Merge v2.0 release branch

This commit is contained in:
Nicolargo 2014-06-14 09:44:02 +02:00
commit cf480a9b41
112 changed files with 9512 additions and 10934 deletions

3
.gitignore vendored
View File

@ -40,3 +40,6 @@ local.properties
# Lang
glances.pot
# Sphinx
_build

View File

@ -2,7 +2,6 @@ language: python
python:
- "2.6"
- "2.7"
- "3.2"
- "3.3"
- "3.4"
install:

View File

@ -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
View File

@ -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
=============

View File

@ -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
View File

@ -1 +0,0 @@
See open issues here: https://github.com/nicolargo/glances/issues?milestone=&page=1&state=open

View File

@ -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

View File

@ -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.*

View File

@ -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 &lt;<a class="reference external" href="mailto:nicolas&#64;nicolargo.com">nicolas&#64;nicolargo.com</a>&gt;</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 (&gt;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 &#64;server</span>
</pre>
<p>where <tt class="docutils literal">&#64;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 &#64;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://&#64;server:61208
</pre>
<p>where <tt class="docutils literal">&#64;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>&nbsp;</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>&nbsp;</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>&nbsp;</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>&nbsp;</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>&nbsp;</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>&nbsp;</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>&nbsp;</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>&nbsp;</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>&nbsp;</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>&nbsp;</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>&nbsp;</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>&nbsp;</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>&nbsp;</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>&nbsp;</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>&nbsp;</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>&nbsp;</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\&lt;User&gt;\Application Data</span>
<pre class="literal-block">
C:\Documents and Settings\&lt;User&gt;\Application Data
</pre>
<p>Since Windows Vista and newer versions:</p>
<pre class="code console literal-block">
<span class="generic output">C:\Users\&lt;User&gt;\AppData\Roaming</span>
<pre class="literal-block">
C:\Users\&lt;User&gt;\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">&quot;WARNING&quot;</tt></div>
<div class="line"><tt class="docutils literal">RED</tt> stat counter is <tt class="docutils literal">&quot;CRITICAL&quot;</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">&lt;50%</tt>, then status is set to <tt class="docutils literal">&quot;OK&quot;</tt></div>
<div class="line">If user|system|nice CPU is <tt class="docutils literal">&gt;50%</tt>, then status is set to <tt class="docutils literal">&quot;CAREFUL&quot;</tt></div>
<div class="line">If user|system|nice CPU is <tt class="docutils literal">&gt;70%</tt>, then status is set to <tt class="docutils literal">&quot;WARNING&quot;</tt></div>
<div class="line">If user|system|nice CPU is <tt class="docutils literal">&gt;90%</tt>, then status is set to <tt class="docutils literal">&quot;CRITICAL&quot;</tt></div>
<div class="line">If user|system CPU is <tt class="docutils literal">&lt;50%</tt>, then status is set to <tt class="docutils literal">&quot;OK&quot;</tt></div>
<div class="line">If user|system CPU is <tt class="docutils literal">&gt;50%</tt>, then status is set to <tt class="docutils literal">&quot;CAREFUL&quot;</tt></div>
<div class="line">If user|system CPU is <tt class="docutils literal">&gt;70%</tt>, then status is set to <tt class="docutils literal">&quot;WARNING&quot;</tt></div>
<div class="line">If user|system CPU is <tt class="docutils literal">&gt;90%</tt>, then status is set to <tt class="docutils literal">&quot;CRITICAL&quot;</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>
&quot;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.&quot;</blockquote>
over 1, 5, and 15 minutes time periods.&quot;</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">&lt;0.7*core</tt>, then status is set to <tt class="docutils literal">&quot;OK&quot;</tt></div>
<div class="line">If average load is <tt class="docutils literal">&gt;0.7*core</tt>, then status is set to <tt class="docutils literal">&quot;CAREFUL&quot;</tt></div>
<div class="line">If average load is <tt class="docutils literal">&gt;1*core</tt>, then status is set to <tt class="docutils literal">&quot;WARNING&quot;</tt></div>
<div class="line">If average load is <tt class="docutils literal">&gt;5*core</tt>, then status is set to <tt class="docutils literal">&quot;CRITICAL&quot;</tt></div>
<div class="line">If load average is <tt class="docutils literal">&lt;0.7*core</tt>, then status is set to <tt class="docutils literal">&quot;OK&quot;</tt></div>
<div class="line">If load average is <tt class="docutils literal">&gt;0.7*core</tt>, then status is set to <tt class="docutils literal">&quot;CAREFUL&quot;</tt></div>
<div class="line">If load average is <tt class="docutils literal">&gt;1*core</tt>, then status is set to <tt class="docutils literal">&quot;WARNING&quot;</tt></div>
<div class="line">If load average is <tt class="docutils literal">&gt;5*core</tt>, then status is set to <tt class="docutils literal">&quot;CRITICAL&quot;</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">&lt;50%</tt>, then status is set to <tt class="docutils literal">&quot;OK&quot;</tt></div>
<div class="line">If memory is <tt class="docutils literal">&gt;50%</tt>, then status is set to <tt class="docutils literal">&quot;CAREFUL&quot;</tt></div>
<div class="line">If memory is <tt class="docutils literal">&gt;70%</tt>, then status is set to <tt class="docutils literal">&quot;WARNING&quot;</tt></div>
<div class="line">If memory is <tt class="docutils literal">&gt;90%</tt>, then status is set to <tt class="docutils literal">&quot;CRITICAL&quot;</tt></div>
<div class="line">If used memory|swap is <tt class="docutils literal">&lt;50%</tt>, then status is set to <tt class="docutils literal">&quot;OK&quot;</tt></div>
<div class="line">If used memory|swap is <tt class="docutils literal">&gt;50%</tt>, then status is set to <tt class="docutils literal">&quot;CAREFUL&quot;</tt></div>
<div class="line">If used memory|swap is <tt class="docutils literal">&gt;70%</tt>, then status is set to <tt class="docutils literal">&quot;WARNING&quot;</tt></div>
<div class="line">If used memory|swap is <tt class="docutils literal">&gt;90%</tt>, then status is set to <tt class="docutils literal">&quot;CRITICAL&quot;</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">&lt;50%</tt>, then status is set to <tt class="docutils literal">&quot;OK&quot;</tt></div>
<div class="line">If bit rate is <tt class="docutils literal">&gt;50%</tt>, then status is set to <tt class="docutils literal">&quot;CAREFUL&quot;</tt></div>
<div class="line">If bit rate is <tt class="docutils literal">&gt;70%</tt>, then status is set to <tt class="docutils literal">&quot;WARNING&quot;</tt></div>
<div class="line">If bit rate is <tt class="docutils literal">&gt;90%</tt>, then status is set to <tt class="docutils literal">&quot;CRITICAL&quot;</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">&lt;50%</tt>, then status is set to <tt class="docutils literal">&quot;OK&quot;</tt></div>
<div class="line">If disk used is <tt class="docutils literal">&gt;50%</tt>, then status is set to <tt class="docutils literal">&quot;CAREFUL&quot;</tt></div>
<div class="line">If disk used is <tt class="docutils literal">&gt;70%</tt>, then status is set to <tt class="docutils literal">&quot;WARNING&quot;</tt></div>
<div class="line">If disk used is <tt class="docutils literal">&gt;90%</tt>, then status is set to <tt class="docutils literal">&quot;CRITICAL&quot;</tt></div>
<div class="line">If used disk is <tt class="docutils literal">&lt;50%</tt>, then status is set to <tt class="docutils literal">&quot;OK&quot;</tt></div>
<div class="line">If used disk is <tt class="docutils literal">&gt;50%</tt>, then status is set to <tt class="docutils literal">&quot;CAREFUL&quot;</tt></div>
<div class="line">If used disk is <tt class="docutils literal">&gt;70%</tt>, then status is set to <tt class="docutils literal">&quot;WARNING&quot;</tt></div>
<div class="line">If used disk is <tt class="docutils literal">&gt;90%</tt>, then status is set to <tt class="docutils literal">&quot;CRITICAL&quot;</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 &lt; count.</li>
<li><tt class="docutils literal">countmax</tt> (optional): maximum number of processes. A warning will be displayed if number of processes &gt; 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 &lt; count.</li>
<li><tt class="docutils literal">countmax</tt> (optional): maximum number of processes. A warning will
be displayed if number of processes &gt; 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">&quot;CRITICAL&quot;</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 &amp; 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>&lt;&lt;&lt;&lt;&lt;&lt;&lt; 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>.
&gt;&gt;&gt;&gt;&gt;&gt;&gt; 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>

View File

@ -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

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.8 KiB

BIN
docs/images/connected.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.6 KiB

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.0 KiB

After

Width:  |  Height:  |  Size: 7.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.2 KiB

After

Width:  |  Height:  |  Size: 7.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.5 KiB

After

Width:  |  Height:  |  Size: 9.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 21 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.1 KiB

After

Width:  |  Height:  |  Size: 7.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.6 KiB

After

Width:  |  Height:  |  Size: 6.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 12 KiB

After

Width:  |  Height:  |  Size: 24 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.9 KiB

After

Width:  |  Height:  |  Size: 23 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.1 KiB

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.0 KiB

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.4 KiB

After

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 90 KiB

After

Width:  |  Height:  |  Size: 222 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 46 KiB

After

Width:  |  Height:  |  Size: 148 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 198 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 242 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 93 KiB

After

Width:  |  Height:  |  Size: 389 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 113 KiB

After

Width:  |  Height:  |  Size: 208 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.4 KiB

After

Width:  |  Height:  |  Size: 16 KiB

View File

@ -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`

View File

@ -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
View 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
...

View File

@ -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
View 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()

View 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()

View 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

View 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()

View 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()

View 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

View 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")

View 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

View 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

View 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()

View 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)

View 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()

View 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

View 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

View 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()

View File

@ -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;
}

View File

@ -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>

View File

@ -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 &darr;</th>
<th scope="col" class="bgnet fgnet">Net TX &uarr;</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 &darr;</th>
<th scope="col" class="bgdiskio fgdiskio">Disk Read &uarr;</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 %}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 20 KiB

File diff suppressed because it is too large Load Diff

View File

View File

@ -0,0 +1,4 @@
</body>
<footer>
</footer>
</html>

View 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>

View File

@ -0,0 +1 @@
<div id="newline"></div>

View 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">&nbsp;%s</span>' % \
(self.__style_list[m['decoration']],
m['msg'].split(' ', 1)[0].replace(' ', '&nbsp;')[: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(' ', '&nbsp;'))
else:
# Display stat
tpl += '<span class="cell" id="%s">%s</span>' % \
(self.__style_list[m['decoration']], m['msg'].replace(' ', '&nbsp;'))
tpl += '</div>'
tpl += '</div>'
tpl += """ \
</article>
%#End Template for Bottle
"""
return template(tpl)

View 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

View 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()

View 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

View 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;}

View 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; }
}

File diff suppressed because one or more lines are too long

View File

View 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

View 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)

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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 doesnt 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

View 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

View 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

View 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

View 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

View 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

View 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)

View 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

View 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

View 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

View 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()

View 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

View 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

View File

@ -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()

View File

@ -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"

View File

@ -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 "

Binary file not shown.

View File

@ -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"

Some files were not shown because too many files have changed in this diff Show More