mirror of
https://github.com/nicolargo/glances.git
synced 2026-03-14 12:00:14 -04:00
Merge branch 'develop' of https://github.com/nicolargo/glances into feature/gpu-nvidia
This commit is contained in:
30
.coveragerc
Normal file
30
.coveragerc
Normal file
@@ -0,0 +1,30 @@
|
||||
[report]
|
||||
|
||||
include =
|
||||
*glances*
|
||||
|
||||
omit =
|
||||
setup.py
|
||||
glances/outputs/*
|
||||
glances/exports/*
|
||||
glances/compat.py
|
||||
glances/autodiscover.py
|
||||
glances/client_browser.py
|
||||
glances/config.py
|
||||
glances/history.py
|
||||
glances/monitored_list.py
|
||||
glances/outdated.py
|
||||
glances/password*.py
|
||||
glances/snmp.py
|
||||
glances/static_list.py
|
||||
|
||||
exclude_lines =
|
||||
pragma: no cover
|
||||
if PY3:
|
||||
if __name__ == .__main__.:
|
||||
if sys.platform.startswith
|
||||
except ImportError:
|
||||
raise NotImplementedError
|
||||
if WINDOWS
|
||||
if OSX
|
||||
if BSD
|
||||
2
.gitattributes
vendored
2
.gitattributes
vendored
@@ -1 +1 @@
|
||||
glances/outputs/static/public/js/*.js -diff
|
||||
glances/outputs/static/public/* -diff linguist-vendored
|
||||
|
||||
19
NEWS
19
NEWS
@@ -5,16 +5,35 @@ Glances Version 2
|
||||
Version 2.8
|
||||
===========
|
||||
|
||||
Deprecated:
|
||||
|
||||
* Deprecate Windows Curse UI: automaticaly open Web Browser for the standalone mode (issue #946)
|
||||
|
||||
Changes:
|
||||
|
||||
* IRQ plugin off by default. '--disable-irq' option replaced by '--enable-irq'.
|
||||
|
||||
Enhancements and new features:
|
||||
|
||||
* Add ZeroMQ exporter (issue #939)
|
||||
* Add CouchDB exporter (issue #928)
|
||||
* Add hotspot Wifi informations (issue #937)
|
||||
* Add default interface speed and automatic rate thresolds (issue #718)
|
||||
* Highlight max stats in the processes list (issue #878)
|
||||
* Docker alerts and actions (issue #875)
|
||||
* Glances API returns the processes PPID (issue #926)
|
||||
* Configure server cached time from the command line --cached-time (issue #901)
|
||||
* Make the log logger configurable (issue #900)
|
||||
* System uptime in export (issue #890)
|
||||
* Refactor the --disable-* options (issue #948)
|
||||
* PID column too small if kernel.pid_max is > 99999 (issue #959)
|
||||
|
||||
Bugs corrected:
|
||||
|
||||
* Glances RAID plugin Traceback (issue #927)
|
||||
* Default AMP crashes when 'command' given (issue #933)
|
||||
* Default AMP ignores `enable` setting (issue #932)
|
||||
* /proc/interrupts not found in an OpenVZ container (issue #947)
|
||||
|
||||
Version 2.7.1
|
||||
=============
|
||||
|
||||
@@ -51,6 +51,7 @@ Optional dependencies:
|
||||
- ``bernhard`` (for the Riemann export module)
|
||||
- ``py-cpuinfo`` (for the Quicklook CPU info module)
|
||||
- ``scandir`` (for the Folders plugin) [Only for Python < 3.5]
|
||||
- ``wifi`` (for the wifi plugin) [Linux-only]
|
||||
|
||||
*Note for Python 2.6 users*
|
||||
|
||||
@@ -109,14 +110,14 @@ features (like the Web interface, exports modules, sensors...):
|
||||
|
||||
.. code-block:: console
|
||||
|
||||
pip install bottle requests batinfo https://bitbucket.org/gleb_zhulik/py3sensors/get/tip.tar.gz zeroconf netifaces pymdstat influxdb elasticsearch potsdb statsd pystache docker-py pysnmp pika py-cpuinfo bernhard cassandra-driver scandir
|
||||
pip install bottle requests batinfo https://bitbucket.org/gleb_zhulik/py3sensors/get/tip.tar.gz zeroconf netifaces pymdstat influxdb elasticsearch potsdb statsd pystache docker-py pysnmp pika py-cpuinfo bernhard cassandra-driver scandir pyzmq
|
||||
|
||||
To upgrade Glances to the latest version:
|
||||
|
||||
.. code-block:: console
|
||||
|
||||
pip install --upgrade glances
|
||||
pip install --upgrade bottle requests batinfo https://bitbucket.org/gleb_zhulik/py3sensors/get/tip.tar.gz zeroconf netifaces pymdstat influxdb elasticsearch potsdb statsd pystache docker-py pysnmp pika py-cpuinfo bernhard cassandra-driver scandir
|
||||
pip install --upgrade bottle requests batinfo https://bitbucket.org/gleb_zhulik/py3sensors/get/tip.tar.gz zeroconf netifaces pymdstat influxdb elasticsearch potsdb statsd pystache docker-py pysnmp pika py-cpuinfo bernhard cassandra-driver scandir pyzmq
|
||||
|
||||
If you need to install Glances in a specific user location, use:
|
||||
|
||||
|
||||
@@ -96,11 +96,20 @@ careful=50
|
||||
warning=70
|
||||
critical=90
|
||||
|
||||
#[network]
|
||||
[network]
|
||||
# Default bitrate thresholds in % of the network interface speed
|
||||
# Default values if not defined: 70/80/90
|
||||
rx_careful=70
|
||||
rx_warning=80
|
||||
rx_critical=90
|
||||
tx_careful=70
|
||||
tx_warning=80
|
||||
tx_critical=90
|
||||
# Define the list of hidden network interfaces (comma-separated regexp)
|
||||
#hide=docker.*,lo
|
||||
# WLAN 0 alias
|
||||
#wlan0_alias=Wireless IF
|
||||
# It is possible to overwrite the bitrate thresholds per interface
|
||||
# WLAN 0 Default limits (in bits per second aka bps) for interface bitrate
|
||||
#wlan0_rx_careful=4000000
|
||||
#wlan0_rx_warning=5000000
|
||||
@@ -111,6 +120,15 @@ critical=90
|
||||
#wlan0_tx_critical=1000000
|
||||
#wlan0_tx_log=True
|
||||
|
||||
[wifi]
|
||||
# Define the list of hidden wireless network interfaces (comma-separated regexp)
|
||||
hide=lo,docker.*
|
||||
# Define SIGNAL thresholds in db (lower is better...)
|
||||
# Based on: http://serverfault.com/questions/501025/industry-standard-for-minimum-wifi-signal-strength
|
||||
careful=-65
|
||||
warning=-75
|
||||
critical=-85
|
||||
|
||||
#[diskio]
|
||||
# Define the list of hidden disks (comma-separated regexp)
|
||||
#hide=sda2,sda5,loop.*
|
||||
@@ -207,6 +225,19 @@ port_default_gateway=True
|
||||
#port_4_port=80
|
||||
#port_4_rtt_warning=1000
|
||||
|
||||
[docker]
|
||||
# Thresholds for CPU and MEM (in %)
|
||||
#cpu_careful=50
|
||||
#cpu_warning=70
|
||||
#cpu_critical=90
|
||||
#mem_careful=20
|
||||
#mem_warning=50
|
||||
#mem_critical=70
|
||||
# Per container thresholds
|
||||
#containername_cpu_careful=10
|
||||
#containername_cpu_warning=20
|
||||
#containername_cpu_critical=30
|
||||
|
||||
##############################################################################
|
||||
# Client/server
|
||||
##############################################################################
|
||||
@@ -306,6 +337,18 @@ db=glances
|
||||
#user=root
|
||||
#password=root
|
||||
|
||||
[zeromq]
|
||||
# Configuration for the --export-zeromq option
|
||||
# http://www.zeromq.org
|
||||
# Use * to bind on all interfaces
|
||||
host=*
|
||||
port=5678
|
||||
# Glances envelopes the stats in a publish message with two frames:
|
||||
# - First frame containing the following prefix (STRING)
|
||||
# - Second frame with the Glances plugin name (STRING)
|
||||
# - Third frame with the Glances plugin stats (JSON)
|
||||
prefix=G
|
||||
|
||||
##############################################################################
|
||||
# AMPS
|
||||
# * enable: Enable (true) or disable (false) the AMP
|
||||
@@ -352,10 +395,10 @@ status_url=http://localhost/nginx_status
|
||||
[amp_systemd]
|
||||
# Use the Systemd AMP
|
||||
enable=true
|
||||
regex=\/usr\/lib\/systemd\/systemd
|
||||
regex=\/lib\/systemd\/systemd
|
||||
refresh=30
|
||||
one_line=true
|
||||
systemctl_cmd=/usr/bin/systemctl --plain
|
||||
systemctl_cmd=/bin/systemctl --plain
|
||||
|
||||
[amp_systemv]
|
||||
# Use the Systemv AMP
|
||||
|
||||
25
docker/master/Dockerfile
Normal file
25
docker/master/Dockerfile
Normal file
@@ -0,0 +1,25 @@
|
||||
#
|
||||
# Glances Dockerfile
|
||||
#
|
||||
# https://github.com/nicolargo/glances
|
||||
#
|
||||
|
||||
# Pull base image.
|
||||
FROM ubuntu
|
||||
|
||||
# Install Glances (develop branch)
|
||||
RUN apt-get update && apt-get -y install curl && rm -rf /var/lib/apt/lists/*
|
||||
RUN curl -L https://raw.githubusercontent.com/nicolargo/glancesautoinstall/master/install.sh | /bin/bash && rm -rf /var/lib/apt/lists/*
|
||||
|
||||
|
||||
# Define working directory.
|
||||
WORKDIR /glances
|
||||
|
||||
# EXPOSE PORT (For XMLRPC)
|
||||
EXPOSE 61209
|
||||
|
||||
# EXPOSE PORT (For Web UI)
|
||||
EXPOSE 61208
|
||||
|
||||
# Define default command.
|
||||
CMD python -m glances -C /glances/conf/glances.conf $GLANCES_OPT
|
||||
BIN
docs/_static/wifi.png
vendored
Normal file
BIN
docs/_static/wifi.png
vendored
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 8.5 KiB |
@@ -16,13 +16,21 @@ displayed.
|
||||
CPU stats description:
|
||||
|
||||
* user: percent time spent in user space
|
||||
> User CPU time is time spent on the processor running your program's code (or code in libraries)
|
||||
* system: percent time spent in kernel space
|
||||
> System CPU time is the time spent running code in the operating system kernel
|
||||
* idle: percent of CPU used by any program
|
||||
> Every program or task that runs on a computer system occupies a certain amount of processing time on the CPU. If the CPU has completed all tasks it is idle.
|
||||
* nice: percent time occupied by user level processes with a positive nice value
|
||||
> The time the CPU has spent running users' processes that have been "niced"
|
||||
* irq: percent time spent servicing/handling hardware/software interrupts
|
||||
> Time servicing interrupts (hardware + software)
|
||||
* iowait: percent time spent in wait (on disk)
|
||||
* steal: percent time in involuntary wait by virtual cpu while hypervisor is servicing another processor/virtual machine
|
||||
> Time spent by the CPU waiting for a IO operations to complete
|
||||
* steal: percent time in involuntary wait by virtual CPU
|
||||
> Steal time is the percentage of time a virtual CPU waits for a real CPU while the hypervisor is servicing another virtual processor
|
||||
* ctx_sw: number of context switches (voluntary + involuntary) per second
|
||||
> A context switch is a procedure that a computer's CPU (central processing unit) follows to change from one task (or process) to another while ensuring that the tasks do not conflict
|
||||
* inter: number of interrupts per second
|
||||
* sw_inter: number of software interrupts per second. Always set to 0 on Windows and SunOS.
|
||||
* syscal: number of system calls per second. Do not displayed on Linux (always 0).
|
||||
|
||||
@@ -8,4 +8,25 @@ Glances uses the Docker API through the `docker-py`_ library.
|
||||
|
||||
.. image:: ../_static/docker.png
|
||||
|
||||
It is possible to define limits and actions from the configuration file
|
||||
under the ``[docker]`` section:
|
||||
|
||||
.. code-block:: ini
|
||||
|
||||
[docker]
|
||||
# Global containers' thresholds for CPU and MEM (in %)
|
||||
cpu_careful=50
|
||||
cpu_warning=70
|
||||
cpu_critical=90
|
||||
mem_careful=20
|
||||
mem_warning=50
|
||||
mem_critical=70
|
||||
# Per container thresholds
|
||||
containername_cpu_careful=10
|
||||
containername_cpu_warning=20
|
||||
containername_cpu_critical=30
|
||||
containername_cpu_critical_action=echo {{Image}} {{Id}} {{cpu}} > /tmp/container_{{name}}.alert
|
||||
|
||||
You can use all the variables ({{foo}}) available in the Docker plugin.
|
||||
|
||||
.. _docker-py: https://github.com/docker/docker-py
|
||||
|
||||
@@ -26,6 +26,7 @@ Legend:
|
||||
load
|
||||
memory
|
||||
network
|
||||
wifi
|
||||
ports
|
||||
disk
|
||||
fs
|
||||
|
||||
@@ -8,6 +8,8 @@ IRQ
|
||||
Glances displays the top 5 interrupts rate. This plugin is only available on
|
||||
GNU/Linux machine (stats are grabbed from the /proc/interrupts file).
|
||||
|
||||
Note: /proc/interrupts file did not exist inside OpenVZ containers.
|
||||
|
||||
How to read the informations:
|
||||
|
||||
* The first Column is the IRQ number / name
|
||||
|
||||
@@ -8,16 +8,20 @@ Network
|
||||
Glances displays the network interface bit rate. The unit is adapted
|
||||
dynamically (bit/s, kbit/s, Mbit/s, etc).
|
||||
|
||||
Alerts are only set if the maximum speed per network interface is
|
||||
available (see sample in the configuration file).
|
||||
If the interface speed is detected (not on all systems), the defaults
|
||||
thresholds are applied (70% for careful, 80% warning and 90% critical).
|
||||
It is possible to define this percents thresholds form the configuration
|
||||
file. It is also possible to define per interface bit rate thresholds.
|
||||
In this case thresholds values are define in bps.
|
||||
|
||||
It's also possibile to define:
|
||||
Additionally, you can define:
|
||||
|
||||
- a list of network interfaces to hide
|
||||
- per-interface limit values
|
||||
- aliases for interface name
|
||||
|
||||
in the ``[network]`` section of the configuration file.
|
||||
The configuration should be done in the ``[network]`` section of the
|
||||
Glances configuration file.
|
||||
|
||||
For example, if you want to hide the loopback interface (lo) and all the
|
||||
virtual docker interface (docker0, docker1, ...):
|
||||
@@ -25,4 +29,25 @@ virtual docker interface (docker0, docker1, ...):
|
||||
.. code-block:: ini
|
||||
|
||||
[network]
|
||||
hide=lo,docker.*
|
||||
# Default bitrate thresholds in % of the network interface speed
|
||||
# Default values if not defined: 70/80/90
|
||||
rx_careful=70
|
||||
rx_warning=80
|
||||
rx_critical=90
|
||||
tx_careful=70
|
||||
tx_warning=80
|
||||
tx_critical=90
|
||||
# Define the list of hidden network interfaces (comma-separated regexp)
|
||||
hide=docker.*,lo
|
||||
# WLAN 0 alias
|
||||
wlan0_alias=Wireless IF
|
||||
# It is possible to overwrite the bitrate thresholds per interface
|
||||
# WLAN 0 Default limits (in bits per second aka bps) for interface bitrate
|
||||
wlan0_rx_careful=4000000
|
||||
wlan0_rx_warning=5000000
|
||||
wlan0_rx_critical=6000000
|
||||
wlan0_rx_log=True
|
||||
wlan0_tx_careful=700000
|
||||
wlan0_tx_warning=900000
|
||||
wlan0_tx_critical=1000000
|
||||
wlan0_tx_log=True
|
||||
|
||||
@@ -52,23 +52,25 @@ Columns display
|
||||
``VIRT`` Virtual Memory Size
|
||||
|
||||
The total amount of virtual memory used by the
|
||||
process
|
||||
process. It includes all code, data and shared
|
||||
libraries plus pages that have been swapped out
|
||||
and pages that have been mapped but not used.
|
||||
``RES`` Resident Memory Size
|
||||
|
||||
The non-swapped physical memory a process is
|
||||
using
|
||||
using (what's currently in the physical memory).
|
||||
``PID`` Process ID
|
||||
``USER`` User ID
|
||||
``NI`` Nice level of the process
|
||||
``S`` Process status
|
||||
|
||||
The status of the process:
|
||||
|
||||
- ``R``: running
|
||||
- ``S``: sleeping (may be interrupted)
|
||||
- ``D``: disk sleep (may not be interrupted)
|
||||
- ``T``: traced/stopped
|
||||
- ``Z``: zombie
|
||||
- ``R``: running or runnable (on run queue)
|
||||
- ``S``: interruptible sleep (waiting for an event)
|
||||
- ``D``: uninterruptible sleep (usually IO)
|
||||
- ``Z``: defunct ("zombie") process
|
||||
- ``T``: traced/stopped by job control signal
|
||||
- ``X``: dead (should never be seen)
|
||||
|
||||
``TIME+`` Cumulative CPU time used by the process
|
||||
``R/s`` Per process I/O read rate in B/s
|
||||
|
||||
31
docs/aoa/wifi.rst
Normal file
31
docs/aoa/wifi.rst
Normal file
@@ -0,0 +1,31 @@
|
||||
.. _wifi:
|
||||
|
||||
Wifi
|
||||
=====
|
||||
|
||||
*Availability: Linux*
|
||||
|
||||
.. image:: ../_static/wifi.png
|
||||
|
||||
Glances displays the Wifi hotspots' name and signal quality.
|
||||
If Glances is ran as root, then all the available hotspots are displayed.
|
||||
|
||||
In the configuration file, you can define signal quality thresholds.
|
||||
"Poor" quality is between -100 and -85dBm, "Good" quality between -85
|
||||
and -60dBm, and "Excellent" between -60 and -40dBm.
|
||||
|
||||
It's also possible to disable the scan on a specific interface from the
|
||||
configuration file (``[wifi]`` section). For example, if you want to
|
||||
hide the loopback interface (lo) and all the virtual docker interfaces:
|
||||
|
||||
.. code-block:: ini
|
||||
|
||||
[wifi]
|
||||
hide=lo,docker.*
|
||||
# Define SIGNAL thresholds in dBm (lower is better...)
|
||||
careful=-65
|
||||
warning=-75
|
||||
critical=-85
|
||||
|
||||
You can disable this plugin using the --disable-wifi option or by heating
|
||||
the 'W' from the user interface.
|
||||
241
docs/cmds.rst
241
docs/cmds.rst
@@ -16,12 +16,101 @@ Command-Line Options
|
||||
|
||||
.. option:: -d, --debug
|
||||
|
||||
enable debug mode
|
||||
enable debug mode. The debugging output is saved to /tmp/glances.log.
|
||||
|
||||
.. option:: -C CONF_FILE, --config CONF_FILE
|
||||
|
||||
path to the configuration file
|
||||
|
||||
.. option:: --disable-alert
|
||||
|
||||
disable alert/log module
|
||||
|
||||
.. option:: --disable-amps
|
||||
|
||||
disable application monitoring process module
|
||||
|
||||
.. option:: --disable-cpu
|
||||
|
||||
disable CPU module
|
||||
|
||||
.. option:: --disable-diskio
|
||||
|
||||
disable disk I/O module
|
||||
|
||||
.. option:: --disable-docker
|
||||
|
||||
disable Docker module
|
||||
|
||||
.. option:: --disable-folders
|
||||
|
||||
disable folders module
|
||||
|
||||
.. option:: --disable-fs
|
||||
|
||||
disable file system module
|
||||
|
||||
.. option:: --disable-hddtemp
|
||||
|
||||
disable HD temperature module
|
||||
|
||||
.. option:: --disable-ip
|
||||
|
||||
disable IP module
|
||||
|
||||
.. option:: --disable-irq
|
||||
|
||||
disable IRQ module
|
||||
|
||||
.. option:: --disable-load
|
||||
|
||||
disable load module
|
||||
|
||||
.. option:: --disable-mem
|
||||
|
||||
disable memory module
|
||||
|
||||
.. option:: --disable-memswap
|
||||
|
||||
disable memory swap module
|
||||
|
||||
.. option:: --disable-network
|
||||
|
||||
disable network module
|
||||
|
||||
.. option:: --disable-ports
|
||||
|
||||
disable Ports module
|
||||
|
||||
.. option:: --disable-process
|
||||
|
||||
disable process module
|
||||
|
||||
.. option:: --disable-raid
|
||||
|
||||
disable RAID module
|
||||
|
||||
.. option:: --disable-sensors
|
||||
|
||||
disable sensors module
|
||||
|
||||
.. option:: --disable-wifi
|
||||
|
||||
disable Wifi module
|
||||
|
||||
.. option:: -0, --disable-irix
|
||||
|
||||
task's CPU usage will be divided by the total number of CPUs
|
||||
|
||||
.. option:: -1, --percpu
|
||||
|
||||
start Glances in per CPU mode
|
||||
|
||||
.. option:: -2, --disable-left-sidebar
|
||||
|
||||
disable network, disk I/O, FS and sensors modules (py3sensors lib
|
||||
needed)
|
||||
|
||||
.. option:: -3, --disable-quicklook
|
||||
|
||||
disable quick look module
|
||||
@@ -30,86 +119,13 @@ Command-Line Options
|
||||
|
||||
disable all but quick look and load
|
||||
|
||||
.. option:: --disable-cpu
|
||||
|
||||
disable CPU module
|
||||
|
||||
.. option:: --disable-mem
|
||||
|
||||
disable memory module
|
||||
|
||||
.. option:: --disable-swap
|
||||
|
||||
disable swap module
|
||||
|
||||
.. option:: --disable-load
|
||||
|
||||
disable load module
|
||||
|
||||
.. option:: --disable-network
|
||||
|
||||
disable network module
|
||||
|
||||
.. option:: --disable-ip
|
||||
|
||||
disable IP module
|
||||
|
||||
.. option:: --disable-diskio
|
||||
|
||||
disable disk I/O module
|
||||
|
||||
.. option:: --disable-fs
|
||||
|
||||
disable filesystem module
|
||||
|
||||
.. option:: --disable-folder
|
||||
|
||||
disable folder module
|
||||
|
||||
.. option:: --disable-irq
|
||||
|
||||
disable IRQ module
|
||||
|
||||
.. option:: --disable-sensors
|
||||
|
||||
disable sensors module
|
||||
|
||||
.. option:: --disable-hddtemp
|
||||
|
||||
disable HD temperature module
|
||||
|
||||
.. option:: --disable-raid
|
||||
|
||||
disable RAID module
|
||||
|
||||
.. option:: --disable-docker
|
||||
|
||||
disable Docker module
|
||||
|
||||
.. option:: --disable-ports
|
||||
|
||||
disable Ports module
|
||||
|
||||
.. option:: -5, --disable-top
|
||||
|
||||
disable top menu (QuickLook, CPU, MEM, SWAP and LOAD)
|
||||
|
||||
.. option:: -2, --disable-left-sidebar
|
||||
.. option:: --enable-history
|
||||
|
||||
disable network, disk I/O, FS and sensors modules (py3sensors lib
|
||||
needed)
|
||||
|
||||
.. option:: --disable-process
|
||||
|
||||
disable process module
|
||||
|
||||
.. option:: --disable-amps
|
||||
|
||||
disable application monitoring process module
|
||||
|
||||
.. option:: --disable-log
|
||||
|
||||
disable log module
|
||||
enable the history mode (matplotlib lib needed)
|
||||
|
||||
.. option:: --disable-bold
|
||||
|
||||
@@ -123,11 +139,11 @@ Command-Line Options
|
||||
|
||||
enable extended stats on top process
|
||||
|
||||
.. option:: --enable-history
|
||||
.. option:: --export-graph
|
||||
|
||||
enable the history mode (matplotlib lib needed)
|
||||
export stats to graph
|
||||
|
||||
.. option:: --path-history PATH_HISTORY
|
||||
.. option:: --path-graph PATH_GRAPH
|
||||
|
||||
set the export path for graph history
|
||||
|
||||
@@ -135,37 +151,41 @@ Command-Line Options
|
||||
|
||||
export stats to a CSV file
|
||||
|
||||
.. option:: --export-influxdb
|
||||
|
||||
export stats to an InfluxDB server (influxdb lib needed)
|
||||
|
||||
.. option:: --export-cassandra
|
||||
|
||||
export stats to a Cassandra/Scylla server (cassandra lib needed)
|
||||
|
||||
.. option:: --export-opentsdb
|
||||
.. option:: --export-couchdb
|
||||
|
||||
export stats to an OpenTSDB server (potsdb lib needed)
|
||||
|
||||
.. option:: --export-statsd
|
||||
|
||||
export stats to a StatsD server (statsd lib needed)
|
||||
|
||||
.. option:: --export-rabbitmq
|
||||
|
||||
export stats to RabbitMQ broker (pika lib needed)
|
||||
|
||||
.. option:: --export-riemann
|
||||
|
||||
export stats to Riemann server (bernhard lib needed)
|
||||
export stats to a CouchDB server (couchdb lib needed)
|
||||
|
||||
.. option:: --export-elasticsearch
|
||||
|
||||
export stats to an Elasticsearch server (elasticsearch lib needed)
|
||||
|
||||
.. option:: --export-couchdb
|
||||
.. option:: --export-influxdb
|
||||
|
||||
export stats to a CouchDB server (couchdb lib needed)
|
||||
export stats to an InfluxDB server (influxdb lib needed)
|
||||
|
||||
.. option:: --export-opentsdb
|
||||
|
||||
export stats to an OpenTSDB server (potsdb lib needed)
|
||||
|
||||
.. option:: --export-rabbitmq
|
||||
|
||||
export stats to RabbitMQ broker (pika lib needed)
|
||||
|
||||
.. option:: --export-statsd
|
||||
|
||||
export stats to a StatsD server (statsd lib needed)
|
||||
|
||||
.. option:: --export-riemann
|
||||
|
||||
export stats to Riemann server (bernhard lib needed)
|
||||
|
||||
.. option:: --export-zeromq
|
||||
|
||||
export stats to a ZeroMQ server (zmq lib needed)
|
||||
|
||||
.. option:: -c CLIENT, --client CLIENT
|
||||
|
||||
@@ -231,6 +251,14 @@ Command-Line Options
|
||||
|
||||
run Glances in web server mode (bottle lib needed)
|
||||
|
||||
.. option:: --cached-time CACHED_TIME
|
||||
|
||||
set the server cache time [default: 1 sec]
|
||||
|
||||
.. option:: open-web-browser
|
||||
|
||||
try to open the Web UI in the default Web browser
|
||||
|
||||
.. option:: -q, --quiet
|
||||
|
||||
do not display the curses interface
|
||||
@@ -243,10 +271,6 @@ Command-Line Options
|
||||
|
||||
force short name for processes name
|
||||
|
||||
.. option:: -0, --disable-irix
|
||||
|
||||
task's CPU usage will be divided by the total number of CPUs
|
||||
|
||||
.. option:: --hide-kernel-threads
|
||||
|
||||
hide kernel threads in process list
|
||||
@@ -271,10 +295,6 @@ Command-Line Options
|
||||
|
||||
display temperature in Fahrenheit (default is Celsius)
|
||||
|
||||
.. option:: -1, --percpu
|
||||
|
||||
start Glances in per CPU mode
|
||||
|
||||
.. option:: --fs-free-space
|
||||
|
||||
display FS free space instead of used
|
||||
@@ -283,6 +303,10 @@ Command-Line Options
|
||||
|
||||
optimize display colors for white background
|
||||
|
||||
.. option:: --disable-check-update
|
||||
|
||||
disable online Glances version ckeck
|
||||
|
||||
Interactive Commands
|
||||
--------------------
|
||||
|
||||
@@ -398,6 +422,9 @@ The following commands (key pressed) are supported while in Glances:
|
||||
``w``
|
||||
Delete finished warning log messages
|
||||
|
||||
``W``
|
||||
Show/hide Wifi module
|
||||
|
||||
``x``
|
||||
Delete finished warning and critical log messages
|
||||
|
||||
|
||||
@@ -110,3 +110,76 @@ By default, the ``glances.log`` file is under the temporary directory:
|
||||
|
||||
If ``glances.log`` is not writable, a new file will be created and
|
||||
returned to the user console.
|
||||
|
||||
If you want to use another system path or change the log message, you can use
|
||||
your own logger configuration. First of all you have to create a glances.json
|
||||
file with (for example) the following content (JSON format):
|
||||
|
||||
.. code-block:: json
|
||||
|
||||
{
|
||||
"version": 1,
|
||||
"disable_existing_loggers": "False",
|
||||
"root": {
|
||||
"level": "INFO",
|
||||
"handlers": ["file", "console"]
|
||||
},
|
||||
"formatters": {
|
||||
"standard": {
|
||||
"format": "%(asctime)s -- %(levelname)s -- %(message)s"
|
||||
},
|
||||
"short": {
|
||||
"format": "%(levelname)s: %(message)s"
|
||||
},
|
||||
"free": {
|
||||
"format": "%(message)s"
|
||||
}
|
||||
},
|
||||
"handlers": {
|
||||
"file": {
|
||||
"level": "DEBUG",
|
||||
"class": "logging.handlers.RotatingFileHandler",
|
||||
"formatter": "standard",
|
||||
"filename": "/var/tmp/glances.log"
|
||||
},
|
||||
"console": {
|
||||
"level": "CRITICAL",
|
||||
"class": "logging.StreamHandler",
|
||||
"formatter": "free"
|
||||
}
|
||||
},
|
||||
"loggers": {
|
||||
"debug": {
|
||||
"handlers": ["file", "console"],
|
||||
"level": "DEBUG"
|
||||
},
|
||||
"verbose": {
|
||||
"handlers": ["file", "console"],
|
||||
"level": "INFO"
|
||||
},
|
||||
"standard": {
|
||||
"handlers": ["file"],
|
||||
"level": "INFO"
|
||||
},
|
||||
"requests": {
|
||||
"handlers": ["file", "console"],
|
||||
"level": "ERROR"
|
||||
},
|
||||
"elasticsearch": {
|
||||
"handlers": ["file", "console"],
|
||||
"level": "ERROR"
|
||||
},
|
||||
"elasticsearch.trace": {
|
||||
"handlers": ["file", "console"],
|
||||
"level": "ERROR"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
and start Glances using the following command line:
|
||||
|
||||
.. code-block:: console
|
||||
|
||||
LOG_CFG=<path>/glances.json glances
|
||||
|
||||
Note: Replace <path> by the folder where your glances.json file is hosted.
|
||||
|
||||
@@ -10,10 +10,11 @@ to providing stats to multiple services (see list below).
|
||||
:maxdepth: 2
|
||||
|
||||
csv
|
||||
influxdb
|
||||
cassandra
|
||||
opentsdb
|
||||
statsd
|
||||
rabbitmq
|
||||
elastic
|
||||
influxdb
|
||||
opentsdb
|
||||
rabbitmq
|
||||
riemann
|
||||
statsd
|
||||
zeromq
|
||||
|
||||
57
docs/gw/zeromq.rst
Normal file
57
docs/gw/zeromq.rst
Normal file
@@ -0,0 +1,57 @@
|
||||
.. _zeromq:
|
||||
|
||||
ZeroMQ
|
||||
======
|
||||
|
||||
You can export statistics to a ``ZeroMQ`` server.
|
||||
|
||||
The connection should be defined in the Glances configuration file as
|
||||
following:
|
||||
|
||||
.. code-block:: ini
|
||||
|
||||
[zeromq]
|
||||
host=127.0.0.1
|
||||
port=5678
|
||||
prefix=G
|
||||
|
||||
Note: Glances `envelopes`_ the stats before publishing it.
|
||||
The message is composed of three frames.
|
||||
|
||||
- first frame containing the prefix configured in the [zeromq] section (as STRING)
|
||||
- second frame with the Glances plugin name (as STRING)
|
||||
- third frame with the Glances plugin stats (as JSON)
|
||||
|
||||
Run Glances with:
|
||||
|
||||
.. code-block:: console
|
||||
|
||||
$ glances --export-zeromq -C <path>/glances.conf
|
||||
|
||||
Following is a simple Python client to subscribe to the Glances stats:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
# -*- coding: utf-8 -*-
|
||||
#
|
||||
# ZeroMQ subscriber for Glances
|
||||
#
|
||||
|
||||
import json
|
||||
import zmq
|
||||
|
||||
context = zmq.Context()
|
||||
|
||||
subscriber = context.socket(zmq.SUB)
|
||||
subscriber.setsockopt(zmq.SUBSCRIBE, 'G')
|
||||
subscriber.connect("tcp://127.0.0.1:5678")
|
||||
|
||||
while True:
|
||||
_, plugin, data_raw = subscriber.recv_multipart()
|
||||
data = json.loads(data_raw)
|
||||
print('{} => {}'.format(plugin, data))
|
||||
|
||||
subscriber.close()
|
||||
context.term()
|
||||
|
||||
.. _envelopes: http://zguide.zeromq.org/page:all#Pub-Sub-Message-Envelopes
|
||||
@@ -22,12 +22,13 @@ features (like the Web interface, exports modules, sensors...):
|
||||
|
||||
.. code-block:: console
|
||||
|
||||
pip install bottle requests batinfo py3sensors zeroconf netifaces pymdstat influxdb elasticsearch potsdb statsd pystache docker-py pysnmp pika py-cpuinfo bernhard cassandra scandir couchdb
|
||||
pip install bottle requests batinfo py3sensors zeroconf netifaces pymdstat influxdb elasticsearch potsdb statsd pystache docker-py pysnmp pika py-cpuinfo bernhard cassandra scandir couchdb pyzmq wifi
|
||||
|
||||
To upgrade Glances to the latest version:
|
||||
To upgrade Glances and all its dependencies to the latests versions:
|
||||
|
||||
.. code-block:: console
|
||||
|
||||
pip install --upgrade bottle requests batinfo py3sensors zeroconf netifaces pymdstat influxdb elasticsearch potsdb statsd pystache docker-py pysnmp pika py-cpuinfo bernhard cassandra scandir couchdb pyzmq wifi
|
||||
pip install --upgrade glances
|
||||
|
||||
For additionnal installation methods, read the official `README`_ file.
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
.\" Man page generated from reStructuredText.
|
||||
.
|
||||
.TH "GLANCES" "1" "Sep 24, 2016" "2.8_DEVELOP" "Glances"
|
||||
.TH "GLANCES" "1" "Nov 21, 2016" "2.8_DEVELOP" "Glances"
|
||||
.SH NAME
|
||||
glances \- An eye on your system
|
||||
.
|
||||
@@ -59,7 +59,7 @@ show program\(aqs version number and exit
|
||||
.INDENT 0.0
|
||||
.TP
|
||||
.B \-d, \-\-debug
|
||||
enable debug mode
|
||||
enable debug mode. The debugging output is saved to /tmp/glances.log.
|
||||
.UNINDENT
|
||||
.INDENT 0.0
|
||||
.TP
|
||||
@@ -68,6 +68,117 @@ path to the configuration file
|
||||
.UNINDENT
|
||||
.INDENT 0.0
|
||||
.TP
|
||||
.B \-\-disable\-alert
|
||||
disable alert/log module
|
||||
.UNINDENT
|
||||
.INDENT 0.0
|
||||
.TP
|
||||
.B \-\-disable\-amps
|
||||
disable application monitoring process module
|
||||
.UNINDENT
|
||||
.INDENT 0.0
|
||||
.TP
|
||||
.B \-\-disable\-cpu
|
||||
disable CPU module
|
||||
.UNINDENT
|
||||
.INDENT 0.0
|
||||
.TP
|
||||
.B \-\-disable\-diskio
|
||||
disable disk I/O module
|
||||
.UNINDENT
|
||||
.INDENT 0.0
|
||||
.TP
|
||||
.B \-\-disable\-docker
|
||||
disable Docker module
|
||||
.UNINDENT
|
||||
.INDENT 0.0
|
||||
.TP
|
||||
.B \-\-disable\-folders
|
||||
disable folders module
|
||||
.UNINDENT
|
||||
.INDENT 0.0
|
||||
.TP
|
||||
.B \-\-disable\-fs
|
||||
disable file system module
|
||||
.UNINDENT
|
||||
.INDENT 0.0
|
||||
.TP
|
||||
.B \-\-disable\-hddtemp
|
||||
disable HD temperature module
|
||||
.UNINDENT
|
||||
.INDENT 0.0
|
||||
.TP
|
||||
.B \-\-disable\-ip
|
||||
disable IP module
|
||||
.UNINDENT
|
||||
.INDENT 0.0
|
||||
.TP
|
||||
.B \-\-disable\-irq
|
||||
disable IRQ module
|
||||
.UNINDENT
|
||||
.INDENT 0.0
|
||||
.TP
|
||||
.B \-\-disable\-load
|
||||
disable load module
|
||||
.UNINDENT
|
||||
.INDENT 0.0
|
||||
.TP
|
||||
.B \-\-disable\-mem
|
||||
disable memory module
|
||||
.UNINDENT
|
||||
.INDENT 0.0
|
||||
.TP
|
||||
.B \-\-disable\-memswap
|
||||
disable memory swap module
|
||||
.UNINDENT
|
||||
.INDENT 0.0
|
||||
.TP
|
||||
.B \-\-disable\-network
|
||||
disable network module
|
||||
.UNINDENT
|
||||
.INDENT 0.0
|
||||
.TP
|
||||
.B \-\-disable\-ports
|
||||
disable Ports module
|
||||
.UNINDENT
|
||||
.INDENT 0.0
|
||||
.TP
|
||||
.B \-\-disable\-process
|
||||
disable process module
|
||||
.UNINDENT
|
||||
.INDENT 0.0
|
||||
.TP
|
||||
.B \-\-disable\-raid
|
||||
disable RAID module
|
||||
.UNINDENT
|
||||
.INDENT 0.0
|
||||
.TP
|
||||
.B \-\-disable\-sensors
|
||||
disable sensors module
|
||||
.UNINDENT
|
||||
.INDENT 0.0
|
||||
.TP
|
||||
.B \-\-disable\-wifi
|
||||
disable Wifi module
|
||||
.UNINDENT
|
||||
.INDENT 0.0
|
||||
.TP
|
||||
.B \-0, \-\-disable\-irix
|
||||
task\(aqs CPU usage will be divided by the total number of CPUs
|
||||
.UNINDENT
|
||||
.INDENT 0.0
|
||||
.TP
|
||||
.B \-1, \-\-percpu
|
||||
start Glances in per CPU mode
|
||||
.UNINDENT
|
||||
.INDENT 0.0
|
||||
.TP
|
||||
.B \-2, \-\-disable\-left\-sidebar
|
||||
disable network, disk I/O, FS and sensors modules (py3sensors lib
|
||||
needed)
|
||||
.UNINDENT
|
||||
.INDENT 0.0
|
||||
.TP
|
||||
.B \-3, \-\-disable\-quicklook
|
||||
disable quick look module
|
||||
.UNINDENT
|
||||
@@ -78,104 +189,13 @@ disable all but quick look and load
|
||||
.UNINDENT
|
||||
.INDENT 0.0
|
||||
.TP
|
||||
.B \-\-disable\-cpu
|
||||
disable CPU module
|
||||
.UNINDENT
|
||||
.INDENT 0.0
|
||||
.TP
|
||||
.B \-\-disable\-mem
|
||||
disable memory module
|
||||
.UNINDENT
|
||||
.INDENT 0.0
|
||||
.TP
|
||||
.B \-\-disable\-swap
|
||||
disable swap module
|
||||
.UNINDENT
|
||||
.INDENT 0.0
|
||||
.TP
|
||||
.B \-\-disable\-load
|
||||
disable load module
|
||||
.UNINDENT
|
||||
.INDENT 0.0
|
||||
.TP
|
||||
.B \-\-disable\-network
|
||||
disable network module
|
||||
.UNINDENT
|
||||
.INDENT 0.0
|
||||
.TP
|
||||
.B \-\-disable\-ip
|
||||
disable IP module
|
||||
.UNINDENT
|
||||
.INDENT 0.0
|
||||
.TP
|
||||
.B \-\-disable\-diskio
|
||||
disable disk I/O module
|
||||
.UNINDENT
|
||||
.INDENT 0.0
|
||||
.TP
|
||||
.B \-\-disable\-fs
|
||||
disable filesystem module
|
||||
.UNINDENT
|
||||
.INDENT 0.0
|
||||
.TP
|
||||
.B \-\-disable\-folder
|
||||
disable folder module
|
||||
.UNINDENT
|
||||
.INDENT 0.0
|
||||
.TP
|
||||
.B \-\-disable\-irq
|
||||
disable IRQ module
|
||||
.UNINDENT
|
||||
.INDENT 0.0
|
||||
.TP
|
||||
.B \-\-disable\-sensors
|
||||
disable sensors module
|
||||
.UNINDENT
|
||||
.INDENT 0.0
|
||||
.TP
|
||||
.B \-\-disable\-hddtemp
|
||||
disable HD temperature module
|
||||
.UNINDENT
|
||||
.INDENT 0.0
|
||||
.TP
|
||||
.B \-\-disable\-raid
|
||||
disable RAID module
|
||||
.UNINDENT
|
||||
.INDENT 0.0
|
||||
.TP
|
||||
.B \-\-disable\-docker
|
||||
disable Docker module
|
||||
.UNINDENT
|
||||
.INDENT 0.0
|
||||
.TP
|
||||
.B \-\-disable\-ports
|
||||
disable Ports module
|
||||
.UNINDENT
|
||||
.INDENT 0.0
|
||||
.TP
|
||||
.B \-5, \-\-disable\-top
|
||||
disable top menu (QuickLook, CPU, MEM, SWAP and LOAD)
|
||||
.UNINDENT
|
||||
.INDENT 0.0
|
||||
.TP
|
||||
.B \-2, \-\-disable\-left\-sidebar
|
||||
disable network, disk I/O, FS and sensors modules (py3sensors lib
|
||||
needed)
|
||||
.UNINDENT
|
||||
.INDENT 0.0
|
||||
.TP
|
||||
.B \-\-disable\-process
|
||||
disable process module
|
||||
.UNINDENT
|
||||
.INDENT 0.0
|
||||
.TP
|
||||
.B \-\-disable\-amps
|
||||
disable application monitoring process module
|
||||
.UNINDENT
|
||||
.INDENT 0.0
|
||||
.TP
|
||||
.B \-\-disable\-log
|
||||
disable log module
|
||||
.B \-\-enable\-history
|
||||
enable the history mode (matplotlib lib needed)
|
||||
.UNINDENT
|
||||
.INDENT 0.0
|
||||
.TP
|
||||
@@ -194,12 +214,12 @@ enable extended stats on top process
|
||||
.UNINDENT
|
||||
.INDENT 0.0
|
||||
.TP
|
||||
.B \-\-enable\-history
|
||||
enable the history mode (matplotlib lib needed)
|
||||
.B \-\-export\-graph
|
||||
export stats to graph
|
||||
.UNINDENT
|
||||
.INDENT 0.0
|
||||
.TP
|
||||
.B \-\-path\-history PATH_HISTORY
|
||||
.B \-\-path\-graph PATH_GRAPH
|
||||
set the export path for graph history
|
||||
.UNINDENT
|
||||
.INDENT 0.0
|
||||
@@ -209,33 +229,13 @@ export stats to a CSV file
|
||||
.UNINDENT
|
||||
.INDENT 0.0
|
||||
.TP
|
||||
.B \-\-export\-influxdb
|
||||
export stats to an InfluxDB server (influxdb lib needed)
|
||||
.UNINDENT
|
||||
.INDENT 0.0
|
||||
.TP
|
||||
.B \-\-export\-cassandra
|
||||
export stats to a Cassandra/Scylla server (cassandra lib needed)
|
||||
.UNINDENT
|
||||
.INDENT 0.0
|
||||
.TP
|
||||
.B \-\-export\-opentsdb
|
||||
export stats to an OpenTSDB server (potsdb lib needed)
|
||||
.UNINDENT
|
||||
.INDENT 0.0
|
||||
.TP
|
||||
.B \-\-export\-statsd
|
||||
export stats to a StatsD server (statsd lib needed)
|
||||
.UNINDENT
|
||||
.INDENT 0.0
|
||||
.TP
|
||||
.B \-\-export\-rabbitmq
|
||||
export stats to RabbitMQ broker (pika lib needed)
|
||||
.UNINDENT
|
||||
.INDENT 0.0
|
||||
.TP
|
||||
.B \-\-export\-riemann
|
||||
export stats to Riemann server (bernhard lib needed)
|
||||
.B \-\-export\-couchdb
|
||||
export stats to a CouchDB server (couchdb lib needed)
|
||||
.UNINDENT
|
||||
.INDENT 0.0
|
||||
.TP
|
||||
@@ -244,8 +244,33 @@ export stats to an Elasticsearch server (elasticsearch lib needed)
|
||||
.UNINDENT
|
||||
.INDENT 0.0
|
||||
.TP
|
||||
.B \-\-export\-couchdb
|
||||
export stats to a CouchDB server (couchdb lib needed)
|
||||
.B \-\-export\-influxdb
|
||||
export stats to an InfluxDB server (influxdb lib needed)
|
||||
.UNINDENT
|
||||
.INDENT 0.0
|
||||
.TP
|
||||
.B \-\-export\-opentsdb
|
||||
export stats to an OpenTSDB server (potsdb lib needed)
|
||||
.UNINDENT
|
||||
.INDENT 0.0
|
||||
.TP
|
||||
.B \-\-export\-rabbitmq
|
||||
export stats to RabbitMQ broker (pika lib needed)
|
||||
.UNINDENT
|
||||
.INDENT 0.0
|
||||
.TP
|
||||
.B \-\-export\-statsd
|
||||
export stats to a StatsD server (statsd lib needed)
|
||||
.UNINDENT
|
||||
.INDENT 0.0
|
||||
.TP
|
||||
.B \-\-export\-riemann
|
||||
export stats to Riemann server (bernhard lib needed)
|
||||
.UNINDENT
|
||||
.INDENT 0.0
|
||||
.TP
|
||||
.B \-\-export\-zeromq
|
||||
export stats to a ZeroMQ server (zmq lib needed)
|
||||
.UNINDENT
|
||||
.INDENT 0.0
|
||||
.TP
|
||||
@@ -329,6 +354,16 @@ run Glances in web server mode (bottle lib needed)
|
||||
.UNINDENT
|
||||
.INDENT 0.0
|
||||
.TP
|
||||
.B \-\-cached\-time CACHED_TIME
|
||||
set the server cache time [default: 1 sec]
|
||||
.UNINDENT
|
||||
.INDENT 0.0
|
||||
.TP
|
||||
.B open\-web\-browser
|
||||
try to open the Web UI in the default Web browser
|
||||
.UNINDENT
|
||||
.INDENT 0.0
|
||||
.TP
|
||||
.B \-q, \-\-quiet
|
||||
do not display the curses interface
|
||||
.UNINDENT
|
||||
@@ -344,11 +379,6 @@ force short name for processes name
|
||||
.UNINDENT
|
||||
.INDENT 0.0
|
||||
.TP
|
||||
.B \-0, \-\-disable\-irix
|
||||
task\(aqs CPU usage will be divided by the total number of CPUs
|
||||
.UNINDENT
|
||||
.INDENT 0.0
|
||||
.TP
|
||||
.B \-\-hide\-kernel\-threads
|
||||
hide kernel threads in process list
|
||||
.UNINDENT
|
||||
@@ -379,11 +409,6 @@ display temperature in Fahrenheit (default is Celsius)
|
||||
.UNINDENT
|
||||
.INDENT 0.0
|
||||
.TP
|
||||
.B \-1, \-\-percpu
|
||||
start Glances in per CPU mode
|
||||
.UNINDENT
|
||||
.INDENT 0.0
|
||||
.TP
|
||||
.B \-\-fs\-free\-space
|
||||
display FS free space instead of used
|
||||
.UNINDENT
|
||||
@@ -392,6 +417,11 @@ display FS free space instead of used
|
||||
.B \-\-theme\-white
|
||||
optimize display colors for white background
|
||||
.UNINDENT
|
||||
.INDENT 0.0
|
||||
.TP
|
||||
.B \-\-disable\-check\-update
|
||||
disable online Glances version ckeck
|
||||
.UNINDENT
|
||||
.SH INTERACTIVE COMMANDS
|
||||
.sp
|
||||
The following commands (key pressed) are supported while in Glances:
|
||||
@@ -511,6 +541,9 @@ View cumulative network I/O
|
||||
.B \fBw\fP
|
||||
Delete finished warning log messages
|
||||
.TP
|
||||
.B \fBW\fP
|
||||
Show/hide Wifi module
|
||||
.TP
|
||||
.B \fBx\fP
|
||||
Delete finished warning and critical log messages
|
||||
.TP
|
||||
|
||||
@@ -20,13 +20,13 @@
|
||||
|
||||
"""Init the Glances software."""
|
||||
|
||||
# Import system libs
|
||||
import locale
|
||||
import platform
|
||||
import signal
|
||||
import sys
|
||||
|
||||
# Global name
|
||||
__appname__ = 'glances'
|
||||
__version__ = '2.8_DEVELOP'
|
||||
__author__ = 'Nicolas Hennion <nicolas@nicolargo.com>'
|
||||
__license__ = 'LGPL'
|
||||
@@ -42,7 +42,9 @@ except ImportError:
|
||||
# Note: others Glances libs will be imported optionally
|
||||
from glances.logger import logger
|
||||
from glances.main import GlancesMain
|
||||
from glances.globals import WINDOWS
|
||||
|
||||
# Check locale
|
||||
try:
|
||||
locale.setlocale(locale.LC_ALL, '')
|
||||
except locale.Error:
|
||||
@@ -93,6 +95,111 @@ def end():
|
||||
sys.exit(0)
|
||||
|
||||
|
||||
def start_standalone(config, args):
|
||||
"""Start the standalone mode"""
|
||||
logger.info("Start standalone mode")
|
||||
|
||||
# Share global var
|
||||
global standalone
|
||||
|
||||
# Import the Glances standalone module
|
||||
from glances.standalone import GlancesStandalone
|
||||
|
||||
# Init the standalone mode
|
||||
standalone = GlancesStandalone(config=config, args=args)
|
||||
|
||||
# Start the standalone (CLI) loop
|
||||
standalone.serve_forever()
|
||||
|
||||
|
||||
def start_clientbrowser(config, args):
|
||||
"""Start the browser client mode"""
|
||||
logger.info("Start client mode (browser)")
|
||||
|
||||
# Share global var
|
||||
global client
|
||||
|
||||
# Import the Glances client browser module
|
||||
from glances.client_browser import GlancesClientBrowser
|
||||
|
||||
# Init the client
|
||||
client = GlancesClientBrowser(config=config, args=args)
|
||||
|
||||
# Start the client loop
|
||||
client.serve_forever()
|
||||
|
||||
# Shutdown the client
|
||||
client.end()
|
||||
|
||||
|
||||
def start_client(config, args):
|
||||
"""Start the client mode"""
|
||||
logger.info("Start client mode")
|
||||
|
||||
# Share global var
|
||||
global client
|
||||
|
||||
# Import the Glances client browser module
|
||||
from glances.client import GlancesClient
|
||||
|
||||
# Init the client
|
||||
client = GlancesClient(config=config, args=args)
|
||||
|
||||
# Test if client and server are in the same major version
|
||||
if not client.login():
|
||||
logger.critical("The server version is not compatible with the client")
|
||||
sys.exit(2)
|
||||
|
||||
# Start the client loop
|
||||
client.serve_forever()
|
||||
|
||||
# Shutdown the client
|
||||
client.end()
|
||||
|
||||
|
||||
def start_server(config, args):
|
||||
"""Start the server mode"""
|
||||
logger.info("Start server mode")
|
||||
|
||||
# Share global var
|
||||
global server
|
||||
|
||||
# Import the Glances server module
|
||||
from glances.server import GlancesServer
|
||||
|
||||
server = GlancesServer(cached_time=args.cached_time,
|
||||
config=config,
|
||||
args=args)
|
||||
print('Glances server is running on {}:{}'.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()
|
||||
|
||||
|
||||
def start_webserver(config, args):
|
||||
"""Start the Web server mode"""
|
||||
logger.info("Start web server mode")
|
||||
|
||||
# Share global var
|
||||
global webserver
|
||||
|
||||
# Import the Glances web server module
|
||||
from glances.webserver import GlancesWebServer
|
||||
|
||||
# Init the web server mode
|
||||
webserver = GlancesWebServer(config=config, args=args)
|
||||
|
||||
# Start the web server loop
|
||||
webserver.serve_forever()
|
||||
|
||||
|
||||
def main():
|
||||
"""Main entry point for Glances.
|
||||
|
||||
@@ -107,92 +214,29 @@ def main():
|
||||
psutil_version))
|
||||
|
||||
# Share global var
|
||||
global core, standalone, client, server, webserver
|
||||
global core
|
||||
|
||||
# Create the Glances main instance
|
||||
core = GlancesMain()
|
||||
config = core.get_config()
|
||||
args = core.get_args()
|
||||
|
||||
# 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():
|
||||
logger.info("Start standalone mode")
|
||||
|
||||
# Import the Glances standalone module
|
||||
from 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():
|
||||
if core.is_standalone() and not WINDOWS:
|
||||
start_standalone(config=config, args=args)
|
||||
elif core.is_client() and not WINDOWS:
|
||||
if core.is_client_browser():
|
||||
logger.info("Start client mode (browser)")
|
||||
|
||||
# Import the Glances client browser module
|
||||
from glances.client_browser import GlancesClientBrowser
|
||||
|
||||
# Init the client
|
||||
client = GlancesClientBrowser(config=core.get_config(),
|
||||
args=core.get_args())
|
||||
|
||||
start_clientbrowser(config=config, args=args)
|
||||
else:
|
||||
logger.info("Start client mode")
|
||||
|
||||
# Import the Glances client module
|
||||
from 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():
|
||||
logger.critical("The server version is not compatible with the client")
|
||||
sys.exit(2)
|
||||
|
||||
# Start the client loop
|
||||
client.serve_forever()
|
||||
|
||||
# Shutdown the client
|
||||
client.end()
|
||||
|
||||
start_client(config=config, args=args)
|
||||
elif core.is_server():
|
||||
logger.info("Start server mode")
|
||||
|
||||
# Import the Glances server module
|
||||
from glances.server import GlancesServer
|
||||
|
||||
args = core.get_args()
|
||||
print args.cached_time
|
||||
|
||||
server = GlancesServer(cached_time=args.cached_time,
|
||||
config=core.get_config(),
|
||||
args=args)
|
||||
print('Glances server is running on {}:{}'.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():
|
||||
logger.info("Start web server mode")
|
||||
|
||||
# Import the Glances web server module
|
||||
from 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()
|
||||
start_server(config=config, args=args)
|
||||
elif core.is_webserver() or (core.is_standalone() and WINDOWS):
|
||||
# Web server mode replace the standalone mode on Windows OS
|
||||
# In this case, try to start the web browser mode automaticaly
|
||||
if core.is_standalone() and WINDOWS:
|
||||
args.open_web_browser = True
|
||||
start_webserver(config=config, args=args)
|
||||
|
||||
@@ -35,7 +35,7 @@ one_line=false
|
||||
command=foo status
|
||||
"""
|
||||
|
||||
from subprocess import check_output, STDOUT
|
||||
from subprocess import check_output, STDOUT, CalledProcessError
|
||||
|
||||
from glances.compat import u, to_ascii
|
||||
from glances.logger import logger
|
||||
@@ -66,8 +66,11 @@ class Amp(GlancesAmp):
|
||||
logger.debug('{}: Error while executing service ({})'.format(self.NAME, e))
|
||||
else:
|
||||
if res is not None:
|
||||
msg = u(check_output(res.split(), stderr=STDOUT))
|
||||
self.set_result(to_ascii(msg.rstrip()))
|
||||
try:
|
||||
msg = u(check_output(res.split(), stderr=STDOUT))
|
||||
self.set_result(to_ascii(msg.rstrip()))
|
||||
except CalledProcessError as e:
|
||||
self.set_result(e.output)
|
||||
else:
|
||||
# Set the default message if command return None
|
||||
# Default sum of CPU and MEM for the matching regex
|
||||
|
||||
@@ -106,9 +106,11 @@ class AmpsList(object):
|
||||
"""Update the command result attributed."""
|
||||
# Search application monitored processes by a regular expression
|
||||
processlist = glances_processes.getalllist()
|
||||
|
||||
# Iter upon the AMPs dict
|
||||
for k, v in iteritems(self.get()):
|
||||
if not v.enable():
|
||||
# Do not update if the enable tag is set
|
||||
continue
|
||||
try:
|
||||
amps_list = [p for p in processlist for c in p['cmdline'] if re.search(v.regex(), c) is not None]
|
||||
except TypeError:
|
||||
|
||||
@@ -22,7 +22,6 @@
|
||||
import socket
|
||||
import sys
|
||||
|
||||
from glances import __appname__
|
||||
from glances.globals import BSD
|
||||
from glances.logger import logger
|
||||
|
||||
@@ -48,8 +47,8 @@ if zeroconf_tag:
|
||||
|
||||
# Global var
|
||||
# Recent versions of the zeroconf python package doesnt like a zeroconf type that ends with '._tcp.'.
|
||||
# Correct issue: zeroconf problem with zeroconf_type = "_%s._tcp." % __appname__ #888
|
||||
zeroconf_type = "_%s._tcp.local." % __appname__
|
||||
# Correct issue: zeroconf problem with zeroconf_type = "_%s._tcp." % 'glances' #888
|
||||
zeroconf_type = "_%s._tcp.local." % 'glances'
|
||||
|
||||
|
||||
class AutoDiscovered(object):
|
||||
|
||||
@@ -21,6 +21,7 @@
|
||||
|
||||
import json
|
||||
import socket
|
||||
import threading
|
||||
|
||||
from glances.compat import Fault, ProtocolError, ServerProxy
|
||||
from glances.autodiscover import GlancesAutoDiscoverServer
|
||||
@@ -90,144 +91,150 @@ class GlancesClientBrowser(object):
|
||||
else:
|
||||
return 'http://{}:{}'.format(server['ip'], server['port'])
|
||||
|
||||
def __update_stats(self, server):
|
||||
"""
|
||||
Update stats for the given server (picked from the server list)
|
||||
"""
|
||||
# Get the server URI
|
||||
uri = self.__get_uri(server)
|
||||
|
||||
# Try to connect to the server
|
||||
t = GlancesClientTransport()
|
||||
t.set_timeout(3)
|
||||
|
||||
# Get common stats
|
||||
try:
|
||||
s = ServerProxy(uri, transport=t)
|
||||
except Exception as e:
|
||||
logger.warning(
|
||||
"Client browser couldn't create socket {}: {}".format(uri, e))
|
||||
else:
|
||||
# Mandatory stats
|
||||
try:
|
||||
# CPU%
|
||||
cpu_percent = 100 - json.loads(s.getCpu())['idle']
|
||||
server['cpu_percent'] = '{:.1f}'.format(cpu_percent)
|
||||
# MEM%
|
||||
server['mem_percent'] = json.loads(s.getMem())['percent']
|
||||
# OS (Human Readable name)
|
||||
server['hr_name'] = json.loads(s.getSystem())['hr_name']
|
||||
except (socket.error, Fault, KeyError) as e:
|
||||
logger.debug(
|
||||
"Error while grabbing stats form {}: {}".format(uri, e))
|
||||
server['status'] = 'OFFLINE'
|
||||
except ProtocolError as e:
|
||||
if e.errcode == 401:
|
||||
# Error 401 (Authentication failed)
|
||||
# Password is not the good one...
|
||||
server['password'] = None
|
||||
server['status'] = 'PROTECTED'
|
||||
else:
|
||||
server['status'] = 'OFFLINE'
|
||||
logger.debug("Cannot grab stats from {} ({} {})".format(uri, e.errcode, e.errmsg))
|
||||
else:
|
||||
# Status
|
||||
server['status'] = 'ONLINE'
|
||||
|
||||
# Optional stats (load is not available on Windows OS)
|
||||
try:
|
||||
# LOAD
|
||||
load_min5 = json.loads(s.getLoad())['min5']
|
||||
server['load_min5'] = '{:.2f}'.format(load_min5)
|
||||
except Exception as e:
|
||||
logger.warning(
|
||||
"Error while grabbing stats form {}: {}".format(uri, e))
|
||||
|
||||
return server
|
||||
|
||||
def __display_server(self, server):
|
||||
"""
|
||||
Connect and display the given server
|
||||
"""
|
||||
# Display the Glances client for the selected server
|
||||
logger.debug("Selected server: {}".format(server))
|
||||
|
||||
# Connection can take time
|
||||
# Display a popup
|
||||
self.screen.display_popup(
|
||||
'Connect to {}:{}'.format(server['name'], server['port']), duration=1)
|
||||
|
||||
# A password is needed to access to the server's stats
|
||||
if server['password'] is None:
|
||||
# First of all, check if a password is available in the [passwords] section
|
||||
clear_password = self.password.get_password(server['name'])
|
||||
if (clear_password is None or self.get_servers_list()
|
||||
[self.screen.active_server]['status'] == 'PROTECTED'):
|
||||
# Else, the password should be enter by the user
|
||||
# Display a popup to enter password
|
||||
clear_password = self.screen.display_popup(
|
||||
'Password needed for {}: '.format(server['name']), is_input=True)
|
||||
# Store the password for the selected server
|
||||
if clear_password is not None:
|
||||
self.set_in_selected('password', self.password.sha256_hash(clear_password))
|
||||
|
||||
# Display the Glance client on the selected server
|
||||
logger.info("Connect Glances client to the {} server".format(server['key']))
|
||||
|
||||
# Init the client
|
||||
args_server = self.args
|
||||
|
||||
# Overwrite connection setting
|
||||
args_server.client = server['ip']
|
||||
args_server.port = server['port']
|
||||
args_server.username = server['username']
|
||||
args_server.password = server['password']
|
||||
client = GlancesClient(config=self.config, args=args_server, return_to_browser=True)
|
||||
|
||||
# Test if client and server are in the same major version
|
||||
if not client.login():
|
||||
self.screen.display_popup(
|
||||
"Sorry, cannot connect to '{}'\n"
|
||||
"See 'glances.log' for more details".format(server['name']))
|
||||
|
||||
# Set the ONLINE status for the selected server
|
||||
self.set_in_selected('status', 'OFFLINE')
|
||||
else:
|
||||
# Start the client loop
|
||||
# Return connection type: 'glances' or 'snmp'
|
||||
connection_type = client.serve_forever()
|
||||
|
||||
try:
|
||||
logger.debug("Disconnect Glances client from the {} server".format(server['key']))
|
||||
except IndexError:
|
||||
# Server did not exist anymore
|
||||
pass
|
||||
else:
|
||||
# Set the ONLINE status for the selected server
|
||||
if connection_type == 'snmp':
|
||||
self.set_in_selected('status', 'SNMP')
|
||||
else:
|
||||
self.set_in_selected('status', 'ONLINE')
|
||||
|
||||
# Return to the browser (no server selected)
|
||||
self.screen.active_server = None
|
||||
|
||||
def __serve_forever(self):
|
||||
"""Main client loop."""
|
||||
while True:
|
||||
# No need to update the server list
|
||||
# It's done by the GlancesAutoDiscoverListener class (autodiscover.py)
|
||||
# Or define staticaly in the configuration file (module static_list.py)
|
||||
# For each server in the list, grab elementary stats (CPU, LOAD, MEM, OS...)
|
||||
# logger.debug(self.get_servers_list())
|
||||
try:
|
||||
for v in self.get_servers_list():
|
||||
# Do not retreive stats for statics server
|
||||
# Why ? Because for each offline servers, the timeout will be reached
|
||||
# So ? The curse interface freezes
|
||||
if v['type'] == 'STATIC' and v['status'] in ['UNKNOWN', 'SNMP', 'OFFLINE']:
|
||||
continue
|
||||
# No need to update the server list
|
||||
# It's done by the GlancesAutoDiscoverListener class (autodiscover.py)
|
||||
# Or define staticaly in the configuration file (module static_list.py)
|
||||
# For each server in the list, grab elementary stats (CPU, LOAD, MEM, OS...)
|
||||
|
||||
# Get the server URI
|
||||
uri = self.__get_uri(v)
|
||||
logger.debug("Iter through the following server list: {}".format(self.get_servers_list()))
|
||||
for v in self.get_servers_list():
|
||||
thread = threading.Thread(target=self.__update_stats, args=[v])
|
||||
thread.start()
|
||||
|
||||
# Try to connect to the server
|
||||
t = GlancesClientTransport()
|
||||
t.set_timeout(3)
|
||||
# Update the screen (list or Glances client)
|
||||
if self.screen.active_server is None:
|
||||
# Display the Glances browser
|
||||
self.screen.update(self.get_servers_list())
|
||||
else:
|
||||
# Display the active server
|
||||
self.__display_server(self.get_servers_list()[self.screen.active_server])
|
||||
|
||||
# Get common stats
|
||||
try:
|
||||
s = ServerProxy(uri, transport=t)
|
||||
except Exception as e:
|
||||
logger.warning(
|
||||
"Client browser couldn't create socket {}: {}".format(uri, e))
|
||||
else:
|
||||
# Mandatory stats
|
||||
try:
|
||||
# CPU%
|
||||
cpu_percent = 100 - json.loads(s.getCpu())['idle']
|
||||
v['cpu_percent'] = '{:.1f}'.format(cpu_percent)
|
||||
# MEM%
|
||||
v['mem_percent'] = json.loads(s.getMem())['percent']
|
||||
# OS (Human Readable name)
|
||||
v['hr_name'] = json.loads(s.getSystem())['hr_name']
|
||||
except (socket.error, Fault, KeyError) as e:
|
||||
logger.debug(
|
||||
"Error while grabbing stats form {}: {}".format(uri, e))
|
||||
v['status'] = 'OFFLINE'
|
||||
except ProtocolError as e:
|
||||
if e.errcode == 401:
|
||||
# Error 401 (Authentication failed)
|
||||
# Password is not the good one...
|
||||
v['password'] = None
|
||||
v['status'] = 'PROTECTED'
|
||||
else:
|
||||
v['status'] = 'OFFLINE'
|
||||
logger.debug("Cannot grab stats from {} ({} {})".format(uri, e.errcode, e.errmsg))
|
||||
else:
|
||||
# Status
|
||||
v['status'] = 'ONLINE'
|
||||
|
||||
# Optional stats (load is not available on Windows OS)
|
||||
try:
|
||||
# LOAD
|
||||
load_min5 = json.loads(s.getLoad())['min5']
|
||||
v['load_min5'] = '{:.2f}'.format(load_min5)
|
||||
except Exception as e:
|
||||
logger.warning(
|
||||
"Error while grabbing stats form {}: {}".format(uri, e))
|
||||
# List can change size during iteration...
|
||||
except RuntimeError:
|
||||
logger.debug(
|
||||
"Server list dictionnary change inside the loop (wait next update)")
|
||||
|
||||
# Update the screen (list or Glances client)
|
||||
if self.screen.active_server is None:
|
||||
# Display the Glances browser
|
||||
self.screen.update(self.get_servers_list())
|
||||
else:
|
||||
# Display the Glances client for the selected server
|
||||
logger.debug("Selected server: {}".format(self.get_servers_list()[self.screen.active_server]))
|
||||
|
||||
# Connection can take time
|
||||
# Display a popup
|
||||
self.screen.display_popup(
|
||||
'Connect to {}:{}'.format(v['name'], v['port']), duration=1)
|
||||
|
||||
# A password is needed to access to the server's stats
|
||||
if self.get_servers_list()[self.screen.active_server]['password'] is None:
|
||||
# First of all, check if a password is available in the [passwords] section
|
||||
clear_password = self.password.get_password(v['name'])
|
||||
if (clear_password is None or self.get_servers_list()
|
||||
[self.screen.active_server]['status'] == 'PROTECTED'):
|
||||
# Else, the password should be enter by the user
|
||||
# Display a popup to enter password
|
||||
clear_password = self.screen.display_popup(
|
||||
'Password needed for {}: '.format(v['name']), is_input=True)
|
||||
# Store the password for the selected server
|
||||
if clear_password is not None:
|
||||
self.set_in_selected('password', self.password.sha256_hash(clear_password))
|
||||
|
||||
# Display the Glance client on the selected server
|
||||
logger.info("Connect Glances client to the {} server".format(
|
||||
self.get_servers_list()[self.screen.active_server]['key']))
|
||||
|
||||
# Init the client
|
||||
args_server = self.args
|
||||
|
||||
# Overwrite connection setting
|
||||
args_server.client = self.get_servers_list()[self.screen.active_server]['ip']
|
||||
args_server.port = self.get_servers_list()[self.screen.active_server]['port']
|
||||
args_server.username = self.get_servers_list()[self.screen.active_server]['username']
|
||||
args_server.password = self.get_servers_list()[self.screen.active_server]['password']
|
||||
client = GlancesClient(config=self.config, args=args_server, return_to_browser=True)
|
||||
|
||||
# Test if client and server are in the same major version
|
||||
if not client.login():
|
||||
self.screen.display_popup(
|
||||
"Sorry, cannot connect to '{}'\n"
|
||||
"See 'glances.log' for more details".format(v['name']))
|
||||
|
||||
# Set the ONLINE status for the selected server
|
||||
self.set_in_selected('status', 'OFFLINE')
|
||||
else:
|
||||
# Start the client loop
|
||||
# Return connection type: 'glances' or 'snmp'
|
||||
connection_type = client.serve_forever()
|
||||
|
||||
try:
|
||||
logger.debug("Disconnect Glances client from the {} server".format(
|
||||
self.get_servers_list()[self.screen.active_server]['key']))
|
||||
except IndexError:
|
||||
# Server did not exist anymore
|
||||
pass
|
||||
else:
|
||||
# Set the ONLINE status for the selected server
|
||||
if connection_type == 'snmp':
|
||||
self.set_in_selected('status', 'SNMP')
|
||||
else:
|
||||
self.set_in_selected('status', 'ONLINE')
|
||||
|
||||
# Return to the browser (no server selected)
|
||||
self.screen.active_server = None
|
||||
# Loop
|
||||
self.__serve_forever()
|
||||
|
||||
def serve_forever(self):
|
||||
"""Wrapper to the serve_forever function.
|
||||
|
||||
@@ -28,12 +28,6 @@ import types
|
||||
|
||||
PY3 = sys.version_info[0] == 3
|
||||
|
||||
|
||||
def to_ascii(s):
|
||||
"""Convert the unicode 's' to a ASCII string
|
||||
Usefull to remove accent (diacritics)"""
|
||||
return unicodedata.normalize('NFKD', s).encode('ASCII', 'ignore')
|
||||
|
||||
if PY3:
|
||||
import queue
|
||||
from configparser import ConfigParser, NoOptionError, NoSectionError
|
||||
@@ -54,6 +48,11 @@ if PY3:
|
||||
viewvalues = operator.methodcaller('values')
|
||||
viewitems = operator.methodcaller('items')
|
||||
|
||||
def to_ascii(s):
|
||||
"""Convert the bytes string to a ASCII string
|
||||
Usefull to remove accent (diacritics)"""
|
||||
return str(s, 'utf-8')
|
||||
|
||||
def listitems(d):
|
||||
return list(d.items())
|
||||
|
||||
@@ -104,6 +103,11 @@ else:
|
||||
viewvalues = operator.methodcaller('viewvalues')
|
||||
viewitems = operator.methodcaller('viewitems')
|
||||
|
||||
def to_ascii(s):
|
||||
"""Convert the unicode 's' to a ASCII string
|
||||
Usefull to remove accent (diacritics)"""
|
||||
return unicodedata.normalize('NFKD', s).encode('ASCII', 'ignore')
|
||||
|
||||
def listitems(d):
|
||||
return d.items()
|
||||
|
||||
|
||||
@@ -24,7 +24,6 @@ import sys
|
||||
import multiprocessing
|
||||
from io import open
|
||||
|
||||
from glances import __appname__
|
||||
from glances.compat import ConfigParser, NoOptionError
|
||||
from glances.globals import BSD, LINUX, OSX, WINDOWS, sys_prefix
|
||||
from glances.logger import logger
|
||||
@@ -71,22 +70,18 @@ class Config(object):
|
||||
paths.append(
|
||||
os.path.join(os.environ.get('XDG_CONFIG_HOME') or
|
||||
os.path.expanduser('~/.config'),
|
||||
__appname__, self.config_filename))
|
||||
'glances', self.config_filename))
|
||||
if BSD:
|
||||
paths.append(
|
||||
os.path.join(sys.prefix, 'etc', __appname__, self.config_filename))
|
||||
paths.append(os.path.join(sys.prefix, 'etc', 'glances', self.config_filename))
|
||||
else:
|
||||
paths.append(
|
||||
os.path.join('/etc', __appname__, self.config_filename))
|
||||
paths.append(os.path.join('/etc/glances', self.config_filename))
|
||||
elif OSX:
|
||||
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))
|
||||
os.path.join(os.path.expanduser('~/Library/Application Support/glances'),
|
||||
self.config_filename))
|
||||
paths.append(os.path.join(sys_prefix, 'etc', 'glances', self.config_filename))
|
||||
elif WINDOWS:
|
||||
paths.append(
|
||||
os.path.join(os.environ.get('APPDATA'), __appname__, self.config_filename))
|
||||
paths.append(os.path.join(os.environ.get('APPDATA'), 'glances', self.config_filename))
|
||||
|
||||
return paths
|
||||
|
||||
@@ -172,6 +167,16 @@ class Config(object):
|
||||
self.set_default('memswap', 'warning', '70')
|
||||
self.set_default('memswap', 'critical', '90')
|
||||
|
||||
# NETWORK
|
||||
if not self.parser.has_section('network'):
|
||||
self.parser.add_section('network')
|
||||
self.set_default('network', 'rx_careful', '70')
|
||||
self.set_default('network', 'rx_warning', '80')
|
||||
self.set_default('network', 'rx_critical', '90')
|
||||
self.set_default('network', 'tx_careful', '70')
|
||||
self.set_default('network', 'tx_warning', '80')
|
||||
self.set_default('network', 'tx_critical', '90')
|
||||
|
||||
# FS
|
||||
if not self.parser.has_section('fs'):
|
||||
self.parser.add_section('fs')
|
||||
@@ -207,6 +212,15 @@ class Config(object):
|
||||
"""Return the loaded configuration file."""
|
||||
return self._loaded_config_file
|
||||
|
||||
def as_dict(self):
|
||||
"""Return the configuration as a dict"""
|
||||
dictionary = {}
|
||||
for section in self.parser.sections():
|
||||
dictionary[section] = {}
|
||||
for option in self.parser.options(section):
|
||||
dictionary[section][option] = self.parser.get(section, option)
|
||||
return dictionary
|
||||
|
||||
def sections(self):
|
||||
"""Return a list of all sections."""
|
||||
return self.parser.sections()
|
||||
@@ -231,6 +245,13 @@ class Config(object):
|
||||
except NoOptionError:
|
||||
return default
|
||||
|
||||
def get_int_value(self, section, option, default=0):
|
||||
"""Get the int value of an option, if it exists."""
|
||||
try:
|
||||
return self.parser.getint(section, option)
|
||||
except NoOptionError:
|
||||
return int(default)
|
||||
|
||||
def get_float_value(self, section, option, default=0.0):
|
||||
"""Get the float value of an option, if it exists."""
|
||||
try:
|
||||
|
||||
@@ -68,7 +68,8 @@ class Export(GlancesExport):
|
||||
plugins = stats.getAllPlugins()
|
||||
|
||||
# Init data with timestamp (issue#708)
|
||||
csv_header = ['timestamp']
|
||||
if self.first_line:
|
||||
csv_header = ['timestamp']
|
||||
csv_data = [time.strftime('%Y-%m-%d %H:%M:%S')]
|
||||
|
||||
# Loop over available plugin
|
||||
|
||||
@@ -64,7 +64,8 @@ class GlancesExport(object):
|
||||
'system',
|
||||
'uptime',
|
||||
'sensors',
|
||||
'docker']
|
||||
'docker',
|
||||
'uptime']
|
||||
|
||||
def get_item_key(self, item):
|
||||
"""Return the value of the item 'key'."""
|
||||
|
||||
122
glances/exports/glances_zeromq.py
Normal file
122
glances/exports/glances_zeromq.py
Normal file
@@ -0,0 +1,122 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
#
|
||||
# This file is part of Glances.
|
||||
#
|
||||
# Copyright (C) 2016 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/>.
|
||||
|
||||
"""ZeroMQ interface class."""
|
||||
|
||||
import sys
|
||||
import json
|
||||
import zmq
|
||||
from zmq.utils.strtypes import asbytes
|
||||
|
||||
from glances.compat import NoOptionError, NoSectionError, b
|
||||
from glances.logger import logger
|
||||
from glances.exports.glances_export import GlancesExport
|
||||
|
||||
|
||||
class Export(GlancesExport):
|
||||
|
||||
"""This class manages the ZeroMQ export module."""
|
||||
|
||||
def __init__(self, config=None, args=None):
|
||||
"""Init the ZeroMQ export IF."""
|
||||
super(Export, self).__init__(config=config, args=args)
|
||||
|
||||
# Load the ZeroMQ configuration file section ([export_zeromq])
|
||||
self.host = None
|
||||
self.port = None
|
||||
self.export_enable = self.load_conf()
|
||||
if not self.export_enable:
|
||||
sys.exit(2)
|
||||
|
||||
# Init the ZeroMQ context
|
||||
self.context = None
|
||||
self.client = self.init()
|
||||
|
||||
def load_conf(self, section="zeromq"):
|
||||
"""Load the ZeroMQ configuration in the Glances configuration file."""
|
||||
if self.config is None:
|
||||
return False
|
||||
try:
|
||||
self.host = self.config.get_value(section, 'host')
|
||||
self.port = self.config.get_value(section, 'port')
|
||||
self.prefix = str(self.config.get_value(section, 'prefix'))
|
||||
except NoSectionError:
|
||||
logger.critical("No ZeroMQ configuration found")
|
||||
return False
|
||||
except NoOptionError as e:
|
||||
logger.critical("Error in the ZeroMQ configuration (%s)" % e)
|
||||
return False
|
||||
else:
|
||||
logger.debug("Load ZeroMQ from the Glances configuration file")
|
||||
|
||||
return True
|
||||
|
||||
def init(self):
|
||||
"""Init the connection to the CouchDB server."""
|
||||
if not self.export_enable:
|
||||
return None
|
||||
|
||||
server_uri = 'tcp://{}:{}'.format(self.host, self.port)
|
||||
|
||||
try:
|
||||
self.context = zmq.Context()
|
||||
publisher = self.context.socket(zmq.PUB)
|
||||
publisher.bind(server_uri)
|
||||
except Exception as e:
|
||||
logger.critical("Cannot connect to ZeroMQ server %s (%s)" % (server_uri, e))
|
||||
sys.exit(2)
|
||||
else:
|
||||
logger.info("Connected to the ZeroMQ server %s" % server_uri)
|
||||
|
||||
return publisher
|
||||
|
||||
def exit(self):
|
||||
"""Close the socket and context"""
|
||||
if self.client is not None:
|
||||
self.client.close()
|
||||
if self.context is not None:
|
||||
self.context.destroy()
|
||||
|
||||
def export(self, name, columns, points):
|
||||
"""Write the points to the ZeroMQ server."""
|
||||
logger.debug("Export {} stats to ZeroMQ".format(name))
|
||||
|
||||
# Create DB input
|
||||
data = dict(zip(columns, points))
|
||||
|
||||
# Do not publish empty stats
|
||||
if data == {}:
|
||||
return False
|
||||
|
||||
# Glances envelopes the stats in a publish message with two frames:
|
||||
# - First frame containing the following prefix (STRING)
|
||||
# - Second frame with the Glances plugin name (STRING)
|
||||
# - Third frame with the Glances plugin stats (JSON)
|
||||
message = [b(self.prefix),
|
||||
b(name),
|
||||
asbytes(json.dumps(data))]
|
||||
|
||||
# Write data to the ZeroMQ bus
|
||||
# Result can be view: tcp://host:port
|
||||
try:
|
||||
self.client.send_multipart(message)
|
||||
except Exception as e:
|
||||
logger.error("Cannot export {} stats to ZeroMQ ({})".format(name, e))
|
||||
|
||||
return True
|
||||
@@ -22,66 +22,66 @@
|
||||
import logging
|
||||
import os
|
||||
import tempfile
|
||||
import json
|
||||
from logging.config import dictConfig
|
||||
|
||||
# Define the logging configuration
|
||||
LOGGING_CFG = {
|
||||
'version': 1,
|
||||
'disable_existing_loggers': False,
|
||||
'root': {
|
||||
'level': 'INFO',
|
||||
'handlers': ['file', 'console']
|
||||
"version": 1,
|
||||
"disable_existing_loggers": "False",
|
||||
"root": {
|
||||
"level": "INFO",
|
||||
"handlers": ["file", "console"]
|
||||
},
|
||||
'formatters': {
|
||||
'standard': {
|
||||
'format': '%(asctime)s -- %(levelname)s -- %(message)s'
|
||||
"formatters": {
|
||||
"standard": {
|
||||
"format": "%(asctime)s -- %(levelname)s -- %(message)s"
|
||||
},
|
||||
'short': {
|
||||
'format': '%(levelname)s: %(message)s'
|
||||
"short": {
|
||||
"format": "%(levelname)s: %(message)s"
|
||||
},
|
||||
'free': {
|
||||
'format': '%(message)s'
|
||||
"free": {
|
||||
"format": "%(message)s"
|
||||
}
|
||||
},
|
||||
'handlers': {
|
||||
'file': {
|
||||
'level': 'DEBUG',
|
||||
'class': 'logging.handlers.RotatingFileHandler',
|
||||
'formatter': 'standard',
|
||||
# http://stackoverflow.com/questions/847850/cross-platform-way-of-getting-temp-directory-in-python
|
||||
"handlers": {
|
||||
"file": {
|
||||
"level": "DEBUG",
|
||||
"class": "logging.handlers.RotatingFileHandler",
|
||||
"formatter": "standard",
|
||||
'filename': os.path.join(tempfile.gettempdir(), 'glances.log')
|
||||
},
|
||||
'console': {
|
||||
'level': 'CRITICAL',
|
||||
'class': 'logging.StreamHandler',
|
||||
'formatter': 'free'
|
||||
"console": {
|
||||
"level": "CRITICAL",
|
||||
"class": "logging.StreamHandler",
|
||||
"formatter": "free"
|
||||
}
|
||||
},
|
||||
'loggers': {
|
||||
'debug': {
|
||||
'handlers': ['file', 'console'],
|
||||
'level': 'DEBUG',
|
||||
"loggers": {
|
||||
"debug": {
|
||||
"handlers": ["file", "console"],
|
||||
"level": "DEBUG"
|
||||
},
|
||||
'verbose': {
|
||||
'handlers': ['file', 'console'],
|
||||
'level': 'INFO'
|
||||
"verbose": {
|
||||
"handlers": ["file", "console"],
|
||||
"level": "INFO"
|
||||
},
|
||||
'standard': {
|
||||
'handlers': ['file'],
|
||||
'level': 'INFO'
|
||||
"standard": {
|
||||
"handlers": ["file"],
|
||||
"level": "INFO"
|
||||
},
|
||||
'requests': {
|
||||
'handlers': ['file', 'console'],
|
||||
'level': 'ERROR',
|
||||
"requests": {
|
||||
"handlers": ["file", "console"],
|
||||
"level": "ERROR"
|
||||
},
|
||||
'elasticsearch': {
|
||||
'handlers': ['file', 'console'],
|
||||
'level': 'ERROR',
|
||||
},
|
||||
'elasticsearch.trace': {
|
||||
'handlers': ['file', 'console'],
|
||||
'level': 'ERROR',
|
||||
"elasticsearch": {
|
||||
"handlers": ["file", "console"],
|
||||
"level": "ERROR"
|
||||
},
|
||||
"elasticsearch.trace": {
|
||||
"handlers": ["file", "console"],
|
||||
"level": "ERROR"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -98,12 +98,31 @@ def tempfile_name():
|
||||
return ret
|
||||
|
||||
|
||||
def glances_logger():
|
||||
"""Build and return the logger."""
|
||||
temp_path = tempfile_name()
|
||||
def glances_logger(env_key='LOG_CFG'):
|
||||
"""Build and return the logger.
|
||||
|
||||
env_key define the env var where a path to a specific JSON logger
|
||||
could be defined
|
||||
|
||||
:return: logger -- Logger instance
|
||||
"""
|
||||
_logger = logging.getLogger()
|
||||
LOGGING_CFG['handlers']['file']['filename'] = temp_path
|
||||
dictConfig(LOGGING_CFG)
|
||||
|
||||
# Overwrite the default logger file
|
||||
LOGGING_CFG['handlers']['file']['filename'] = tempfile_name()
|
||||
|
||||
# By default, use the LOGGING_CFG lgger configuration
|
||||
config = LOGGING_CFG
|
||||
|
||||
# Check if a specific configuration is available
|
||||
user_file = os.getenv(env_key, None)
|
||||
if user_file and os.path.exists(user_file):
|
||||
# A user file as been defined. Use it...
|
||||
with open(user_file, 'rt') as f:
|
||||
config = json.load(f)
|
||||
|
||||
# Load the configuration
|
||||
dictConfig(config)
|
||||
|
||||
return _logger
|
||||
|
||||
|
||||
@@ -147,7 +147,7 @@ class GlancesLogs(object):
|
||||
1, # COUNT
|
||||
[], # TOP 3 PROCESS LIST
|
||||
proc_desc, # MONITORED PROCESSES DESC
|
||||
'cpu_percent'] # TOP PROCESS SORTKEY
|
||||
glances_processes.sort_key] # TOP PROCESS SORTKEY
|
||||
|
||||
# Add the item to the list
|
||||
self.logs_list.insert(0, item)
|
||||
|
||||
138
glances/main.py
138
glances/main.py
@@ -2,7 +2,7 @@
|
||||
#
|
||||
# This file is part of Glances.
|
||||
#
|
||||
# Copyright (C) 2015 Nicolargo <nicolas@nicolargo.com>
|
||||
# Copyright (C) 2016 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
|
||||
@@ -24,8 +24,8 @@ import os
|
||||
import sys
|
||||
import tempfile
|
||||
|
||||
from glances import __appname__, __version__, psutil_version
|
||||
from glances.compat import input, NoOptionError, NoSectionError
|
||||
from glances import __version__, psutil_version
|
||||
from glances.compat import input
|
||||
from glances.config import Config
|
||||
from glances.globals import LINUX, WINDOWS
|
||||
from glances.logger import logger
|
||||
@@ -61,7 +61,7 @@ Monitor local machine with the Web interface (Web UI):\n\
|
||||
Glances web server started on http://0.0.0.0:61208/\n\
|
||||
\n\
|
||||
Monitor local machine and export stats to a CSV file (standalone mode):\n\
|
||||
$ glances --export-csv\n\
|
||||
$ glances --export-csv /tmp/glances.csv\n\
|
||||
\n\
|
||||
Monitor local machine and export stats to a InfluxDB server with 5s refresh time (standalone mode):\n\
|
||||
$ glances -t 5 --export-influxdb\n\
|
||||
@@ -88,7 +88,7 @@ Start the client browser (browser mode):\n\
|
||||
"""Init all the command line arguments."""
|
||||
version = "Glances v" + __version__ + " with psutil v" + psutil_version
|
||||
parser = argparse.ArgumentParser(
|
||||
prog=__appname__,
|
||||
prog='glances',
|
||||
conflict_handler='resolve',
|
||||
formatter_class=argparse.RawDescriptionHelpFormatter,
|
||||
epilog=self.example_of_use)
|
||||
@@ -99,58 +99,64 @@ Start the client browser (browser mode):\n\
|
||||
parser.add_argument('-C', '--config', dest='conf_file',
|
||||
help='path to the configuration file')
|
||||
# Enable or disable option on startup
|
||||
parser.add_argument('-3', '--disable-quicklook', action='store_true', default=False,
|
||||
dest='disable_quicklook', help='disable quick look module')
|
||||
parser.add_argument('-4', '--full-quicklook', action='store_true', default=False,
|
||||
dest='full_quicklook', help='disable all but quick look and load')
|
||||
parser.add_argument('--disable-alert', action='store_true', default=False,
|
||||
dest='disable_alert', help='disable alert module')
|
||||
parser.add_argument('--disable-amps', action='store_true', default=False,
|
||||
dest='disable_amps', help='disable applications monitoring process (AMP) module')
|
||||
parser.add_argument('--disable-cpu', action='store_true', default=False,
|
||||
dest='disable_cpu', help='disable CPU module')
|
||||
parser.add_argument('--disable-mem', action='store_true', default=False,
|
||||
dest='disable_mem', help='disable memory module')
|
||||
parser.add_argument('--disable-swap', action='store_true', default=False,
|
||||
dest='disable_swap', help='disable swap module')
|
||||
parser.add_argument('--disable-diskio', action='store_true', default=False,
|
||||
dest='disable_diskio', help='disable disk I/O module')
|
||||
parser.add_argument('--disable-docker', action='store_true', default=False,
|
||||
dest='disable_docker', help='disable Docker module')
|
||||
parser.add_argument('--disable-folders', action='store_true', default=False,
|
||||
dest='disable_folders', help='disable folder module')
|
||||
parser.add_argument('--disable-fs', action='store_true', default=False,
|
||||
dest='disable_fs', help='disable filesystem module')
|
||||
parser.add_argument('--disable-hddtemp', action='store_true', default=False,
|
||||
dest='disable_hddtemp', help='disable HD temperature module')
|
||||
parser.add_argument('--disable-ip', action='store_true', default=False,
|
||||
dest='disable_ip', help='disable IP module')
|
||||
parser.add_argument('--disable-load', action='store_true', default=False,
|
||||
dest='disable_load', help='disable load module')
|
||||
parser.add_argument('--disable-mem', action='store_true', default=False,
|
||||
dest='disable_mem', help='disable memory module')
|
||||
parser.add_argument('--disable-memswap', action='store_true', default=False,
|
||||
dest='disable_memswap', help='disable memory swap module')
|
||||
parser.add_argument('--disable-network', action='store_true', default=False,
|
||||
dest='disable_network', help='disable network module')
|
||||
parser.add_argument('--disable-ports', action='store_true', default=False,
|
||||
dest='disable_ports', help='disable ports scanner module')
|
||||
parser.add_argument('--disable-ip', action='store_true', default=False,
|
||||
dest='disable_ip', help='disable IP module')
|
||||
parser.add_argument('--disable-diskio', action='store_true', default=False,
|
||||
dest='disable_diskio', help='disable disk I/O module')
|
||||
parser.add_argument('--disable-irq', action='store_true', default=False,
|
||||
dest='disable_irq', help='disable IRQ module'),
|
||||
parser.add_argument('--disable-fs', action='store_true', default=False,
|
||||
dest='disable_fs', help='disable filesystem module')
|
||||
parser.add_argument('--disable-folder', action='store_true', default=False,
|
||||
dest='disable_folder', help='disable folder module')
|
||||
parser.add_argument('--disable-sensors', action='store_true', default=False,
|
||||
dest='disable_sensors', help='disable sensors module')
|
||||
parser.add_argument('--disable-hddtemp', action='store_true', default=False,
|
||||
dest='disable_hddtemp', help='disable HD temperature module')
|
||||
parser.add_argument('--disable-process', action='store_true', default=False,
|
||||
dest='disable_process', help='disable process module')
|
||||
parser.add_argument('--disable-raid', action='store_true', default=False,
|
||||
dest='disable_raid', help='disable RAID module')
|
||||
parser.add_argument('--disable-docker', action='store_true', default=False,
|
||||
dest='disable_docker', help='disable Docker module')
|
||||
parser.add_argument('-5', '--disable-top', action='store_true',
|
||||
default=False, dest='disable_top',
|
||||
help='disable top menu (QL, CPU, MEM, SWAP and LOAD)')
|
||||
parser.add_argument('--disable-sensors', action='store_true', default=False,
|
||||
dest='disable_sensors', help='disable sensors module')
|
||||
parser.add_argument('--disable-wifi', action='store_true', default=False,
|
||||
dest='disable_wifi', help='disable wifi module')
|
||||
parser.add_argument('-0', '--disable-irix', action='store_true', default=False,
|
||||
dest='disable_irix', help='task\'s cpu usage will be divided by the total number of CPUs')
|
||||
parser.add_argument('-1', '--percpu', action='store_true', default=False,
|
||||
dest='percpu', help='start Glances in per CPU mode')
|
||||
parser.add_argument('-2', '--disable-left-sidebar', action='store_true',
|
||||
default=False, dest='disable_left_sidebar',
|
||||
help='disable network, disk I/O, FS and sensors modules')
|
||||
parser.add_argument('--disable-process', action='store_true', default=False,
|
||||
dest='disable_process', help='disable process module')
|
||||
parser.add_argument('--disable-amps', action='store_true', default=False,
|
||||
dest='disable_amps', help='disable applications monitoring process (AMP) module')
|
||||
parser.add_argument('--disable-log', action='store_true', default=False,
|
||||
dest='disable_log', help='disable log module')
|
||||
parser.add_argument('-3', '--disable-quicklook', action='store_true', default=False,
|
||||
dest='disable_quicklook', help='disable quick look module')
|
||||
parser.add_argument('-4', '--full-quicklook', action='store_true', default=False,
|
||||
dest='full_quicklook', help='disable all but quick look and load')
|
||||
parser.add_argument('-5', '--disable-top', action='store_true',
|
||||
default=False, dest='disable_top',
|
||||
help='disable top menu (QL, CPU, MEM, SWAP and LOAD)')
|
||||
parser.add_argument('--disable-history', action='store_true', default=False,
|
||||
dest='disable_history', help='disable stats history')
|
||||
parser.add_argument('--disable-bold', action='store_true', default=False,
|
||||
dest='disable_bold', help='disable bold mode in the terminal')
|
||||
parser.add_argument('--disable-bg', action='store_true', default=False,
|
||||
dest='disable_bg', help='disable background colors in the terminal')
|
||||
parser.add_argument('--enable-irq', action='store_true', default=False,
|
||||
dest='enable_irq', help='enable IRQ module'),
|
||||
parser.add_argument('--enable-process-extended', action='store_true', default=False,
|
||||
dest='enable_process_extended', help='enable extended stats on top process')
|
||||
# Export modules feature
|
||||
@@ -176,6 +182,8 @@ Start the client browser (browser mode):\n\
|
||||
dest='export_riemann', help='export stats to riemann broker (bernhard lib needed)')
|
||||
parser.add_argument('--export-couchdb', action='store_true', default=False,
|
||||
dest='export_couchdb', help='export stats to a CouchDB server (couch lib needed)')
|
||||
parser.add_argument('--export-zeromq', action='store_true', default=False,
|
||||
dest='export_zeromq', help='export stats to a ZeroMQ server (pyzmq lib needed)')
|
||||
# Client/Server option
|
||||
parser.add_argument('-c', '--client', dest='client',
|
||||
help='connect to a Glances server by IPv4/IPv6 address or hostname')
|
||||
@@ -211,6 +219,8 @@ Start the client browser (browser mode):\n\
|
||||
dest='webserver', help='run Glances in web server mode (bottle needed)')
|
||||
parser.add_argument('--cached-time', default=self.cached_time, type=int,
|
||||
dest='cached_time', help='set the server cache time [default: {} sec]'.format(self.cached_time))
|
||||
parser.add_argument('--open-web-browser', action='store_true', default=False,
|
||||
dest='open_web_browser', help='try to open the Web UI in the default Web browser')
|
||||
# Display options
|
||||
parser.add_argument('-q', '--quiet', default=False, action='store_true',
|
||||
dest='quiet', help='do not display the curses interface')
|
||||
@@ -218,8 +228,6 @@ Start the client browser (browser mode):\n\
|
||||
dest='process_filter', help='set the process filter pattern (regular expression)')
|
||||
parser.add_argument('--process-short-name', action='store_true', default=False,
|
||||
dest='process_short_name', help='force short name for processes name')
|
||||
parser.add_argument('-0', '--disable-irix', action='store_true', default=False,
|
||||
dest='disable_irix', help='task\'s cpu usage will be divided by the total number of CPUs')
|
||||
if not WINDOWS:
|
||||
parser.add_argument('--hide-kernel-threads', action='store_true', default=False,
|
||||
dest='no_kernel_threads', help='hide kernel threads in process list')
|
||||
@@ -234,8 +242,6 @@ Start the client browser (browser mode):\n\
|
||||
dest='diskio_iops', help='show IO per second in the DiskIO plugin')
|
||||
parser.add_argument('--fahrenheit', action='store_true', default=False,
|
||||
dest='fahrenheit', help='display temperature in Fahrenheit (default is Celsius)')
|
||||
parser.add_argument('-1', '--percpu', action='store_true', default=False,
|
||||
dest='percpu', help='start Glances in per CPU mode')
|
||||
parser.add_argument('--fs-free-space', action='store_true', default=False,
|
||||
dest='fs_free_space', help='display FS free space instead of used')
|
||||
parser.add_argument('--theme-white', action='store_true', default=False,
|
||||
@@ -278,11 +284,14 @@ Start the client browser (browser mode):\n\
|
||||
args.password_prompt = True
|
||||
# Prompt username
|
||||
if args.server:
|
||||
args.username = self.__get_username(description='Define the Glances server username: ')
|
||||
args.username = self.__get_username(
|
||||
description='Define the Glances server username: ')
|
||||
elif args.webserver:
|
||||
args.username = self.__get_username(description='Define the Glances webserver username: ')
|
||||
args.username = self.__get_username(
|
||||
description='Define the Glances webserver username: ')
|
||||
elif args.client:
|
||||
args.username = self.__get_username(description='Enter the Glances server username: ')
|
||||
args.username = self.__get_username(
|
||||
description='Enter the Glances server username: ')
|
||||
else:
|
||||
# Default user name is 'glances'
|
||||
args.username = self.username
|
||||
@@ -291,17 +300,20 @@ Start the client browser (browser mode):\n\
|
||||
# Interactive or file password
|
||||
if args.server:
|
||||
args.password = self.__get_password(
|
||||
description='Define the Glances server password ({} username): '.format(args.username),
|
||||
description='Define the Glances server password ({} username): '.format(
|
||||
args.username),
|
||||
confirm=True,
|
||||
username=args.username)
|
||||
elif args.webserver:
|
||||
args.password = self.__get_password(
|
||||
description='Define the Glances webserver password ({} username): '.format(args.username),
|
||||
description='Define the Glances webserver password ({} username): '.format(
|
||||
args.username),
|
||||
confirm=True,
|
||||
username=args.username)
|
||||
elif args.client:
|
||||
args.password = self.__get_password(
|
||||
description='Enter the Glances server password ({} username): '.format(args.username),
|
||||
description='Enter the Glances server password ({} username): '.format(
|
||||
args.username),
|
||||
clear=True,
|
||||
username=args.username)
|
||||
else:
|
||||
@@ -321,7 +333,7 @@ Start the client browser (browser mode):\n\
|
||||
args.disable_quicklook = False
|
||||
args.disable_cpu = True
|
||||
args.disable_mem = True
|
||||
args.disable_swap = True
|
||||
args.disable_memswap = True
|
||||
args.disable_load = False
|
||||
|
||||
# Manage disable_top option
|
||||
@@ -330,7 +342,7 @@ Start the client browser (browser mode):\n\
|
||||
args.disable_quicklook = True
|
||||
args.disable_cpu = True
|
||||
args.disable_mem = True
|
||||
args.disable_swap = True
|
||||
args.disable_memswap = True
|
||||
args.disable_load = True
|
||||
|
||||
# Control parameter and exit if it is not OK
|
||||
@@ -338,28 +350,32 @@ Start the client browser (browser mode):\n\
|
||||
|
||||
# Export is only available in standalone or client mode (issue #614)
|
||||
export_tag = args.export_csv or \
|
||||
args.export_elasticsearch or \
|
||||
args.export_statsd or \
|
||||
args.export_influxdb or \
|
||||
args.export_cassandra or \
|
||||
args.export_opentsdb or \
|
||||
args.export_rabbitmq or \
|
||||
args.export_couchdb
|
||||
args.export_elasticsearch or \
|
||||
args.export_statsd or \
|
||||
args.export_influxdb or \
|
||||
args.export_cassandra or \
|
||||
args.export_opentsdb or \
|
||||
args.export_rabbitmq or \
|
||||
args.export_couchdb
|
||||
if not (self.is_standalone() or self.is_client()) and export_tag:
|
||||
logger.critical("Export is only available in standalone or client mode")
|
||||
logger.critical(
|
||||
"Export is only available in standalone or client mode")
|
||||
sys.exit(2)
|
||||
|
||||
# Filter is only available in standalone mode
|
||||
if args.process_filter is not None and not self.is_standalone():
|
||||
logger.critical("Process filter is only available in standalone mode")
|
||||
logger.critical(
|
||||
"Process filter is only available in standalone mode")
|
||||
sys.exit(2)
|
||||
|
||||
# Check graph output path
|
||||
if args.export_graph and args.path_graph is not None:
|
||||
if not os.access(args.path_graph, os.W_OK):
|
||||
logger.critical("Graphs output path {0} do not exist or is not writable".format(args.path_graph))
|
||||
logger.critical(
|
||||
"Graphs output path {0} do not exist or is not writable".format(args.path_graph))
|
||||
sys.exit(2)
|
||||
logger.debug("Graphs output path is set to {0}".format(args.path_graph))
|
||||
logger.debug(
|
||||
"Graphs output path is set to {0}".format(args.path_graph))
|
||||
|
||||
# For export graph, history is mandatory
|
||||
if args.export_graph and args.disable_history:
|
||||
|
||||
@@ -32,7 +32,7 @@ except ImportError:
|
||||
else:
|
||||
outdated_tag = True
|
||||
|
||||
from glances import __version__, __appname__
|
||||
from glances import __version__
|
||||
from glances.globals import BSD, LINUX, OSX, WINDOWS
|
||||
from glances.logger import logger
|
||||
|
||||
@@ -155,12 +155,11 @@ class Outdated(object):
|
||||
if LINUX or BSD:
|
||||
return os.path.join(os.environ.get('XDG_CONFIG_HOME') or
|
||||
os.path.expanduser('~/.config'),
|
||||
__appname__)
|
||||
'glances')
|
||||
elif OSX:
|
||||
return os.path.join(os.path.expanduser('~/Library/Application Support/'),
|
||||
__appname__)
|
||||
return os.path.expanduser('~/Library/Application Support/glances')
|
||||
elif WINDOWS:
|
||||
return os.path.join(os.environ.get('APPDATA'), __appname__)
|
||||
return os.path.join(os.environ.get('APPDATA'), 'glances')
|
||||
|
||||
def _update_pypi_version(self):
|
||||
"""Get the latest Pypi version (as a string) via the Restful JSON API"""
|
||||
|
||||
@@ -24,8 +24,10 @@ import os
|
||||
import sys
|
||||
import tempfile
|
||||
from io import open
|
||||
import webbrowser
|
||||
|
||||
from glances.timer import Timer
|
||||
from glances.globals import WINDOWS
|
||||
from glances.logger import logger
|
||||
|
||||
try:
|
||||
@@ -39,7 +41,10 @@ class GlancesBottle(object):
|
||||
|
||||
"""This class manages the Bottle Web server."""
|
||||
|
||||
def __init__(self, args=None):
|
||||
def __init__(self, config=None, args=None):
|
||||
# Init config
|
||||
self.config = config
|
||||
|
||||
# Init args
|
||||
self.args = args
|
||||
|
||||
@@ -89,6 +94,8 @@ class GlancesBottle(object):
|
||||
self._app.route('/<refresh_time:int>', method=["GET"], callback=self._index)
|
||||
|
||||
# REST API
|
||||
self._app.route('/api/2/config', method="GET", callback=self._api_config)
|
||||
self._app.route('/api/2/config/<item>', method="GET", callback=self._api_config_item)
|
||||
self._app.route('/api/2/args', method="GET", callback=self._api_args)
|
||||
self._app.route('/api/2/args/<item>', method="GET", callback=self._api_args_item)
|
||||
self._app.route('/api/2/help', method="GET", callback=self._api_help)
|
||||
@@ -117,9 +124,19 @@ class GlancesBottle(object):
|
||||
self.plugins_list = self.stats.getAllPlugins()
|
||||
|
||||
# Bind the Bottle TCP address/port
|
||||
bindmsg = 'Glances web server started on http://{}:{}/'.format(self.args.bind_address, self.args.port)
|
||||
bindurl = 'http://{}:{}/'.format(self.args.bind_address,
|
||||
self.args.port)
|
||||
bindmsg = 'Glances web server started on {}'.format(bindurl)
|
||||
logger.info(bindmsg)
|
||||
print(bindmsg)
|
||||
if self.args.open_web_browser:
|
||||
# Implementation of the issue #946
|
||||
# Try to open the Glances Web UI in the default Web browser if:
|
||||
# 1) --open-web-browser option is used
|
||||
# 2) Glances standalone mode is running on Windows OS
|
||||
webbrowser.open(bindurl,
|
||||
new=2,
|
||||
autoraise=1)
|
||||
self._app.run(host=self.args.bind_address, port=self.args.port, quiet=not self.args.debug)
|
||||
|
||||
def end(self):
|
||||
@@ -407,6 +424,43 @@ class GlancesBottle(object):
|
||||
"""
|
||||
return self._api_itemvalue(plugin, item, value)
|
||||
|
||||
def _api_config(self):
|
||||
"""Glances API RESTFul implementation.
|
||||
|
||||
Return the JSON representation of the Glances configuration file
|
||||
HTTP/200 if OK
|
||||
HTTP/404 if others error
|
||||
"""
|
||||
response.content_type = 'application/json'
|
||||
|
||||
try:
|
||||
# Get the JSON value of the config' dict
|
||||
args_json = json.dumps(self.config.as_dict())
|
||||
except Exception as e:
|
||||
abort(404, "Cannot get config (%s)" % str(e))
|
||||
return args_json
|
||||
|
||||
def _api_config_item(self, item):
|
||||
"""Glances API RESTFul implementation.
|
||||
|
||||
Return the JSON representation of the Glances configuration item
|
||||
HTTP/200 if OK
|
||||
HTTP/400 if item is not found
|
||||
HTTP/404 if others error
|
||||
"""
|
||||
response.content_type = 'application/json'
|
||||
|
||||
config_dict = self.config.as_dict()
|
||||
if item not in config_dict:
|
||||
abort(400, "Unknown configuration item %s" % item)
|
||||
|
||||
try:
|
||||
# Get the JSON value of the config' dict
|
||||
args_json = json.dumps(config_dict[item])
|
||||
except Exception as e:
|
||||
abort(404, "Cannot get config item (%s)" % str(e))
|
||||
return args_json
|
||||
|
||||
def _api_args(self):
|
||||
"""Glances API RESTFul implementation.
|
||||
|
||||
@@ -436,7 +490,7 @@ class GlancesBottle(object):
|
||||
response.content_type = 'application/json'
|
||||
|
||||
if item not in self.args:
|
||||
abort(400, "Unknown item %s" % item)
|
||||
abort(400, "Unknown argument item %s" % item)
|
||||
|
||||
try:
|
||||
# Get the JSON value of the args' dict
|
||||
|
||||
@@ -51,6 +51,45 @@ class _GlancesCurses(object):
|
||||
Note: It is a private class, use GlancesCursesClient or GlancesCursesBrowser.
|
||||
"""
|
||||
|
||||
_hotkeys = {
|
||||
'0': {'switch': 'disable_irix'},
|
||||
'1': {'switch': 'percpu'},
|
||||
'2': {'switch': 'disable_left_sidebar'},
|
||||
'3': {'switch': 'disable_quicklook'},
|
||||
'4': {'switch': 'full_quicklook'},
|
||||
'5': {'switch': 'disable_top'},
|
||||
'/': {'switch': 'process_short_name'},
|
||||
'd': {'switch': 'disable_diskio'},
|
||||
'A': {'switch': 'disable_amps'},
|
||||
'b': {'switch': 'byte'},
|
||||
'B': {'switch': 'diskio_iops'},
|
||||
'D': {'switch': 'disable_docker'},
|
||||
'e': {'switch': 'enable_process_extended'},
|
||||
'F': {'switch': 'fs_free_space'},
|
||||
'h': {'switch': 'help_tag'},
|
||||
'I': {'switch': 'disable_ip'},
|
||||
'l': {'switch': 'disable_alert'},
|
||||
'M': {'switch': 'reset_minmax_tag'},
|
||||
'n': {'switch': 'disable_network'},
|
||||
'P': {'switch': 'disable_ports'},
|
||||
'Q': {'switch': 'enable_irq'},
|
||||
'r': {'switch': 'reset_history_tag'},
|
||||
'R': {'switch': 'disable_raid'},
|
||||
's': {'switch': 'disable_sensors'},
|
||||
'T': {'switch': 'network_sum'},
|
||||
'U': {'switch': 'network_cumul'},
|
||||
'W': {'switch': 'disable_wifi'},
|
||||
# Processes sort hotkeys
|
||||
'a': {'auto_sort': True, 'sort_key': 'cpu_percent'},
|
||||
'c': {'auto_sort': False, 'sort_key': 'cpu_percent'},
|
||||
'i': {'auto_sort': False, 'sort_key': 'io_counters'},
|
||||
'm': {'auto_sort': False, 'sort_key': 'memory_percent'},
|
||||
'p': {'auto_sort': False, 'sort_key': 'name'},
|
||||
't': {'auto_sort': False, 'sort_key': 'cpu_times'},
|
||||
'u': {'auto_sort': False, 'sort_key': 'username'},
|
||||
'c': {'auto_sort': False, 'sort_key': 'cpu_percent'}
|
||||
}
|
||||
|
||||
def __init__(self, config=None, args=None):
|
||||
# Init
|
||||
self.config = config
|
||||
@@ -73,7 +112,6 @@ class _GlancesCurses(object):
|
||||
# Load the 'outputs' section of the configuration file
|
||||
# - Init the theme (default is black)
|
||||
self.theme = {'name': 'black'}
|
||||
self.load_config(self.config)
|
||||
|
||||
# Init cursor
|
||||
self._init_cursor()
|
||||
@@ -286,7 +324,23 @@ class _GlancesCurses(object):
|
||||
# Catch the pressed key
|
||||
self.pressedkey = self.get_key(self.term_window)
|
||||
|
||||
# Actions...
|
||||
# Actions (available in the global hotkey dict)...
|
||||
for hotkey in self._hotkeys:
|
||||
if self.pressedkey == ord(hotkey) and 'switch' in self._hotkeys[hotkey]:
|
||||
setattr(self.args,
|
||||
self._hotkeys[hotkey]['switch'],
|
||||
not getattr(self.args,
|
||||
self._hotkeys[hotkey]['switch']))
|
||||
if self.pressedkey == ord(hotkey) and 'auto_sort' in self._hotkeys[hotkey]:
|
||||
setattr(glances_processes,
|
||||
'auto_sort',
|
||||
self._hotkeys[hotkey]['auto_sort'])
|
||||
if self.pressedkey == ord(hotkey) and 'sort_key' in self._hotkeys[hotkey]:
|
||||
setattr(glances_processes,
|
||||
'sort_key',
|
||||
self._hotkeys[hotkey]['sort_key'])
|
||||
|
||||
# Other actions...
|
||||
if self.pressedkey == ord('\x1b') or self.pressedkey == ord('q'):
|
||||
# 'ESC'|'q' > Quit
|
||||
if return_to_browser:
|
||||
@@ -295,152 +349,29 @@ class _GlancesCurses(object):
|
||||
self.end()
|
||||
logger.info("Stop Glances")
|
||||
sys.exit(0)
|
||||
elif self.pressedkey == 10:
|
||||
elif self.pressedkey == ord('\n'):
|
||||
# 'ENTER' > Edit the process filter
|
||||
self.edit_filter = not self.edit_filter
|
||||
elif self.pressedkey == ord('0'):
|
||||
# '0' > Switch between IRIX and Solaris mode
|
||||
self.args.disable_irix = not self.args.disable_irix
|
||||
elif self.pressedkey == ord('1'):
|
||||
# '1' > Switch between CPU and PerCPU information
|
||||
self.args.percpu = not self.args.percpu
|
||||
elif self.pressedkey == ord('2'):
|
||||
# '2' > Enable/disable left sidebar
|
||||
self.args.disable_left_sidebar = not self.args.disable_left_sidebar
|
||||
elif self.pressedkey == ord('3'):
|
||||
# '3' > Enable/disable quicklook
|
||||
self.args.disable_quicklook = not self.args.disable_quicklook
|
||||
elif self.pressedkey == ord('4'):
|
||||
# '4' > Enable/disable all but quick look and load
|
||||
self.args.full_quicklook = not self.args.full_quicklook
|
||||
if self.args.full_quicklook:
|
||||
self.args.disable_quicklook = False
|
||||
self.args.disable_cpu = True
|
||||
self.args.disable_mem = True
|
||||
self.args.disable_swap = True
|
||||
self.enable_fullquicklook()
|
||||
else:
|
||||
self.args.disable_quicklook = False
|
||||
self.args.disable_cpu = False
|
||||
self.args.disable_mem = False
|
||||
self.args.disable_swap = False
|
||||
self.disable_fullquicklook()
|
||||
elif self.pressedkey == ord('5'):
|
||||
# '5' > Enable/disable top menu
|
||||
logger.info(self.args.disable_top)
|
||||
self.args.disable_top = not self.args.disable_top
|
||||
if self.args.disable_top:
|
||||
self.args.disable_quicklook = True
|
||||
self.args.disable_cpu = True
|
||||
self.args.disable_mem = True
|
||||
self.args.disable_swap = True
|
||||
self.args.disable_load = True
|
||||
self.disable_top()
|
||||
else:
|
||||
self.args.disable_quicklook = False
|
||||
self.args.disable_cpu = False
|
||||
self.args.disable_mem = False
|
||||
self.args.disable_swap = False
|
||||
self.args.disable_load = False
|
||||
elif self.pressedkey == ord('/'):
|
||||
# '/' > Switch between short/long name for processes
|
||||
self.args.process_short_name = not self.args.process_short_name
|
||||
elif self.pressedkey == ord('a'):
|
||||
# 'a' > Sort processes automatically and reset to 'cpu_percent'
|
||||
glances_processes.auto_sort = True
|
||||
glances_processes.sort_key = 'cpu_percent'
|
||||
elif self.pressedkey == ord('A'):
|
||||
# 'A' > enable/disable AMP module
|
||||
self.args.disable_amps = not self.args.disable_amps
|
||||
elif self.pressedkey == ord('b'):
|
||||
# 'b' > Switch between bit/s and Byte/s for network IO
|
||||
self.args.byte = not self.args.byte
|
||||
elif self.pressedkey == ord('B'):
|
||||
# 'B' > Switch between bit/s and IO/s for Disk IO
|
||||
self.args.diskio_iops = not self.args.diskio_iops
|
||||
elif self.pressedkey == ord('c'):
|
||||
# 'c' > Sort processes by CPU usage
|
||||
glances_processes.auto_sort = False
|
||||
glances_processes.sort_key = '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('D'):
|
||||
# 'D' > Show/hide Docker stats
|
||||
self.args.disable_docker = not self.args.disable_docker
|
||||
elif self.pressedkey == ord('e'):
|
||||
# 'e' > Enable/Disable extended stats for top process
|
||||
self.args.enable_process_extended = not self.args.enable_process_extended
|
||||
if not self.args.enable_process_extended:
|
||||
glances_processes.disable_extended()
|
||||
else:
|
||||
glances_processes.enable_extended()
|
||||
self.enable_top()
|
||||
elif self.pressedkey == ord('E'):
|
||||
# 'E' > Erase the process filter
|
||||
logger.info("Erase process filter")
|
||||
glances_processes.process_filter = None
|
||||
elif self.pressedkey == ord('F'):
|
||||
# 'F' > Switch between FS available and free space
|
||||
self.args.fs_free_space = not self.args.fs_free_space
|
||||
elif self.pressedkey == ord('f'):
|
||||
# 'f' > Show/hide fs / folder stats
|
||||
self.args.disable_fs = not self.args.disable_fs
|
||||
self.args.disable_folder = not self.args.disable_folder
|
||||
self.args.disable_folders = not self.args.disable_folders
|
||||
elif self.pressedkey == ord('g'):
|
||||
# 'g' > Export graphs to file
|
||||
# 'g' > Generate graph from history
|
||||
self.graph_tag = not self.graph_tag
|
||||
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)
|
||||
glances_processes.auto_sort = False
|
||||
glances_processes.sort_key = 'io_counters'
|
||||
elif self.pressedkey == ord('I'):
|
||||
# 'I' > Show/hide IP module
|
||||
self.args.disable_ip = not self.args.disable_ip
|
||||
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
|
||||
glances_processes.auto_sort = False
|
||||
glances_processes.sort_key = 'memory_percent'
|
||||
elif self.pressedkey == ord('M'):
|
||||
# 'M' > Reset processes summary min/max
|
||||
self.args.reset_minmax_tag = not self.args.reset_minmax_tag
|
||||
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
|
||||
glances_processes.auto_sort = False
|
||||
glances_processes.sort_key = 'name'
|
||||
elif self.pressedkey == ord('P'):
|
||||
# 'P' > Disable ports scan plugins
|
||||
self.args.disable_ports = not self.args.disable_ports
|
||||
elif self.pressedkey == ord('Q'):
|
||||
self.args.disable_irq = not self.args.disable_irq
|
||||
elif self.pressedkey == ord('r'):
|
||||
# 'r' > Reset history
|
||||
self.reset_history_tag = not self.reset_history_tag
|
||||
elif self.pressedkey == ord('R'):
|
||||
# 'R' > Hide RAID plugins
|
||||
self.args.disable_raid = not self.args.disable_raid
|
||||
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' > Sort processes by TIME usage
|
||||
glances_processes.auto_sort = False
|
||||
glances_processes.sort_key = 'cpu_times'
|
||||
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' > Sort processes by USER
|
||||
glances_processes.auto_sort = False
|
||||
glances_processes.sort_key = 'username'
|
||||
elif self.pressedkey == ord('U'):
|
||||
# 'U' > View cumulative network I/O (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()
|
||||
@@ -448,17 +379,52 @@ class _GlancesCurses(object):
|
||||
# 'x' > Delete finished warning and critical logs
|
||||
glances_logs.clean(critical=True)
|
||||
elif self.pressedkey == ord('z'):
|
||||
# 'z' > Enable/Disable processes stats (count + list + AMPs)
|
||||
# Enable/Disable display
|
||||
# 'z' > Enable or disable processes
|
||||
self.args.disable_process = not self.args.disable_process
|
||||
# Enable/Disable update
|
||||
if self.args.disable_process:
|
||||
glances_processes.disable()
|
||||
else:
|
||||
glances_processes.enable()
|
||||
|
||||
# Change the curse interface according to the current configuration
|
||||
if not self.args.enable_process_extended:
|
||||
glances_processes.disable_extended()
|
||||
else:
|
||||
glances_processes.enable_extended()
|
||||
|
||||
# Return the key code
|
||||
return self.pressedkey
|
||||
|
||||
def disable_top(self):
|
||||
"""Disable the top panel"""
|
||||
self.args.disable_quicklook = True
|
||||
self.args.disable_cpu = True
|
||||
self.args.disable_mem = True
|
||||
self.args.disable_memswap = True
|
||||
self.args.disable_load = True
|
||||
|
||||
def enable_top(self):
|
||||
"""Enable the top panel"""
|
||||
self.args.disable_quicklook = False
|
||||
self.args.disable_cpu = False
|
||||
self.args.disable_mem = False
|
||||
self.args.disable_memswap = False
|
||||
self.args.disable_load = False
|
||||
|
||||
def disable_fullquicklook(self):
|
||||
"""Disable the full quicklook mode"""
|
||||
self.args.disable_quicklook = False
|
||||
self.args.disable_cpu = False
|
||||
self.args.disable_mem = False
|
||||
self.args.disable_memswap = False
|
||||
|
||||
def enable_fullquicklook(self):
|
||||
"""Disable the full quicklook mode"""
|
||||
self.args.disable_quicklook = False
|
||||
self.args.disable_cpu = True
|
||||
self.args.disable_mem = True
|
||||
self.args.disable_memswap = True
|
||||
|
||||
def end(self):
|
||||
"""Shutdown the curses window."""
|
||||
if hasattr(curses, 'echo'):
|
||||
@@ -495,6 +461,51 @@ class _GlancesCurses(object):
|
||||
"""New column in the curses interface."""
|
||||
self.column = self.next_column
|
||||
|
||||
def __get_stat_display(self, stats, plugin_max_width):
|
||||
ret = {}
|
||||
ret["system"] = stats.get_plugin(
|
||||
'system').get_stats_display(args=self.args)
|
||||
ret["uptime"] = stats.get_plugin('uptime').get_stats_display()
|
||||
if self.args.percpu:
|
||||
ret["cpu"] = stats.get_plugin('percpu').get_stats_display(args=self.args)
|
||||
else:
|
||||
ret["cpu"] = stats.get_plugin('cpu').get_stats_display(args=self.args)
|
||||
ret["load"] = stats.get_plugin('load').get_stats_display(args=self.args)
|
||||
ret["mem"] = stats.get_plugin('mem').get_stats_display(args=self.args)
|
||||
ret["memswap"] = stats.get_plugin('memswap').get_stats_display(args=self.args)
|
||||
ret["network"] = stats.get_plugin('network').get_stats_display(
|
||||
args=self.args, max_width=plugin_max_width)
|
||||
ret["wifi"] = stats.get_plugin('wifi').get_stats_display(
|
||||
args=self.args, max_width=plugin_max_width)
|
||||
ret["irq"] = stats.get_plugin('irq').get_stats_display(
|
||||
args=self.args, max_width=plugin_max_width)
|
||||
try:
|
||||
ret["ip"] = stats.get_plugin('ip').get_stats_display(args=self.args)
|
||||
except AttributeError:
|
||||
ret["ip"] = None
|
||||
ret["diskio"] = stats.get_plugin(
|
||||
'diskio').get_stats_display(args=self.args)
|
||||
ret["fs"] = stats.get_plugin('fs').get_stats_display(
|
||||
args=self.args, max_width=plugin_max_width)
|
||||
ret["folders"] = stats.get_plugin('folders').get_stats_display(
|
||||
args=self.args, max_width=plugin_max_width)
|
||||
ret["raid"] = stats.get_plugin('raid').get_stats_display(
|
||||
args=self.args)
|
||||
ret["sensors"] = stats.get_plugin(
|
||||
'sensors').get_stats_display(args=self.args)
|
||||
ret["ports"] = stats.get_plugin(
|
||||
'ports').get_stats_display(args=self.args)
|
||||
ret["now"] = stats.get_plugin('now').get_stats_display()
|
||||
ret["docker"] = stats.get_plugin('docker').get_stats_display(
|
||||
args=self.args)
|
||||
ret["processcount"] = stats.get_plugin(
|
||||
'processcount').get_stats_display(args=self.args)
|
||||
ret["amps"] = stats.get_plugin(
|
||||
'amps').get_stats_display(args=self.args)
|
||||
ret["alert"] = stats.get_plugin(
|
||||
'alert').get_stats_display(args=self.args)
|
||||
return ret
|
||||
|
||||
def display(self, stats, cs_status=None):
|
||||
"""Display stats on the screen.
|
||||
|
||||
@@ -528,50 +539,12 @@ class _GlancesCurses(object):
|
||||
|
||||
# Update the client server status
|
||||
self.args.cs_status = cs_status
|
||||
stats_system = stats.get_plugin(
|
||||
'system').get_stats_display(args=self.args)
|
||||
stats_uptime = stats.get_plugin('uptime').get_stats_display()
|
||||
if self.args.percpu:
|
||||
stats_cpu = stats.get_plugin('percpu').get_stats_display(args=self.args)
|
||||
else:
|
||||
stats_cpu = stats.get_plugin('cpu').get_stats_display(args=self.args)
|
||||
stats_load = stats.get_plugin('load').get_stats_display(args=self.args)
|
||||
stats_mem = stats.get_plugin('mem').get_stats_display(args=self.args)
|
||||
stats_memswap = stats.get_plugin('memswap').get_stats_display(args=self.args)
|
||||
stats_network = stats.get_plugin('network').get_stats_display(
|
||||
args=self.args, max_width=plugin_max_width)
|
||||
stats_irq = stats.get_plugin('irq').get_stats_display(
|
||||
args=self.args, max_width=plugin_max_width)
|
||||
try:
|
||||
stats_ip = stats.get_plugin('ip').get_stats_display(args=self.args)
|
||||
except AttributeError:
|
||||
stats_ip = None
|
||||
stats_diskio = stats.get_plugin(
|
||||
'diskio').get_stats_display(args=self.args)
|
||||
stats_fs = stats.get_plugin('fs').get_stats_display(
|
||||
args=self.args, max_width=plugin_max_width)
|
||||
stats_folders = stats.get_plugin('folders').get_stats_display(
|
||||
args=self.args, max_width=plugin_max_width)
|
||||
stats_raid = stats.get_plugin('raid').get_stats_display(
|
||||
args=self.args)
|
||||
stats_sensors = stats.get_plugin(
|
||||
'sensors').get_stats_display(args=self.args)
|
||||
stats_ports = stats.get_plugin(
|
||||
'ports').get_stats_display(args=self.args)
|
||||
stats_now = stats.get_plugin('now').get_stats_display()
|
||||
stats_docker = stats.get_plugin('docker').get_stats_display(
|
||||
args=self.args)
|
||||
stats_processcount = stats.get_plugin(
|
||||
'processcount').get_stats_display(args=self.args)
|
||||
stats_amps = stats.get_plugin(
|
||||
'amps').get_stats_display(args=self.args)
|
||||
stats_alert = stats.get_plugin(
|
||||
'alert').get_stats_display(args=self.args)
|
||||
__stat_display = self.__get_stat_display(stats, plugin_max_width)
|
||||
|
||||
# Adapt number of processes to the available space
|
||||
max_processes_displayed = screen_y - 11 - \
|
||||
self.get_stats_display_height(stats_alert) - \
|
||||
self.get_stats_display_height(stats_docker)
|
||||
self.get_stats_display_height(__stat_display["alert"]) - \
|
||||
self.get_stats_display_height(__stat_display["docker"])
|
||||
try:
|
||||
if self.args.enable_process_extended and not self.args.process_tree:
|
||||
max_processes_displayed -= 4
|
||||
@@ -584,7 +557,7 @@ class _GlancesCurses(object):
|
||||
logger.debug("Set number of displayed processes to {}".format(max_processes_displayed))
|
||||
glances_processes.max_processes = max_processes_displayed
|
||||
|
||||
stats_processlist = stats.get_plugin(
|
||||
__stat_display["processlist"] = stats.get_plugin(
|
||||
'processlist').get_stats_display(args=self.args)
|
||||
|
||||
# Display the stats on the curses interface
|
||||
@@ -604,16 +577,19 @@ class _GlancesCurses(object):
|
||||
# Space between column
|
||||
self.space_between_column = 0
|
||||
self.new_line()
|
||||
l_uptime = self.get_stats_display_width(
|
||||
stats_system) + self.space_between_column + self.get_stats_display_width(stats_ip) + 3 + self.get_stats_display_width(stats_uptime)
|
||||
l_uptime = self.get_stats_display_width(__stat_display["system"]) \
|
||||
+ self.space_between_column \
|
||||
+ self.get_stats_display_width(__stat_display["ip"]) + 3 \
|
||||
+ self.get_stats_display_width(__stat_display["uptime"])
|
||||
self.display_plugin(
|
||||
stats_system, display_optional=(screen_x >= l_uptime))
|
||||
__stat_display["system"],
|
||||
display_optional=(screen_x >= l_uptime))
|
||||
self.new_column()
|
||||
self.display_plugin(stats_ip)
|
||||
self.display_plugin(__stat_display["ip"])
|
||||
# Space between column
|
||||
self.space_between_column = 3
|
||||
self.new_column()
|
||||
self.display_plugin(stats_uptime)
|
||||
self.display_plugin(__stat_display["uptime"])
|
||||
|
||||
# ========================================================
|
||||
# Display second line (<SUMMARY>+CPU|PERCPU+LOAD+MEM+SWAP)
|
||||
@@ -622,36 +598,36 @@ class _GlancesCurses(object):
|
||||
self.new_line()
|
||||
|
||||
# Init quicklook
|
||||
stats_quicklook = {'msgdict': []}
|
||||
__stat_display["quicklook"] = {'msgdict': []}
|
||||
quicklook_width = 0
|
||||
|
||||
# Get stats for CPU, MEM, SWAP and LOAD (if needed)
|
||||
if self.args.disable_cpu:
|
||||
cpu_width = 0
|
||||
else:
|
||||
cpu_width = self.get_stats_display_width(stats_cpu)
|
||||
cpu_width = self.get_stats_display_width(__stat_display["cpu"])
|
||||
if self.args.disable_mem:
|
||||
mem_width = 0
|
||||
else:
|
||||
mem_width = self.get_stats_display_width(stats_mem)
|
||||
if self.args.disable_swap:
|
||||
mem_width = self.get_stats_display_width(__stat_display["mem"])
|
||||
if self.args.disable_memswap:
|
||||
swap_width = 0
|
||||
else:
|
||||
swap_width = self.get_stats_display_width(stats_memswap)
|
||||
swap_width = self.get_stats_display_width(__stat_display["memswap"])
|
||||
if self.args.disable_load:
|
||||
load_width = 0
|
||||
else:
|
||||
load_width = self.get_stats_display_width(stats_load)
|
||||
load_width = self.get_stats_display_width(__stat_display["load"])
|
||||
|
||||
# Size of plugins but quicklook
|
||||
stats_width = cpu_width + mem_width + swap_width + load_width
|
||||
|
||||
# Number of plugin but quicklook
|
||||
stats_number = (
|
||||
int(not self.args.disable_cpu and stats_cpu['msgdict'] != []) +
|
||||
int(not self.args.disable_mem and stats_mem['msgdict'] != []) +
|
||||
int(not self.args.disable_swap and stats_memswap['msgdict'] != []) +
|
||||
int(not self.args.disable_load and stats_load['msgdict'] != []))
|
||||
int(not self.args.disable_cpu and __stat_display["cpu"]['msgdict'] != []) +
|
||||
int(not self.args.disable_mem and __stat_display["mem"]['msgdict'] != []) +
|
||||
int(not self.args.disable_memswap and __stat_display["memswap"]['msgdict'] != []) +
|
||||
int(not self.args.disable_load and __stat_display["load"]['msgdict'] != []))
|
||||
|
||||
if not self.args.disable_quicklook:
|
||||
# Quick look is in the place !
|
||||
@@ -660,15 +636,15 @@ class _GlancesCurses(object):
|
||||
else:
|
||||
quicklook_width = min(screen_x - (stats_width + 8 + stats_number * self.space_between_column), 79)
|
||||
try:
|
||||
stats_quicklook = stats.get_plugin(
|
||||
__stat_display["quicklook"] = stats.get_plugin(
|
||||
'quicklook').get_stats_display(max_width=quicklook_width, args=self.args)
|
||||
except AttributeError as e:
|
||||
logger.debug("Quicklook plugin not available (%s)" % e)
|
||||
else:
|
||||
quicklook_width = self.get_stats_display_width(stats_quicklook)
|
||||
quicklook_width = self.get_stats_display_width(__stat_display["quicklook"])
|
||||
stats_width += quicklook_width + 1
|
||||
self.space_between_column = 1
|
||||
self.display_plugin(stats_quicklook)
|
||||
self.display_plugin(__stat_display["quicklook"])
|
||||
self.new_column()
|
||||
|
||||
# Compute spaces between plugins
|
||||
@@ -683,7 +659,7 @@ class _GlancesCurses(object):
|
||||
if self.args.disable_mem:
|
||||
mem_width = 0
|
||||
else:
|
||||
mem_width = self.get_stats_display_width(stats_mem, without_option=True)
|
||||
mem_width = self.get_stats_display_width(__stat_display["mem"], without_option=True)
|
||||
stats_width = quicklook_width + 1 + cpu_width + mem_width + swap_width + load_width
|
||||
self.space_between_column = max(1, int((screen_x - stats_width) / (stats_number - 1)))
|
||||
# No space again ? Remove optionnal CPU stats
|
||||
@@ -692,20 +668,20 @@ class _GlancesCurses(object):
|
||||
if self.args.disable_cpu:
|
||||
cpu_width = 0
|
||||
else:
|
||||
cpu_width = self.get_stats_display_width(stats_cpu, without_option=True)
|
||||
cpu_width = self.get_stats_display_width(__stat_display["cpu"], without_option=True)
|
||||
stats_width = quicklook_width + 1 + cpu_width + mem_width + swap_width + load_width
|
||||
self.space_between_column = max(1, int((screen_x - stats_width) / (stats_number - 1)))
|
||||
else:
|
||||
self.space_between_column = 0
|
||||
|
||||
# Display CPU, MEM, SWAP and LOAD
|
||||
self.display_plugin(stats_cpu, display_optional=display_optional_cpu)
|
||||
self.display_plugin(__stat_display["cpu"], display_optional=display_optional_cpu)
|
||||
self.new_column()
|
||||
self.display_plugin(stats_mem, display_optional=display_optional_mem)
|
||||
self.display_plugin(__stat_display["mem"], display_optional=display_optional_mem)
|
||||
self.new_column()
|
||||
self.display_plugin(stats_memswap)
|
||||
self.display_plugin(__stat_display["memswap"])
|
||||
self.new_column()
|
||||
self.display_plugin(stats_load)
|
||||
self.display_plugin(__stat_display["load"])
|
||||
|
||||
# Space between column
|
||||
self.space_between_column = 3
|
||||
@@ -718,13 +694,24 @@ class _GlancesCurses(object):
|
||||
# ==================================================================
|
||||
self.init_column()
|
||||
if not (self.args.disable_network and
|
||||
self.args.disable_wifi and
|
||||
self.args.disable_ports and
|
||||
self.args.disable_diskio and
|
||||
self.args.disable_fs and
|
||||
self.args.disable_folder and
|
||||
self.args.enable_irq and
|
||||
self.args.disable_folders and
|
||||
self.args.disable_raid and
|
||||
self.args.disable_sensors) and not self.args.disable_left_sidebar:
|
||||
for s in (stats_network, stats_ports, stats_diskio, stats_fs, stats_irq, stats_folders, stats_raid, stats_sensors, stats_now):
|
||||
for s in (__stat_display["network"],
|
||||
__stat_display["wifi"],
|
||||
__stat_display["ports"],
|
||||
__stat_display["diskio"],
|
||||
__stat_display["fs"],
|
||||
__stat_display["irq"],
|
||||
__stat_display["folders"],
|
||||
__stat_display["raid"],
|
||||
__stat_display["sensors"],
|
||||
__stat_display["now"]):
|
||||
self.new_line()
|
||||
self.display_plugin(s)
|
||||
|
||||
@@ -740,18 +727,18 @@ class _GlancesCurses(object):
|
||||
# DOCKER+PROCESS_COUNT+AMPS+PROCESS_LIST+ALERT
|
||||
self.new_column()
|
||||
self.new_line()
|
||||
self.display_plugin(stats_docker)
|
||||
self.display_plugin(__stat_display["docker"])
|
||||
self.new_line()
|
||||
self.display_plugin(stats_processcount)
|
||||
self.display_plugin(__stat_display["processcount"])
|
||||
self.new_line()
|
||||
self.display_plugin(stats_amps)
|
||||
self.display_plugin(__stat_display["amps"])
|
||||
self.new_line()
|
||||
self.display_plugin(stats_processlist,
|
||||
self.display_plugin(__stat_display["processlist"],
|
||||
display_optional=(screen_x > 102),
|
||||
display_additional=(not OSX),
|
||||
max_y=(screen_y - self.get_stats_display_height(stats_alert) - 2))
|
||||
max_y=(screen_y - self.get_stats_display_height(__stat_display["alert"]) - 2))
|
||||
self.new_line()
|
||||
self.display_plugin(stats_alert)
|
||||
self.display_plugin(__stat_display["alert"])
|
||||
|
||||
# History option
|
||||
# Generate history graph
|
||||
|
||||
@@ -4,6 +4,7 @@ var mainBowerFiles = require('main-bower-files');
|
||||
var ngAnnotate = require('gulp-ng-annotate');
|
||||
var templateCache = require('gulp-angular-templatecache');
|
||||
var del = require('del');
|
||||
var rename = require('gulp-rename');
|
||||
|
||||
gulp.task('clean', function() {
|
||||
del('./public/*')
|
||||
@@ -14,6 +15,7 @@ gulp.task('copy', function() {
|
||||
.pipe(gulp.dest('./public'));
|
||||
|
||||
gulp.src('./css/*.css')
|
||||
.pipe(rename({suffix: '.min'}))
|
||||
.pipe(gulp.dest('./public/css'));
|
||||
|
||||
gulp.src('./images/*.png')
|
||||
@@ -26,6 +28,7 @@ gulp.task('copy', function() {
|
||||
gulp.task('bower', function() {
|
||||
return gulp.src(mainBowerFiles())
|
||||
.pipe(concat('vendor.js'))
|
||||
.pipe(rename({suffix: '.min'}))
|
||||
.pipe(gulp.dest('./public/js'))
|
||||
});
|
||||
|
||||
@@ -33,12 +36,14 @@ gulp.task('build-js', function() {
|
||||
return gulp.src('./js/**/*.js')
|
||||
.pipe(ngAnnotate())
|
||||
.pipe(concat('main.js'))
|
||||
.pipe(rename({suffix: '.min'}))
|
||||
.pipe(gulp.dest('./public/js'))
|
||||
});
|
||||
|
||||
gulp.task('template', function () {
|
||||
return gulp.src('./html/plugins/*.html')
|
||||
.pipe(templateCache('templates.js', {'root': 'plugins/', 'module': 'glancesApp'}))
|
||||
.pipe(rename({suffix: '.min'}))
|
||||
.pipe(gulp.dest('./public/js'));
|
||||
});
|
||||
|
||||
|
||||
@@ -8,13 +8,13 @@
|
||||
<base href="/">
|
||||
|
||||
<link rel="icon" type="image/x-icon" href="favicon.ico" />
|
||||
<link rel="stylesheet" type="text/css" href="css/normalize.css" />
|
||||
<link rel="stylesheet" type="text/css" href="css/normalize.min.css" />
|
||||
<link rel="stylesheet" type="text/css" href="css/bootstrap.min.css" />
|
||||
<link rel="stylesheet" type="text/css" href="css/style.css" />
|
||||
<link rel="stylesheet" type="text/css" href="css/style.min.css" />
|
||||
|
||||
<script type="text/javascript" src="js/vendor.js"></script>
|
||||
<script type="text/javascript" src="js/main.js"></script>
|
||||
<script type="text/javascript" src="js/templates.js"></script>
|
||||
<script type="text/javascript" src="js/vendor.min.js"></script>
|
||||
<script type="text/javascript" src="js/main.min.js"></script>
|
||||
<script type="text/javascript" src="js/templates.min.js"></script>
|
||||
</head>
|
||||
|
||||
<body ng-view="" ng-keydown="onKeyDown($event)">
|
||||
|
||||
10
glances/outputs/static/html/plugins/wifi.html
Normal file
10
glances/outputs/static/html/plugins/wifi.html
Normal file
@@ -0,0 +1,10 @@
|
||||
<div class="table-row">
|
||||
<div class="table-cell text-left title">WIFI</div>
|
||||
<div class="table-cell"></div>
|
||||
<div class="table-cell">dBm</div>
|
||||
</div>
|
||||
<div class="table-row" ng-repeat="hotspot in statsWifi.hotspots | orderBy: 'ssid'">
|
||||
<div class="table-cell text-left">{{ hotspot.ssid|limitTo:20 }} <span ng-if="hotspot.encrypted">{{ hotspot.encryption_type }}</span></div>
|
||||
<div class="table-cell"></div>
|
||||
<div class="table-cell" ng-class="statsWifi.getDecoration(hotspot, 'signal')">{{ hotspot.signal }}</div>
|
||||
</div>
|
||||
@@ -35,7 +35,7 @@
|
||||
<div class="hidden-xs hidden-sm col-md-4 col-lg-3" ng-if="!arguments.disable_mem">
|
||||
<section id="mem_more" class="plugin" ng-include src="'plugins/mem_more.html'"></section>
|
||||
</div>
|
||||
<div class="col-sm-6 col-md-4 col-lg-3" ng-if="!arguments.disable_swap">
|
||||
<div class="col-sm-6 col-md-4 col-lg-3" ng-if="!arguments.disable_memswap">
|
||||
<section id="memswap" class="plugin" ng-include src="'plugins/memswap.html'"></section>
|
||||
</div>
|
||||
<div class="col-sm-6 col-md-4 col-lg-3" ng-if="!arguments.disable_load">
|
||||
@@ -46,20 +46,21 @@
|
||||
<div class="col-sm-6 sidebar" ng-show="!arguments.disable_left_sidebar">
|
||||
<div class="table">
|
||||
<section id="network" class="plugin table-row-group" ng-show="!arguments.disable_network" ng-include src="'plugins/network.html'"></section>
|
||||
<section id="wifi" class="plugin table-row-group" ng-show="!arguments.disable_wifi && statsWifi.hotspots.length > 0" ng-include src="'plugins/wifi.html'"></section>
|
||||
<section id="ports" class="plugin table-row-group" ng-show="!arguments.disable_ports" ng-include src="'plugins/ports.html'"></section>
|
||||
<section id="diskio" class="plugin table-row-group" ng-show="!arguments.disable_diskio && statsDiskio.disks.length > 0" ng-include src="'plugins/diskio.html'"></section>
|
||||
|
||||
<section id="fs" class="plugin table-row-group" ng-show="!arguments.disable_fs" ng-include src="'plugins/fs.html'"></section>
|
||||
<section id="irq" class="plugin table-row-group" ng-show="!arguments.disable_irq" ng-include src="'plugins/irq.html'"></section>
|
||||
<section id="folders" class="plugin table-row-group" ng-show="!arguments.disable_fs && statsFolders.folders.length > 0" ng-include src="'plugins/folders.html'"></section>
|
||||
<section id="irq" class="plugin table-row-group" ng-show="arguments.enable_irq && statsIrq.irqs.length > 0" ng-include src="'plugins/irq.html'"></section>
|
||||
<section id="folders" class="plugin table-row-group" ng-show="!arguments.disable_fs && statsFolders.folders.length > 0" ng-include src="'plugins/folders.html'"></section>
|
||||
<section id="raid" class="plugin table-row-group" ng-show="statsRaid.hasDisks()" ng-include src="'plugins/raid.html'"></section>
|
||||
<section id="sensors" class="plugin table-row-group" ng-show="!arguments.disable_sensors && statsSensors.sensors.length > 0" ng-include src="'plugins/sensors.html'"></section>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-sm-18">
|
||||
<section id="containers" class="plugin" ng-show="statsDocker.containers.length && !arguments.disable_docker" ng-include src="'plugins/docker.html'"></section>
|
||||
<section id="alerts" ng-show="!arguments.disable_log" ng-include src="'plugins/alerts.html'"></section>
|
||||
<section id="alert" class="plugin" ng-show="!arguments.disable_log" ng-include src="'plugins/alert.html'"></section>
|
||||
<section id="alerts" ng-show="!arguments.disable_alert" ng-include src="'plugins/alerts.html'"></section>
|
||||
<section id="alert" class="plugin" ng-show="!arguments.disable_alert" ng-include src="'plugins/alert.html'"></section>
|
||||
<div ng-show="!arguments.disable_process">
|
||||
<section id="processcount" class="plugin" ng-include src="'plugins/processcount.html'"></section>
|
||||
<div class="row" ng-if="!arguments.disable_amps">
|
||||
|
||||
@@ -43,6 +43,7 @@ glancesApp.controller('statsController', function ($scope, $rootScope, $interval
|
||||
$scope.statsSystem = GlancesStats.getPlugin('system');
|
||||
$scope.statsUptime = GlancesStats.getPlugin('uptime');
|
||||
$scope.statsPorts = GlancesStats.getPlugin('ports');
|
||||
$scope.statsWifi = GlancesStats.getPlugin('wifi');
|
||||
|
||||
$rootScope.title = $scope.statsSystem.hostname + ' - Glances';
|
||||
|
||||
@@ -112,7 +113,7 @@ glancesApp.controller('statsController', function ($scope, $rootScope, $interval
|
||||
break;
|
||||
case $event.shiftKey && $event.keyCode == keycodes.Q:
|
||||
// Q => Show/hide IRQ
|
||||
$scope.arguments.disable_irq = !$scope.arguments.disable_irq;
|
||||
$scope.arguments.enable_irq = !$scope.arguments.enable_irq;
|
||||
break;
|
||||
case !$event.shiftKey && $event.keyCode == keycodes.f:
|
||||
// f => Show/hide filesystem stats
|
||||
@@ -152,7 +153,7 @@ glancesApp.controller('statsController', function ($scope, $rootScope, $interval
|
||||
break;
|
||||
case !$event.shiftKey && $event.keyCode == keycodes.l:
|
||||
// l => Show/hide alert logs
|
||||
$scope.arguments.disable_log = !$scope.arguments.disable_log;
|
||||
$scope.arguments.disable_alert = !$scope.arguments.disable_alert;
|
||||
break;
|
||||
case $event.shiftKey && $event.keyCode == keycodes.ONE:
|
||||
// 1 => Global CPU or per-CPU stats
|
||||
@@ -182,7 +183,7 @@ glancesApp.controller('statsController', function ($scope, $rootScope, $interval
|
||||
$scope.arguments.disable_quicklook = !$scope.arguments.disable_quicklook;
|
||||
$scope.arguments.disable_cpu = !$scope.arguments.disable_cpu;
|
||||
$scope.arguments.disable_mem = !$scope.arguments.disable_mem;
|
||||
$scope.arguments.disable_swap = !$scope.arguments.disable_swap;
|
||||
$scope.arguments.disable_memswap = !$scope.arguments.disable_memswap;
|
||||
$scope.arguments.disable_load = !$scope.arguments.disable_load;
|
||||
break;
|
||||
case $event.shiftKey && $event.keyCode == keycodes.i:
|
||||
@@ -193,6 +194,10 @@ glancesApp.controller('statsController', function ($scope, $rootScope, $interval
|
||||
// I => Enable/disable ports module
|
||||
$scope.arguments.disable_ports = !$scope.arguments.disable_ports;
|
||||
break;
|
||||
case $event.shiftKey && $event.keyCode == keycodes.w:
|
||||
// 'W' > Enable/Disable Wifi plugin
|
||||
$scope.arguments.disable_wifi = !$scope.arguments.disable_wifi;
|
||||
break;
|
||||
}
|
||||
};
|
||||
});
|
||||
@@ -23,7 +23,8 @@ glancesApp.service('GlancesStats', function($http, $injector, $q, GlancesPlugin)
|
||||
'sensors': 'GlancesPluginSensors',
|
||||
'system': 'GlancesPluginSystem',
|
||||
'uptime': 'GlancesPluginUptime',
|
||||
'ports': 'GlancesPluginPorts'
|
||||
'ports': 'GlancesPluginPorts',
|
||||
'wifi': 'GlancesPluginWifi'
|
||||
};
|
||||
|
||||
this.getData = function() {
|
||||
@@ -12,7 +12,7 @@ glancesApp.service('GlancesPluginIrq', function() {
|
||||
|
||||
var irq = {
|
||||
'irq_line': IrqData['irq_line'],
|
||||
'irq_rate': IrqData['irq_rate']
|
||||
'irq_rate': IrqData['irq_rate']
|
||||
};
|
||||
|
||||
this.irqs.push(irq);
|
||||
@@ -3,7 +3,7 @@ glancesApp.service('GlancesPluginRaid', function () {
|
||||
this.disks = [];
|
||||
|
||||
this.setData = function (data, views) {
|
||||
this.disks = [];
|
||||
var disks = [];
|
||||
data = data[_pluginName];
|
||||
|
||||
_.forIn(data, function(diskData, diskKey) {
|
||||
@@ -26,8 +26,10 @@ glancesApp.service('GlancesPluginRaid', function () {
|
||||
});
|
||||
});
|
||||
|
||||
this.disks.push(disk);
|
||||
}, this);
|
||||
disks.push(disk);
|
||||
});
|
||||
|
||||
this.disks = disks;
|
||||
};
|
||||
|
||||
this.hasDisks = function() {
|
||||
36
glances/outputs/static/js/services/plugins/wifi.js
Normal file
36
glances/outputs/static/js/services/plugins/wifi.js
Normal file
@@ -0,0 +1,36 @@
|
||||
glancesApp.service('GlancesPluginWifi', function() {
|
||||
var _pluginName = "wifi";
|
||||
var _view = {};
|
||||
this.hotspots = [];
|
||||
|
||||
this.setData = function(data, views) {
|
||||
data = data[_pluginName];
|
||||
_view = views[_pluginName];
|
||||
|
||||
this.hotspots = [];
|
||||
for (var i = 0; i < data.length; i++) {
|
||||
var hotspotData = data[i];
|
||||
|
||||
if (hotspotData['ssid'] === '') {
|
||||
continue;
|
||||
}
|
||||
|
||||
var hotspot = {
|
||||
'ssid': hotspotData['ssid'],
|
||||
'encrypted': hotspotData['encrypted'],
|
||||
'signal': hotspotData['signal'],
|
||||
'encryption_type': hotspotData['encryption_type'],
|
||||
};
|
||||
|
||||
this.hotspots.push(hotspot);
|
||||
}
|
||||
};
|
||||
|
||||
this.getDecoration = function(hotpost, field) {
|
||||
if(_view[hotpost.ssid][field] == undefined) {
|
||||
return;
|
||||
}
|
||||
|
||||
return _view[hotpost.ssid][field].decoration.toLowerCase();
|
||||
};
|
||||
});
|
||||
@@ -30,5 +30,5 @@ var keycodes = {
|
||||
'r' : '82',
|
||||
'q' : '81',
|
||||
'A' : '65',
|
||||
'R' : '82',
|
||||
'Q' : '81'
|
||||
}
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
"gulp-angular-templatecache": "^2.0.0",
|
||||
"gulp-concat": "^2.6.0",
|
||||
"gulp-ng-annotate": "^2.0.0",
|
||||
"gulp-rename": "^1.2.2",
|
||||
"main-bower-files": "^2.13.1"
|
||||
},
|
||||
"scripts": {
|
||||
|
||||
@@ -62,11 +62,15 @@ body {
|
||||
}
|
||||
.ok, .status, .process {
|
||||
color: #3E7B04;
|
||||
font-weight: bold;
|
||||
/*font-weight: bold;*/
|
||||
}
|
||||
.ok_log {
|
||||
background-color: #3E7B04;
|
||||
color: white;
|
||||
/*font-weight: bold;*/
|
||||
}
|
||||
.max {
|
||||
color: #3E7B04;
|
||||
font-weight: bold;
|
||||
}
|
||||
.careful {
|
||||
BIN
glances/outputs/static/public/index.html
vendored
BIN
glances/outputs/static/public/index.html
vendored
Binary file not shown.
@@ -27,6 +27,210 @@ var glancesApp = angular.module('glancesApp', ['ngRoute'])
|
||||
$rootScope.title = "Glances";
|
||||
}]);
|
||||
|
||||
glancesApp.controller('statsController', ["$scope", "$rootScope", "$interval", "GlancesStats", "help", "arguments", "favicoService", function ($scope, $rootScope, $interval, GlancesStats, help, arguments, favicoService) {
|
||||
$scope.help = help;
|
||||
$scope.arguments = arguments;
|
||||
|
||||
$scope.sorter = {
|
||||
column: "cpu_percent",
|
||||
auto: true,
|
||||
isReverseColumn: function (column) {
|
||||
return !(column == 'username' || column == 'name');
|
||||
},
|
||||
getColumnLabel: function (column) {
|
||||
if (_.isEqual(column, ['io_read', 'io_write'])) {
|
||||
return 'io_counters';
|
||||
} else {
|
||||
return column;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
$scope.dataLoaded = false;
|
||||
$scope.refreshData = function () {
|
||||
GlancesStats.getData().then(function (data) {
|
||||
|
||||
$scope.statsAlert = GlancesStats.getPlugin('alert');
|
||||
$scope.statsCpu = GlancesStats.getPlugin('cpu');
|
||||
$scope.statsDiskio = GlancesStats.getPlugin('diskio');
|
||||
$scope.statsIrq = GlancesStats.getPlugin('irq');
|
||||
$scope.statsDocker = GlancesStats.getPlugin('docker');
|
||||
$scope.statsFs = GlancesStats.getPlugin('fs');
|
||||
$scope.statsFolders = GlancesStats.getPlugin('folders');
|
||||
$scope.statsIp = GlancesStats.getPlugin('ip');
|
||||
$scope.statsLoad = GlancesStats.getPlugin('load');
|
||||
$scope.statsMem = GlancesStats.getPlugin('mem');
|
||||
$scope.statsMemSwap = GlancesStats.getPlugin('memswap');
|
||||
$scope.statsAmps = GlancesStats.getPlugin('amps');
|
||||
$scope.statsNetwork = GlancesStats.getPlugin('network');
|
||||
$scope.statsPerCpu = GlancesStats.getPlugin('percpu');
|
||||
$scope.statsProcessCount = GlancesStats.getPlugin('processcount');
|
||||
$scope.statsProcessList = GlancesStats.getPlugin('processlist');
|
||||
$scope.statsQuicklook = GlancesStats.getPlugin('quicklook');
|
||||
$scope.statsRaid = GlancesStats.getPlugin('raid');
|
||||
$scope.statsSensors = GlancesStats.getPlugin('sensors');
|
||||
$scope.statsSystem = GlancesStats.getPlugin('system');
|
||||
$scope.statsUptime = GlancesStats.getPlugin('uptime');
|
||||
$scope.statsPorts = GlancesStats.getPlugin('ports');
|
||||
$scope.statsWifi = GlancesStats.getPlugin('wifi');
|
||||
|
||||
$rootScope.title = $scope.statsSystem.hostname + ' - Glances';
|
||||
|
||||
if ($scope.statsAlert.hasOngoingAlerts()) {
|
||||
favicoService.badge($scope.statsAlert.countOngoingAlerts());
|
||||
} else {
|
||||
favicoService.reset();
|
||||
}
|
||||
|
||||
$scope.is_disconnected = false;
|
||||
$scope.dataLoaded = true;
|
||||
}, function() {
|
||||
$scope.is_disconnected = true;
|
||||
});
|
||||
};
|
||||
|
||||
$scope.refreshData();
|
||||
$interval(function () {
|
||||
$scope.refreshData();
|
||||
}, arguments.time * 1000); // in milliseconds
|
||||
|
||||
$scope.onKeyDown = function ($event) {
|
||||
|
||||
switch (true) {
|
||||
case !$event.shiftKey && $event.keyCode == keycodes.a:
|
||||
// a => Sort processes automatically
|
||||
$scope.sorter.column = "cpu_percent";
|
||||
$scope.sorter.auto = true;
|
||||
break;
|
||||
case $event.shiftKey && $event.keyCode == keycodes.A:
|
||||
// A => Enable/disable AMPs
|
||||
$scope.arguments.disable_amps = !$scope.arguments.disable_amps;
|
||||
break;
|
||||
case !$event.shiftKey && $event.keyCode == keycodes.c:
|
||||
// c => Sort processes by CPU%
|
||||
$scope.sorter.column = "cpu_percent";
|
||||
$scope.sorter.auto = false;
|
||||
break;
|
||||
case !$event.shiftKey && $event.keyCode == keycodes.m:
|
||||
// m => Sort processes by MEM%
|
||||
$scope.sorter.column = "memory_percent";
|
||||
$scope.sorter.auto = false;
|
||||
break;
|
||||
case !$event.shiftKey && $event.keyCode == keycodes.u:
|
||||
// u => Sort processes by user
|
||||
$scope.sorter.column = "username";
|
||||
$scope.sorter.auto = false;
|
||||
break;
|
||||
case !$event.shiftKey && $event.keyCode == keycodes.p:
|
||||
// p => Sort processes by name
|
||||
$scope.sorter.column = "name";
|
||||
$scope.sorter.auto = false;
|
||||
break;
|
||||
case !$event.shiftKey && $event.keyCode == keycodes.i:
|
||||
// i => Sort processes by I/O rate
|
||||
$scope.sorter.column = ['io_read', 'io_write'];
|
||||
$scope.sorter.auto = false;
|
||||
break;
|
||||
case !$event.shiftKey && $event.keyCode == keycodes.t:
|
||||
// t => Sort processes by time
|
||||
$scope.sorter.column = "timemillis";
|
||||
$scope.sorter.auto = false;
|
||||
break;
|
||||
case !$event.shiftKey && $event.keyCode == keycodes.d:
|
||||
// d => Show/hide disk I/O stats
|
||||
$scope.arguments.disable_diskio = !$scope.arguments.disable_diskio;
|
||||
break;
|
||||
case $event.shiftKey && $event.keyCode == keycodes.Q:
|
||||
// Q => Show/hide IRQ
|
||||
$scope.arguments.enable_irq = !$scope.arguments.enable_irq;
|
||||
break;
|
||||
case !$event.shiftKey && $event.keyCode == keycodes.f:
|
||||
// f => Show/hide filesystem stats
|
||||
$scope.arguments.disable_fs = !$scope.arguments.disable_fs;
|
||||
break;
|
||||
case !$event.shiftKey && $event.keyCode == keycodes.n:
|
||||
// n => Show/hide network stats
|
||||
$scope.arguments.disable_network = !$scope.arguments.disable_network;
|
||||
break;
|
||||
case !$event.shiftKey && $event.keyCode == keycodes.s:
|
||||
// s => Show/hide sensors stats
|
||||
$scope.arguments.disable_sensors = !$scope.arguments.disable_sensors;
|
||||
break;
|
||||
case $event.shiftKey && $event.keyCode == keycodes.TWO:
|
||||
// 2 => Show/hide left sidebar
|
||||
$scope.arguments.disable_left_sidebar = !$scope.arguments.disable_left_sidebar;
|
||||
break;
|
||||
case !$event.shiftKey && $event.keyCode == keycodes.z:
|
||||
// z => Enable/disable processes stats
|
||||
$scope.arguments.disable_process = !$scope.arguments.disable_process;
|
||||
break;
|
||||
case $event.keyCode == keycodes.SLASH:
|
||||
// SLASH => Enable/disable short processes name
|
||||
$scope.arguments.process_short_name = !$scope.arguments.process_short_name;
|
||||
break;
|
||||
case $event.shiftKey && $event.keyCode == keycodes.D:
|
||||
// D => Enable/disable Docker stats
|
||||
$scope.arguments.disable_docker = !$scope.arguments.disable_docker;
|
||||
break;
|
||||
case !$event.shiftKey && $event.keyCode == keycodes.b:
|
||||
// b => Bytes or bits for network I/O
|
||||
$scope.arguments.byte = !$scope.arguments.byte;
|
||||
break;
|
||||
case $event.shiftKey && $event.keyCode == keycodes.b:
|
||||
// 'B' => Switch between bit/s and IO/s for Disk IO
|
||||
$scope.arguments.diskio_iops = !$scope.arguments.diskio_iops;
|
||||
break;
|
||||
case !$event.shiftKey && $event.keyCode == keycodes.l:
|
||||
// l => Show/hide alert logs
|
||||
$scope.arguments.disable_alert = !$scope.arguments.disable_alert;
|
||||
break;
|
||||
case $event.shiftKey && $event.keyCode == keycodes.ONE:
|
||||
// 1 => Global CPU or per-CPU stats
|
||||
$scope.arguments.percpu = !$scope.arguments.percpu;
|
||||
break;
|
||||
case !$event.shiftKey && $event.keyCode == keycodes.h:
|
||||
// h => Show/hide this help screen
|
||||
$scope.arguments.help_tag = !$scope.arguments.help_tag;
|
||||
break;
|
||||
case $event.shiftKey && $event.keyCode == keycodes.T:
|
||||
// T => View network I/O as combination
|
||||
$scope.arguments.network_sum = !$scope.arguments.network_sum;
|
||||
break;
|
||||
case $event.shiftKey && $event.keyCode == keycodes.u:
|
||||
// U => View cumulative network I/O
|
||||
$scope.arguments.network_cumul = !$scope.arguments.network_cumul;
|
||||
break;
|
||||
case $event.shiftKey && $event.keyCode == keycodes.f:
|
||||
// F => Show filesystem free space
|
||||
$scope.arguments.fs_free_space = !$scope.arguments.fs_free_space;
|
||||
break;
|
||||
case $event.shiftKey && $event.keyCode == keycodes.THREE:
|
||||
// 3 => Enable/disable quick look plugin
|
||||
$scope.arguments.disable_quicklook = !$scope.arguments.disable_quicklook;
|
||||
break;
|
||||
case $event.shiftKey && $event.keyCode == keycodes.FIVE:
|
||||
$scope.arguments.disable_quicklook = !$scope.arguments.disable_quicklook;
|
||||
$scope.arguments.disable_cpu = !$scope.arguments.disable_cpu;
|
||||
$scope.arguments.disable_mem = !$scope.arguments.disable_mem;
|
||||
$scope.arguments.disable_memswap = !$scope.arguments.disable_memswap;
|
||||
$scope.arguments.disable_load = !$scope.arguments.disable_load;
|
||||
break;
|
||||
case $event.shiftKey && $event.keyCode == keycodes.i:
|
||||
// I => Show/hide IP module
|
||||
$scope.arguments.disable_ip = !$scope.arguments.disable_ip;
|
||||
break;
|
||||
case $event.shiftKey && $event.keyCode == keycodes.p:
|
||||
// I => Enable/disable ports module
|
||||
$scope.arguments.disable_ports = !$scope.arguments.disable_ports;
|
||||
break;
|
||||
case $event.shiftKey && $event.keyCode == keycodes.w:
|
||||
// 'W' > Enable/Disable Wifi plugin
|
||||
$scope.arguments.disable_wifi = !$scope.arguments.disable_wifi;
|
||||
break;
|
||||
}
|
||||
};
|
||||
}]);
|
||||
|
||||
glancesApp.directive("sortableTh", function() {
|
||||
return {
|
||||
restrict: 'A',
|
||||
@@ -177,199 +381,6 @@ glancesApp.filter('timedelta', ["$filter", function($filter) {
|
||||
}
|
||||
}]);
|
||||
|
||||
glancesApp.controller('statsController', ["$scope", "$rootScope", "$interval", "GlancesStats", "help", "arguments", function ($scope, $rootScope, $interval, GlancesStats, help, arguments) {
|
||||
$scope.help = help;
|
||||
$scope.arguments = arguments;
|
||||
|
||||
$scope.sorter = {
|
||||
column: "cpu_percent",
|
||||
auto: true,
|
||||
isReverseColumn: function (column) {
|
||||
return !(column == 'username' || column == 'name');
|
||||
},
|
||||
getColumnLabel: function (column) {
|
||||
if (_.isEqual(column, ['io_read', 'io_write'])) {
|
||||
return 'io_counters';
|
||||
} else {
|
||||
return column;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
$scope.dataLoaded = false;
|
||||
$scope.refreshData = function () {
|
||||
GlancesStats.getData().then(function (data) {
|
||||
|
||||
$scope.statsAlert = GlancesStats.getPlugin('alert');
|
||||
$scope.statsCpu = GlancesStats.getPlugin('cpu');
|
||||
$scope.statsDiskio = GlancesStats.getPlugin('diskio');
|
||||
$scope.statsIrq = GlancesStats.getPlugin('irq');
|
||||
$scope.statsDocker = GlancesStats.getPlugin('docker');
|
||||
$scope.statsFs = GlancesStats.getPlugin('fs');
|
||||
$scope.statsFolders = GlancesStats.getPlugin('folders');
|
||||
$scope.statsIp = GlancesStats.getPlugin('ip');
|
||||
$scope.statsLoad = GlancesStats.getPlugin('load');
|
||||
$scope.statsMem = GlancesStats.getPlugin('mem');
|
||||
$scope.statsMemSwap = GlancesStats.getPlugin('memswap');
|
||||
$scope.statsAmps = GlancesStats.getPlugin('amps');
|
||||
$scope.statsNetwork = GlancesStats.getPlugin('network');
|
||||
$scope.statsPerCpu = GlancesStats.getPlugin('percpu');
|
||||
$scope.statsProcessCount = GlancesStats.getPlugin('processcount');
|
||||
$scope.statsProcessList = GlancesStats.getPlugin('processlist');
|
||||
$scope.statsQuicklook = GlancesStats.getPlugin('quicklook');
|
||||
$scope.statsRaid = GlancesStats.getPlugin('raid');
|
||||
$scope.statsSensors = GlancesStats.getPlugin('sensors');
|
||||
$scope.statsSystem = GlancesStats.getPlugin('system');
|
||||
$scope.statsUptime = GlancesStats.getPlugin('uptime');
|
||||
$scope.statsPorts = GlancesStats.getPlugin('ports');
|
||||
|
||||
$rootScope.title = $scope.statsSystem.hostname + ' - Glances';
|
||||
|
||||
$scope.is_disconnected = false;
|
||||
$scope.dataLoaded = true;
|
||||
}, function() {
|
||||
$scope.is_disconnected = true;
|
||||
});
|
||||
};
|
||||
|
||||
$scope.refreshData();
|
||||
$interval(function () {
|
||||
$scope.refreshData();
|
||||
}, arguments.time * 1000); // in milliseconds
|
||||
|
||||
$scope.onKeyDown = function ($event) {
|
||||
|
||||
switch (true) {
|
||||
case !$event.shiftKey && $event.keyCode == keycodes.a:
|
||||
// a => Sort processes automatically
|
||||
$scope.sorter.column = "cpu_percent";
|
||||
$scope.sorter.auto = true;
|
||||
break;
|
||||
case $event.shiftKey && $event.keyCode == keycodes.A:
|
||||
// A => Enable/disable AMPs
|
||||
$scope.arguments.disable_amps = !$scope.arguments.disable_amps;
|
||||
break;
|
||||
case !$event.shiftKey && $event.keyCode == keycodes.c:
|
||||
// c => Sort processes by CPU%
|
||||
$scope.sorter.column = "cpu_percent";
|
||||
$scope.sorter.auto = false;
|
||||
break;
|
||||
case !$event.shiftKey && $event.keyCode == keycodes.m:
|
||||
// m => Sort processes by MEM%
|
||||
$scope.sorter.column = "memory_percent";
|
||||
$scope.sorter.auto = false;
|
||||
break;
|
||||
case !$event.shiftKey && $event.keyCode == keycodes.u:
|
||||
// u => Sort processes by user
|
||||
$scope.sorter.column = "username";
|
||||
$scope.sorter.auto = false;
|
||||
break;
|
||||
case !$event.shiftKey && $event.keyCode == keycodes.p:
|
||||
// p => Sort processes by name
|
||||
$scope.sorter.column = "name";
|
||||
$scope.sorter.auto = false;
|
||||
break;
|
||||
case !$event.shiftKey && $event.keyCode == keycodes.i:
|
||||
// i => Sort processes by I/O rate
|
||||
$scope.sorter.column = ['io_read', 'io_write'];
|
||||
$scope.sorter.auto = false;
|
||||
break;
|
||||
case !$event.shiftKey && $event.keyCode == keycodes.t:
|
||||
// t => Sort processes by time
|
||||
$scope.sorter.column = "timemillis";
|
||||
$scope.sorter.auto = false;
|
||||
break;
|
||||
case !$event.shiftKey && $event.keyCode == keycodes.d:
|
||||
// d => Show/hide disk I/O stats
|
||||
$scope.arguments.disable_diskio = !$scope.arguments.disable_diskio;
|
||||
break;
|
||||
case $event.shiftKey && $event.keyCode == keycodes.Q:
|
||||
// R => Show/hide IRQ
|
||||
$scope.arguments.disable_irq = !$scope.arguments.disable_irq;
|
||||
break;
|
||||
case !$event.shiftKey && $event.keyCode == keycodes.f:
|
||||
// f => Show/hide filesystem stats
|
||||
$scope.arguments.disable_fs = !$scope.arguments.disable_fs;
|
||||
break;
|
||||
case !$event.shiftKey && $event.keyCode == keycodes.n:
|
||||
// n => Show/hide network stats
|
||||
$scope.arguments.disable_network = !$scope.arguments.disable_network;
|
||||
break;
|
||||
case !$event.shiftKey && $event.keyCode == keycodes.s:
|
||||
// s => Show/hide sensors stats
|
||||
$scope.arguments.disable_sensors = !$scope.arguments.disable_sensors;
|
||||
break;
|
||||
case $event.shiftKey && $event.keyCode == keycodes.TWO:
|
||||
// 2 => Show/hide left sidebar
|
||||
$scope.arguments.disable_left_sidebar = !$scope.arguments.disable_left_sidebar;
|
||||
break;
|
||||
case !$event.shiftKey && $event.keyCode == keycodes.z:
|
||||
// z => Enable/disable processes stats
|
||||
$scope.arguments.disable_process = !$scope.arguments.disable_process;
|
||||
break;
|
||||
case $event.keyCode == keycodes.SLASH:
|
||||
// SLASH => Enable/disable short processes name
|
||||
$scope.arguments.process_short_name = !$scope.arguments.process_short_name;
|
||||
break;
|
||||
case $event.shiftKey && $event.keyCode == keycodes.D:
|
||||
// D => Enable/disable Docker stats
|
||||
$scope.arguments.disable_docker = !$scope.arguments.disable_docker;
|
||||
break;
|
||||
case !$event.shiftKey && $event.keyCode == keycodes.b:
|
||||
// b => Bytes or bits for network I/O
|
||||
$scope.arguments.byte = !$scope.arguments.byte;
|
||||
break;
|
||||
case $event.shiftKey && $event.keyCode == keycodes.b:
|
||||
// 'B' => Switch between bit/s and IO/s for Disk IO
|
||||
$scope.arguments.diskio_iops = !$scope.arguments.diskio_iops;
|
||||
break;
|
||||
case !$event.shiftKey && $event.keyCode == keycodes.l:
|
||||
// l => Show/hide alert logs
|
||||
$scope.arguments.disable_log = !$scope.arguments.disable_log;
|
||||
break;
|
||||
case $event.shiftKey && $event.keyCode == keycodes.ONE:
|
||||
// 1 => Global CPU or per-CPU stats
|
||||
$scope.arguments.percpu = !$scope.arguments.percpu;
|
||||
break;
|
||||
case !$event.shiftKey && $event.keyCode == keycodes.h:
|
||||
// h => Show/hide this help screen
|
||||
$scope.arguments.help_tag = !$scope.arguments.help_tag;
|
||||
break;
|
||||
case $event.shiftKey && $event.keyCode == keycodes.T:
|
||||
// T => View network I/O as combination
|
||||
$scope.arguments.network_sum = !$scope.arguments.network_sum;
|
||||
break;
|
||||
case $event.shiftKey && $event.keyCode == keycodes.u:
|
||||
// U => View cumulative network I/O
|
||||
$scope.arguments.network_cumul = !$scope.arguments.network_cumul;
|
||||
break;
|
||||
case $event.shiftKey && $event.keyCode == keycodes.f:
|
||||
// F => Show filesystem free space
|
||||
$scope.arguments.fs_free_space = !$scope.arguments.fs_free_space;
|
||||
break;
|
||||
case $event.shiftKey && $event.keyCode == keycodes.THREE:
|
||||
// 3 => Enable/disable quick look plugin
|
||||
$scope.arguments.disable_quicklook = !$scope.arguments.disable_quicklook;
|
||||
break;
|
||||
case $event.shiftKey && $event.keyCode == keycodes.FIVE:
|
||||
$scope.arguments.disable_quicklook = !$scope.arguments.disable_quicklook;
|
||||
$scope.arguments.disable_cpu = !$scope.arguments.disable_cpu;
|
||||
$scope.arguments.disable_mem = !$scope.arguments.disable_mem;
|
||||
$scope.arguments.disable_swap = !$scope.arguments.disable_swap;
|
||||
$scope.arguments.disable_load = !$scope.arguments.disable_load;
|
||||
break;
|
||||
case $event.shiftKey && $event.keyCode == keycodes.i:
|
||||
// I => Show/hide IP module
|
||||
$scope.arguments.disable_ip = !$scope.arguments.disable_ip;
|
||||
break;
|
||||
case $event.shiftKey && $event.keyCode == keycodes.p:
|
||||
// I => Enable/disable ports module
|
||||
$scope.arguments.disable_ports = !$scope.arguments.disable_ports;
|
||||
break;
|
||||
}
|
||||
};
|
||||
}]);
|
||||
|
||||
var keycodes = {
|
||||
'a' : '65',
|
||||
'c' : '67',
|
||||
@@ -405,6 +416,21 @@ var keycodes = {
|
||||
'R' : '82',
|
||||
}
|
||||
|
||||
glancesApp.service('favicoService', function() {
|
||||
|
||||
var favico = new Favico({
|
||||
animation : 'none'
|
||||
});
|
||||
|
||||
this.badge = function(nb) {
|
||||
favico.badge(nb);
|
||||
};
|
||||
|
||||
this.reset = function() {
|
||||
favico.reset();
|
||||
};
|
||||
});
|
||||
|
||||
glancesApp.service('GlancesStats', ["$http", "$injector", "$q", "GlancesPlugin", function($http, $injector, $q, GlancesPlugin) {
|
||||
var _stats = [], _views = [], _limits = [];
|
||||
|
||||
@@ -412,7 +438,7 @@ glancesApp.service('GlancesStats', ["$http", "$injector", "$q", "GlancesPlugin",
|
||||
'alert': 'GlancesPluginAlert',
|
||||
'cpu': 'GlancesPluginCpu',
|
||||
'diskio': 'GlancesPluginDiskio',
|
||||
'irq' : 'GlancesPluginIrq',
|
||||
'irq' : 'GlancesPluginIrq',
|
||||
'docker': 'GlancesPluginDocker',
|
||||
'ip': 'GlancesPluginIp',
|
||||
'fs': 'GlancesPluginFs',
|
||||
@@ -430,7 +456,8 @@ glancesApp.service('GlancesStats', ["$http", "$injector", "$q", "GlancesPlugin",
|
||||
'sensors': 'GlancesPluginSensors',
|
||||
'system': 'GlancesPluginSystem',
|
||||
'uptime': 'GlancesPluginUptime',
|
||||
'ports': 'GlancesPluginPorts'
|
||||
'ports': 'GlancesPluginPorts',
|
||||
'wifi': 'GlancesPluginWifi'
|
||||
};
|
||||
|
||||
this.getData = function() {
|
||||
@@ -532,7 +559,7 @@ glancesApp.service('GlancesPluginAlert', function () {
|
||||
, minutes = parseInt((duration / (1000 * 60)) % 60)
|
||||
, hours = parseInt((duration / (1000 * 60 * 60)) % 24);
|
||||
|
||||
alert.duration = _.padLeft(hours, 2, '0') + ":" + _.padLeft(minutes, 2, '0') + ":" + _.padLeft(seconds, 2, '0');
|
||||
alert.duration = _.padStart(hours, 2, '0') + ":" + _.padStart(minutes, 2, '0') + ":" + _.padStart(seconds, 2, '0');
|
||||
}
|
||||
|
||||
_alerts.push(alert);
|
||||
@@ -550,6 +577,14 @@ glancesApp.service('GlancesPluginAlert', function () {
|
||||
this.count = function () {
|
||||
return _alerts.length;
|
||||
};
|
||||
|
||||
this.hasOngoingAlerts = function () {
|
||||
return _.filter(_alerts, { 'ongoing': true }).length > 0;
|
||||
};
|
||||
|
||||
this.countOngoingAlerts = function () {
|
||||
return _.filter(_alerts, { 'ongoing': true }).length;
|
||||
}
|
||||
});
|
||||
|
||||
glancesApp.service('GlancesPluginAmps', function() {
|
||||
@@ -824,7 +859,7 @@ glancesApp.service('GlancesPluginIrq', function() {
|
||||
|
||||
var irq = {
|
||||
'irq_line': IrqData['irq_line'],
|
||||
'irq_rate': IrqData['irq_rate']
|
||||
'irq_rate': IrqData['irq_rate']
|
||||
};
|
||||
|
||||
this.irqs.push(irq);
|
||||
@@ -1176,7 +1211,7 @@ glancesApp.service('GlancesPluginRaid', function () {
|
||||
this.disks = [];
|
||||
|
||||
this.setData = function (data, views) {
|
||||
this.disks = [];
|
||||
var disks = [];
|
||||
data = data[_pluginName];
|
||||
|
||||
_.forIn(data, function(diskData, diskKey) {
|
||||
@@ -1199,8 +1234,10 @@ glancesApp.service('GlancesPluginRaid', function () {
|
||||
});
|
||||
});
|
||||
|
||||
this.disks.push(disk);
|
||||
}, this);
|
||||
disks.push(disk);
|
||||
});
|
||||
|
||||
this.disks = disks;
|
||||
};
|
||||
|
||||
this.hasDisks = function() {
|
||||
@@ -1287,3 +1324,40 @@ glancesApp.service('GlancesPluginUptime', function() {
|
||||
this.uptime = data['uptime'];
|
||||
};
|
||||
});
|
||||
|
||||
glancesApp.service('GlancesPluginWifi', function() {
|
||||
var _pluginName = "wifi";
|
||||
var _view = {};
|
||||
this.hotspots = [];
|
||||
|
||||
this.setData = function(data, views) {
|
||||
data = data[_pluginName];
|
||||
_view = views[_pluginName];
|
||||
|
||||
this.hotspots = [];
|
||||
for (var i = 0; i < data.length; i++) {
|
||||
var hotspotData = data[i];
|
||||
|
||||
if (hotspotData['ssid'] === '') {
|
||||
continue;
|
||||
}
|
||||
|
||||
var hotspot = {
|
||||
'ssid': hotspotData['ssid'],
|
||||
'encrypted': hotspotData['encrypted'],
|
||||
'signal': hotspotData['signal'],
|
||||
'encryption_type': hotspotData['encryption_type'],
|
||||
};
|
||||
|
||||
this.hotspots.push(hotspot);
|
||||
}
|
||||
};
|
||||
|
||||
this.getDecoration = function(hotpost, field) {
|
||||
if(_view[hotpost.ssid][field] == undefined) {
|
||||
return;
|
||||
}
|
||||
|
||||
return _view[hotpost.ssid][field].decoration.toLowerCase();
|
||||
};
|
||||
});
|
||||
@@ -21,4 +21,5 @@ $templateCache.put('plugins/quicklook.html','<div class="cpu-name">\n {{ stat
|
||||
$templateCache.put('plugins/raid.html','<div class="table-row">\n <div class="table-cell text-left title">RAID disks</div>\n <div class="table-cell">Used</div>\n <div class="table-cell">Total</div>\n</div>\n<div class="table-row" ng-repeat="disk in statsRaid.disks | orderBy: \'name\'">\n <div class="table-cell text-left">\n {{ disk.type | uppercase }} {{ disk.name }}\n <div class="warning" ng-show="disk.degraded">\u2514\u2500 Degraded mode</div>\n <div ng-show="disk.degraded"> \u2514\u2500 {{ disk.config }}</div>\n\n <div class="critical" ng-show="disk.inactive">\u2514\u2500 Status {{ disk.status }}</div>\n <div ng-show="disk.inactive" ng-repeat="component in disk.components | orderBy: \'number\'">\n {{ $last ? \'\u2514\u2500\' : \'\u251C\u2500\' }} disk {{ component.number }}: {{ component.name }}\n </div>\n </div>\n <div class="table-cell" ng-show="!disk.inactive" ng-class="statsRaid.getAlert(disk)">{{ disk.used }}</div>\n <div class="table-cell" ng-show="!disk.inactive" ng-class="statsRaid.getAlert(disk)">{{ disk.available }}</div>\n</div>');
|
||||
$templateCache.put('plugins/sensors.html','<div class="table-row">\n <div class="table-cell text-left title">SENSORS</div>\n</div>\n\n<div class="table-row" ng-repeat="sensor in statsSensors.sensors">\n <div class="table-cell text-left">{{ sensor.label }}</div>\n <div class="table-cell">{{ sensor.unit }}</div>\n <div class="table-cell" ng-class="statsSensors.getAlert(sensor)">{{ sensor.value }}</div>\n</div>\n');
|
||||
$templateCache.put('plugins/system.html','<span ng-if="is_disconnected" class="critical">Disconnected from</span>\n<span class="title">{{ statsSystem.hostname }}</span>\n<span ng-show="statsSystem.isLinux()" class="hidden-xs hidden-sm">({{ statsSystem.humanReadableName }} / {{ statsSystem.os.name }} {{ statsSystem.os.version }})</span>\n<span ng-show="!statsSystem.isLinux()" class="hidden-xs hidden-sm">({{ statsSystem.os.name }} {{ statsSystem.os.version }} {{ statsSystem.platform }})</span>');
|
||||
$templateCache.put('plugins/uptime.html','<span>Uptime: {{ statsUptime.uptime }}</span>\n');}]);
|
||||
$templateCache.put('plugins/uptime.html','<span>Uptime: {{ statsUptime.uptime }}</span>\n');
|
||||
$templateCache.put('plugins/wifi.html','<div class="table-row">\n <div class="table-cell text-left title">WIFI</div>\n <div class="table-cell"></div>\n <div class="table-cell">dBm</div>\n</div>\n<div class="table-row" ng-repeat="hotspot in statsWifi.hotspots | orderBy: \'ssid\'">\n <div class="table-cell text-left">{{ hotspot.ssid|limitTo:20 }} <span ng-if="hotspot.encrypted">{{ hotspot.encryption_type }}</span></div>\n <div class="table-cell"></div>\n <div class="table-cell" ng-class="statsWifi.getDecoration(hotspot, \'signal\')">{{ hotspot.signal }}</div>\n</div>\n');}]);
|
||||
File diff suppressed because it is too large
Load Diff
BIN
glances/outputs/static/public/stats.html
vendored
BIN
glances/outputs/static/public/stats.html
vendored
Binary file not shown.
@@ -26,7 +26,6 @@ import sys
|
||||
import uuid
|
||||
from io import open
|
||||
|
||||
from glances import __appname__
|
||||
from glances.compat import b, input
|
||||
from glances.globals import BSD, LINUX, OSX, WINDOWS
|
||||
from glances.logger import logger
|
||||
@@ -59,7 +58,7 @@ class GlancesPassword(object):
|
||||
app_path = '.'
|
||||
|
||||
# Append the Glances folder
|
||||
app_path = os.path.join(app_path, __appname__)
|
||||
app_path = os.path.join(app_path, 'glances')
|
||||
|
||||
return app_path
|
||||
|
||||
|
||||
@@ -60,7 +60,7 @@ class Plugin(GlancesPlugin):
|
||||
ret = []
|
||||
|
||||
# Only process if display plugin enable...
|
||||
if args.disable_log:
|
||||
if not self.stats and self.is_disable():
|
||||
return ret
|
||||
|
||||
# Build the string message
|
||||
|
||||
@@ -21,7 +21,6 @@
|
||||
|
||||
from glances.compat import iteritems
|
||||
from glances.amps_list import AmpsList as glancesAmpsList
|
||||
from glances.logger import logger
|
||||
from glances.plugins.glances_plugin import GlancesPlugin
|
||||
|
||||
|
||||
@@ -48,6 +47,7 @@ class Plugin(GlancesPlugin):
|
||||
"""Reset/init the stats."""
|
||||
self.stats = []
|
||||
|
||||
@GlancesPlugin._check_decorator
|
||||
@GlancesPlugin._log_result_decorator
|
||||
def update(self):
|
||||
"""Update the AMP list."""
|
||||
@@ -97,7 +97,7 @@ class Plugin(GlancesPlugin):
|
||||
# Only process if stats exist and display plugin enable...
|
||||
ret = []
|
||||
|
||||
if not self.stats or args.disable_process or args.disable_amps:
|
||||
if not self.stats or args.disable_process or self.is_disable():
|
||||
return ret
|
||||
|
||||
# Build the string message
|
||||
|
||||
@@ -54,6 +54,7 @@ class Plugin(GlancesPlugin):
|
||||
"""Reset/init the stats."""
|
||||
self.stats = []
|
||||
|
||||
@GlancesPlugin._check_decorator
|
||||
@GlancesPlugin._log_result_decorator
|
||||
def update(self):
|
||||
"""Update battery capacity stats using the input method."""
|
||||
|
||||
@@ -84,9 +84,11 @@ class Plugin(GlancesPlugin):
|
||||
"""Reset/init the stats."""
|
||||
self.stats = {}
|
||||
|
||||
@GlancesPlugin._check_decorator
|
||||
@GlancesPlugin._log_result_decorator
|
||||
def update(self):
|
||||
"""Update CPU stats using the input method."""
|
||||
|
||||
# Reset stats
|
||||
self.reset()
|
||||
|
||||
@@ -96,12 +98,6 @@ class Plugin(GlancesPlugin):
|
||||
elif self.input_method == 'snmp':
|
||||
self.update_snmp()
|
||||
|
||||
# Update the history list
|
||||
self.update_stats_history()
|
||||
|
||||
# Update the view
|
||||
self.update_views()
|
||||
|
||||
return self.stats
|
||||
|
||||
def update_local(self):
|
||||
@@ -140,7 +136,8 @@ class Plugin(GlancesPlugin):
|
||||
self.cpu_stats_old = cpu_stats
|
||||
else:
|
||||
for stat in cpu_stats._fields:
|
||||
self.stats[stat] = getattr(cpu_stats, stat) - getattr(self.cpu_stats_old, stat)
|
||||
if getattr(cpu_stats, stat) is not None:
|
||||
self.stats[stat] = getattr(cpu_stats, stat) - getattr(self.cpu_stats_old, stat)
|
||||
|
||||
self.stats['time_since_update'] = time_since_update
|
||||
|
||||
@@ -223,7 +220,7 @@ class Plugin(GlancesPlugin):
|
||||
ret = []
|
||||
|
||||
# Only process if stats exist and plugin not disable
|
||||
if not self.stats or args.disable_cpu:
|
||||
if not self.stats or self.is_disable():
|
||||
return ret
|
||||
|
||||
# Build the string message
|
||||
|
||||
@@ -65,6 +65,7 @@ class Plugin(GlancesPlugin):
|
||||
"""Reset/init the stats."""
|
||||
self.stats = []
|
||||
|
||||
@GlancesPlugin._check_decorator
|
||||
@GlancesPlugin._log_result_decorator
|
||||
def update(self):
|
||||
"""Update disk I/O stats using the input method."""
|
||||
@@ -141,12 +142,6 @@ class Plugin(GlancesPlugin):
|
||||
# No standard way for the moment...
|
||||
pass
|
||||
|
||||
# Update the history list
|
||||
self.update_stats_history('disk_name')
|
||||
|
||||
# Update the view
|
||||
self.update_views()
|
||||
|
||||
return self.stats
|
||||
|
||||
def update_views(self):
|
||||
@@ -169,7 +164,7 @@ class Plugin(GlancesPlugin):
|
||||
ret = []
|
||||
|
||||
# Only process if stats exist and display plugin enable...
|
||||
if not self.stats or args.disable_diskio:
|
||||
if not self.stats or self.is_disable():
|
||||
return ret
|
||||
|
||||
# Build the string message
|
||||
|
||||
@@ -66,6 +66,9 @@ class Plugin(GlancesPlugin):
|
||||
# value: instance of ThreadDockerGrabber
|
||||
self.thread_list = {}
|
||||
|
||||
# Init the stats
|
||||
self.reset()
|
||||
|
||||
def exit(self):
|
||||
"""Overwrite the exit method to close threads"""
|
||||
for t in itervalues(self.thread_list):
|
||||
@@ -141,22 +144,28 @@ class Plugin(GlancesPlugin):
|
||||
"""Reset/init the stats."""
|
||||
self.stats = {}
|
||||
|
||||
@GlancesPlugin._check_decorator
|
||||
@GlancesPlugin._log_result_decorator
|
||||
def update(self):
|
||||
"""Update Docker stats using the input method."""
|
||||
global docker_tag
|
||||
|
||||
# Reset stats
|
||||
self.reset()
|
||||
|
||||
# Get the current Docker API client
|
||||
if not self.docker_client:
|
||||
# First time, try to connect to the server
|
||||
self.docker_client = self.connect()
|
||||
if self.docker_client is None:
|
||||
global docker_tag
|
||||
try:
|
||||
self.docker_client = self.connect()
|
||||
except:
|
||||
docker_tag = False
|
||||
else:
|
||||
if self.docker_client is None:
|
||||
docker_tag = False
|
||||
|
||||
# The Docker-py lib is mandatory
|
||||
if not docker_tag or (self.args is not None and self.args.disable_docker):
|
||||
if not docker_tag:
|
||||
return self.stats
|
||||
|
||||
if self.input_method == 'local':
|
||||
@@ -356,7 +365,7 @@ class Plugin(GlancesPlugin):
|
||||
network_new['tx'] = netcounters["eth0"]["tx_bytes"] - self.netcounters_old[container_id]["eth0"]["tx_bytes"]
|
||||
network_new['cumulative_rx'] = netcounters["eth0"]["rx_bytes"]
|
||||
network_new['cumulative_tx'] = netcounters["eth0"]["tx_bytes"]
|
||||
except KeyError:
|
||||
except KeyError as e:
|
||||
# all_stats do not have INTERFACE information
|
||||
logger.debug("Can not grab network interface usage for container {0} ({1})".format(container_id, e))
|
||||
logger.debug(all_stats)
|
||||
@@ -434,13 +443,59 @@ class Plugin(GlancesPlugin):
|
||||
"""Return the user ticks by reading the environment variable."""
|
||||
return os.sysconf(os.sysconf_names['SC_CLK_TCK'])
|
||||
|
||||
def get_stats_action(self):
|
||||
"""Return stats for the action
|
||||
Docker will return self.stats['containers']"""
|
||||
return self.stats['containers']
|
||||
|
||||
def update_views(self):
|
||||
"""Update stats views."""
|
||||
# Call the father's method
|
||||
super(Plugin, self).update_views()
|
||||
|
||||
if 'containers' not in self.stats:
|
||||
return False
|
||||
|
||||
# Add specifics informations
|
||||
# Alert
|
||||
for i in self.stats['containers']:
|
||||
# Init the views for the current container (key = container name)
|
||||
self.views[i[self.get_key()]] = {'cpu': {}, 'mem': {}}
|
||||
# CPU alert
|
||||
if 'cpu' in i and 'total' in i['cpu']:
|
||||
# Looking for specific CPU container threasold in the conf file
|
||||
alert = self.get_alert(i['cpu']['total'],
|
||||
header=i['name'] + '_cpu',
|
||||
action_key=i['name'])
|
||||
if alert == 'DEFAULT':
|
||||
# Not found ? Get back to default CPU threasold value
|
||||
alert = self.get_alert(i['cpu']['total'], header='cpu')
|
||||
self.views[i[self.get_key()]]['cpu']['decoration'] = alert
|
||||
# MEM alert
|
||||
if 'memory' in i and 'usage' in i['memory']:
|
||||
# Looking for specific MEM container threasold in the conf file
|
||||
alert = self.get_alert(i['memory']['usage'],
|
||||
maximum=i['memory']['limit'],
|
||||
header=i['name'] + '_mem',
|
||||
action_key=i['name'])
|
||||
if alert == 'DEFAULT':
|
||||
# Not found ? Get back to default MEM threasold value
|
||||
alert = self.get_alert(i['memory']['usage'],
|
||||
maximum=i['memory']['limit'],
|
||||
header='mem')
|
||||
self.views[i[self.get_key()]]['mem']['decoration'] = alert
|
||||
|
||||
return True
|
||||
|
||||
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 non null) and display plugin enable...
|
||||
if not self.stats or args.disable_docker or len(self.stats['containers']) == 0:
|
||||
if not self.stats \
|
||||
or len(self.stats['containers']) == 0 \
|
||||
or self.is_disable():
|
||||
return ret
|
||||
|
||||
# Build the string message
|
||||
@@ -502,13 +557,17 @@ class Plugin(GlancesPlugin):
|
||||
msg = '{:>6.1f}'.format(container['cpu']['total'])
|
||||
except KeyError:
|
||||
msg = '{:>6}'.format('?')
|
||||
ret.append(self.curse_add_line(msg))
|
||||
ret.append(self.curse_add_line(msg, self.get_views(item=container['name'],
|
||||
key='cpu',
|
||||
option='decoration')))
|
||||
# MEM
|
||||
try:
|
||||
msg = '{:>7}'.format(self.auto_unit(container['memory']['usage']))
|
||||
except KeyError:
|
||||
msg = '{:>7}'.format('?')
|
||||
ret.append(self.curse_add_line(msg))
|
||||
ret.append(self.curse_add_line(msg, self.get_views(item=container['name'],
|
||||
key='mem',
|
||||
option='decoration')))
|
||||
try:
|
||||
msg = '{:>7}'.format(self.auto_unit(container['memory']['limit']))
|
||||
except KeyError:
|
||||
|
||||
@@ -52,6 +52,8 @@ class Plugin(GlancesPlugin):
|
||||
"""Load the foldered list from the config file, if it exists."""
|
||||
self.glances_folders = glancesFolderList(config)
|
||||
|
||||
@GlancesPlugin._check_decorator
|
||||
@GlancesPlugin._log_result_decorator
|
||||
def update(self):
|
||||
"""Update the foldered list."""
|
||||
# Reset the list
|
||||
@@ -96,7 +98,7 @@ class Plugin(GlancesPlugin):
|
||||
ret = []
|
||||
|
||||
# Only process if stats exist and display plugin enable...
|
||||
if not self.stats or args.disable_folder:
|
||||
if not self.stats or self.is_disable():
|
||||
return ret
|
||||
|
||||
# Build the string message
|
||||
|
||||
@@ -89,6 +89,7 @@ class Plugin(GlancesPlugin):
|
||||
"""Reset/init the stats."""
|
||||
self.stats = []
|
||||
|
||||
@GlancesPlugin._check_decorator
|
||||
@GlancesPlugin._log_result_decorator
|
||||
def update(self):
|
||||
"""Update the FS stats using the input method."""
|
||||
@@ -179,12 +180,6 @@ class Plugin(GlancesPlugin):
|
||||
'key': self.get_key()}
|
||||
self.stats.append(fs_current)
|
||||
|
||||
# Update the history list
|
||||
self.update_stats_history('mnt_point')
|
||||
|
||||
# Update the view
|
||||
self.update_views()
|
||||
|
||||
return self.stats
|
||||
|
||||
def update_views(self):
|
||||
@@ -204,7 +199,7 @@ class Plugin(GlancesPlugin):
|
||||
ret = []
|
||||
|
||||
# Only process if stats exist and display plugin enable...
|
||||
if not self.stats or args.disable_fs:
|
||||
if not self.stats or self.is_disable():
|
||||
return ret
|
||||
|
||||
# Max size for the fsname name
|
||||
|
||||
@@ -52,6 +52,8 @@ class Plugin(GlancesPlugin):
|
||||
"""Reset/init the stats."""
|
||||
self.stats = []
|
||||
|
||||
@GlancesPlugin._check_decorator
|
||||
@GlancesPlugin._log_result_decorator
|
||||
def update(self):
|
||||
"""Update HDD stats using the input method."""
|
||||
# Reset stats
|
||||
@@ -90,10 +92,6 @@ class GlancesGrabHDDTemp(object):
|
||||
# Reset the list
|
||||
self.reset()
|
||||
|
||||
# Only update if --disable-hddtemp is not set
|
||||
if self.args is None or self.args.disable_hddtemp:
|
||||
return
|
||||
|
||||
# Fetch the data
|
||||
# data = ("|/dev/sda|WDC WD2500JS-75MHB0|44|C|"
|
||||
# "|/dev/sdb|WDC WD2500JS-75MHB0|35|C|"
|
||||
@@ -146,7 +144,8 @@ class GlancesGrabHDDTemp(object):
|
||||
except socket.error as e:
|
||||
logger.debug("Cannot connect to an HDDtemp server ({}:{} => {})".format(self.host, self.port, e))
|
||||
logger.debug("Disable the HDDtemp module. Use the --disable-hddtemp to hide the previous message.")
|
||||
self.args.disable_hddtemp = True
|
||||
if self.args is not None:
|
||||
self.args.disable_hddtemp = True
|
||||
data = ""
|
||||
finally:
|
||||
sck.close()
|
||||
|
||||
@@ -23,7 +23,7 @@ Help plugin.
|
||||
Just a stupid plugin to display the help screen.
|
||||
"""
|
||||
|
||||
from glances import __appname__, __version__, psutil_version
|
||||
from glances import __version__, psutil_version
|
||||
from glances.plugins.glances_plugin import GlancesPlugin
|
||||
|
||||
|
||||
@@ -50,7 +50,7 @@ class Plugin(GlancesPlugin):
|
||||
pass
|
||||
|
||||
def generate_view_data(self):
|
||||
self.view_data['version'] = '{0} {1}'.format(__appname__.title(), __version__)
|
||||
self.view_data['version'] = '{0} {1}'.format('Glances', __version__)
|
||||
self.view_data['psutil_version'] = ' with PSutil {0}'.format(psutil_version)
|
||||
|
||||
try:
|
||||
|
||||
@@ -22,7 +22,7 @@
|
||||
import threading
|
||||
from json import loads
|
||||
|
||||
from glances.compat import iterkeys, urlopen, URLError, queue
|
||||
from glances.compat import iterkeys, urlopen, queue
|
||||
from glances.globals import BSD
|
||||
from glances.logger import logger
|
||||
from glances.timer import Timer
|
||||
@@ -75,6 +75,7 @@ class Plugin(GlancesPlugin):
|
||||
"""Reset/init the stats."""
|
||||
self.stats = {}
|
||||
|
||||
@GlancesPlugin._check_decorator
|
||||
@GlancesPlugin._log_result_decorator
|
||||
def update(self):
|
||||
"""Update IP stats using the input method.
|
||||
@@ -104,9 +105,6 @@ class Plugin(GlancesPlugin):
|
||||
# Not implemented yet
|
||||
pass
|
||||
|
||||
# Update the view
|
||||
self.update_views()
|
||||
|
||||
return self.stats
|
||||
|
||||
def update_views(self):
|
||||
@@ -125,7 +123,7 @@ class Plugin(GlancesPlugin):
|
||||
ret = []
|
||||
|
||||
# Only process if stats exist and display plugin enable...
|
||||
if not self.stats or args.disable_ip:
|
||||
if not self.stats or self.is_disable():
|
||||
return ret
|
||||
|
||||
# Build the string message
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
#
|
||||
# This file is part of Glances.
|
||||
#
|
||||
# Copyright (C) 2015 Angelo Poerio <angelo.poerio@gmail.com>
|
||||
# Copyright (C) 2016 Angelo Poerio <angelo.poerio@gmail.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
|
||||
@@ -19,7 +19,10 @@
|
||||
|
||||
"""IRQ plugin."""
|
||||
|
||||
import os
|
||||
import operator
|
||||
|
||||
from glances.logger import logger
|
||||
from glances.globals import LINUX
|
||||
from glances.timer import getTimeSinceLastUpdate
|
||||
from glances.plugins.glances_plugin import GlancesPlugin
|
||||
@@ -39,19 +42,19 @@ class Plugin(GlancesPlugin):
|
||||
# We want to display the stat in the curse interface
|
||||
self.display_curse = True
|
||||
|
||||
self.lasts = {}
|
||||
|
||||
# Init the stats
|
||||
self.irq = GlancesIRQ()
|
||||
self.reset()
|
||||
|
||||
def get_key(self):
|
||||
"""Return the key of the list."""
|
||||
return 'irq_line'
|
||||
return self.irq.get_key()
|
||||
|
||||
def reset(self):
|
||||
"""Reset/init the stats."""
|
||||
self.stats = []
|
||||
|
||||
@GlancesPlugin._check_decorator
|
||||
@GlancesPlugin._log_result_decorator
|
||||
def update(self):
|
||||
"""Update the IRQ stats"""
|
||||
@@ -59,40 +62,22 @@ class Plugin(GlancesPlugin):
|
||||
# Reset the list
|
||||
self.reset()
|
||||
|
||||
if not LINUX: # only available on GNU/Linux
|
||||
# IRQ plugin only available on GNU/Linux
|
||||
if not LINUX:
|
||||
return self.stats
|
||||
|
||||
if self.input_method == 'local':
|
||||
with open('/proc/interrupts') as irq_proc:
|
||||
time_since_update = getTimeSinceLastUpdate('irq')
|
||||
irq_proc.readline() # skip header line
|
||||
for irq_line in irq_proc.readlines():
|
||||
splitted_line = irq_line.split()
|
||||
irq_line = splitted_line[0].replace(':', '')
|
||||
current_irqs = sum([int(count) for count in splitted_line[
|
||||
1:] if count.isdigit()]) # sum interrupts on all CPUs
|
||||
irq_rate = int(
|
||||
current_irqs -
|
||||
self.lasts.get(irq_line) if self.lasts.get(irq_line) else 0 //
|
||||
time_since_update)
|
||||
irq_current = {
|
||||
'irq_line': irq_line,
|
||||
'irq_rate': irq_rate,
|
||||
'key': self.get_key(),
|
||||
'time_since_update': time_since_update
|
||||
}
|
||||
self.stats.append(irq_current)
|
||||
self.lasts[irq_line] = current_irqs
|
||||
# Grab the stats
|
||||
self.stats = self.irq.get()
|
||||
|
||||
elif self.input_method == 'snmp':
|
||||
# not available
|
||||
pass
|
||||
|
||||
# Update the view
|
||||
self.update_views()
|
||||
|
||||
# Get the TOP 5
|
||||
self.stats = sorted(self.stats, key=operator.itemgetter(
|
||||
'irq_rate'), reverse=True)[:5] # top 5 IRQ by rate/s
|
||||
|
||||
return self.stats
|
||||
|
||||
def update_views(self):
|
||||
@@ -105,11 +90,9 @@ class Plugin(GlancesPlugin):
|
||||
# Init the return message
|
||||
ret = []
|
||||
|
||||
if not LINUX: # only available on GNU/Linux
|
||||
return ret
|
||||
|
||||
# Only available on GNU/Linux
|
||||
# Only process if stats exist and display plugin enable...
|
||||
if not self.stats or args.disable_irq:
|
||||
if not LINUX or not self.stats or not self.args.enable_irq:
|
||||
return ret
|
||||
|
||||
if max_width is not None and max_width >= 23:
|
||||
@@ -126,9 +109,111 @@ class Plugin(GlancesPlugin):
|
||||
|
||||
for i in self.stats:
|
||||
ret.append(self.curse_new_line())
|
||||
msg = '{:>3}'.format(i['irq_line'])
|
||||
msg = '{:<15}'.format(i['irq_line'][:15])
|
||||
ret.append(self.curse_add_line(msg))
|
||||
msg = '{:>20}'.format(str(i['irq_rate']))
|
||||
msg = '{:>8}'.format(str(i['irq_rate']))
|
||||
ret.append(self.curse_add_line(msg))
|
||||
|
||||
return ret
|
||||
|
||||
|
||||
class GlancesIRQ(object):
|
||||
"""
|
||||
This class manages the IRQ file
|
||||
"""
|
||||
|
||||
IRQ_FILE = '/proc/interrupts'
|
||||
|
||||
def __init__(self):
|
||||
"""
|
||||
Init the class
|
||||
The stat are stored in a internal list of dict
|
||||
"""
|
||||
self.lasts = {}
|
||||
self.reset()
|
||||
|
||||
def reset(self):
|
||||
"""Reset the stats"""
|
||||
self.stats = []
|
||||
self.cpu_number = 0
|
||||
|
||||
def get(self):
|
||||
"""Return the current IRQ stats"""
|
||||
return self.__update()
|
||||
|
||||
def get_key(self):
|
||||
"""Return the key of the dict."""
|
||||
return 'irq_line'
|
||||
|
||||
def __header(self, line):
|
||||
"""The header contain the number of CPU
|
||||
|
||||
CPU0 CPU1 CPU2 CPU3
|
||||
0: 21 0 0 0 IO-APIC 2-edge timer
|
||||
"""
|
||||
self.cpu_number = len(line.split())
|
||||
return self.cpu_number
|
||||
|
||||
def __humanname(self, line):
|
||||
"""Get a line and
|
||||
Return the IRQ name, alias or number (choose the best for human)
|
||||
|
||||
IRQ line samples:
|
||||
1: 44487 341 44 72 IO-APIC 1-edge i8042
|
||||
LOC: 33549868 22394684 32474570 21855077 Local timer interrupts
|
||||
"""
|
||||
splitted_line = line.split()
|
||||
irq_line = splitted_line[0].replace(':', '')
|
||||
if irq_line.isdigit():
|
||||
# If the first column is a digit, use the alias (last column)
|
||||
irq_line += '_{}'.format(splitted_line[-1])
|
||||
return irq_line
|
||||
|
||||
def __sum(self, line):
|
||||
"""Get a line and
|
||||
Return the IRQ sum number
|
||||
|
||||
IRQ line samples:
|
||||
1: 44487 341 44 72 IO-APIC 1-edge i8042
|
||||
LOC: 33549868 22394684 32474570 21855077 Local timer interrupts
|
||||
"""
|
||||
splitted_line = line.split()
|
||||
# sum interrupts on all CPUs
|
||||
return sum(map(int, splitted_line[1:(self.cpu_number + 1)]))
|
||||
|
||||
def __update(self):
|
||||
"""
|
||||
Load the IRQ file and update the internal dict
|
||||
"""
|
||||
|
||||
self.reset()
|
||||
|
||||
if not os.path.exists(self.IRQ_FILE):
|
||||
# Correct issue #947: IRQ file do not exist on OpenVZ container
|
||||
return self.stats
|
||||
|
||||
try:
|
||||
with open(self.IRQ_FILE) as irq_proc:
|
||||
time_since_update = getTimeSinceLastUpdate('irq')
|
||||
# Read the header
|
||||
self.__header(irq_proc.readline())
|
||||
# Read the rest of the lines (one line per IRQ)
|
||||
for line in irq_proc.readlines():
|
||||
irq_line = self.__humanname(line)
|
||||
current_irqs = self.__sum(line)
|
||||
irq_rate = int(
|
||||
current_irqs - self.lasts.get(irq_line)
|
||||
if self.lasts.get(irq_line)
|
||||
else 0 // time_since_update)
|
||||
irq_current = {
|
||||
'irq_line': irq_line,
|
||||
'irq_rate': irq_rate,
|
||||
'key': self.get_key(),
|
||||
'time_since_update': time_since_update
|
||||
}
|
||||
self.stats.append(irq_current)
|
||||
self.lasts[irq_line] = current_irqs
|
||||
except (OSError, IOError):
|
||||
pass
|
||||
|
||||
return self.stats
|
||||
|
||||
@@ -74,6 +74,7 @@ class Plugin(GlancesPlugin):
|
||||
"""Reset/init the stats."""
|
||||
self.stats = {}
|
||||
|
||||
@GlancesPlugin._check_decorator
|
||||
@GlancesPlugin._log_result_decorator
|
||||
def update(self):
|
||||
"""Update load stats."""
|
||||
@@ -108,12 +109,6 @@ class Plugin(GlancesPlugin):
|
||||
|
||||
self.stats['cpucore'] = self.nb_log_core
|
||||
|
||||
# Update the history list
|
||||
self.update_stats_history()
|
||||
|
||||
# Update the view
|
||||
self.update_views()
|
||||
|
||||
return self.stats
|
||||
|
||||
def update_views(self):
|
||||
@@ -137,7 +132,7 @@ class Plugin(GlancesPlugin):
|
||||
ret = []
|
||||
|
||||
# Only process if stats exist, not empty (issue #871) and plugin not disabled
|
||||
if not self.stats or (self.stats == {}) or args.disable_load:
|
||||
if not self.stats or (self.stats == {}) or self.is_disable():
|
||||
return ret
|
||||
|
||||
# Build the string message
|
||||
|
||||
@@ -76,6 +76,7 @@ class Plugin(GlancesPlugin):
|
||||
"""Reset/init the stats."""
|
||||
self.stats = {}
|
||||
|
||||
@GlancesPlugin._check_decorator
|
||||
@GlancesPlugin._log_result_decorator
|
||||
def update(self):
|
||||
"""Update RAM memory stats using the input method."""
|
||||
@@ -156,12 +157,6 @@ class Plugin(GlancesPlugin):
|
||||
# percent: the percentage usage calculated as (total - available) / total * 100.
|
||||
self.stats['percent'] = float((self.stats['total'] - self.stats['free']) / self.stats['total'] * 100)
|
||||
|
||||
# Update the history list
|
||||
self.update_stats_history()
|
||||
|
||||
# Update the view
|
||||
self.update_views()
|
||||
|
||||
return self.stats
|
||||
|
||||
def update_views(self):
|
||||
@@ -183,7 +178,7 @@ class Plugin(GlancesPlugin):
|
||||
ret = []
|
||||
|
||||
# Only process if stats exist and plugin not disabled
|
||||
if not self.stats or args.disable_mem:
|
||||
if not self.stats or self.is_disable():
|
||||
return ret
|
||||
|
||||
# Build the string message
|
||||
|
||||
@@ -64,6 +64,7 @@ class Plugin(GlancesPlugin):
|
||||
"""Reset/init the stats."""
|
||||
self.stats = {}
|
||||
|
||||
@GlancesPlugin._check_decorator
|
||||
@GlancesPlugin._log_result_decorator
|
||||
def update(self):
|
||||
"""Update swap memory stats using the input method."""
|
||||
@@ -131,12 +132,6 @@ class Plugin(GlancesPlugin):
|
||||
self.stats['percent'] = float(
|
||||
(self.stats['total'] - self.stats['free']) / self.stats['total'] * 100)
|
||||
|
||||
# Update the history list
|
||||
self.update_stats_history()
|
||||
|
||||
# Update the view
|
||||
self.update_views()
|
||||
|
||||
return self.stats
|
||||
|
||||
def update_views(self):
|
||||
@@ -154,7 +149,7 @@ class Plugin(GlancesPlugin):
|
||||
ret = []
|
||||
|
||||
# Only process if stats exist and plugin not disabled
|
||||
if not self.stats or args.disable_swap:
|
||||
if not self.stats or self.is_disable():
|
||||
return ret
|
||||
|
||||
# Build the string message
|
||||
|
||||
@@ -22,6 +22,7 @@
|
||||
import base64
|
||||
import operator
|
||||
|
||||
from glances.logger import logger
|
||||
from glances.timer import getTimeSinceLastUpdate
|
||||
from glances.plugins.glances_plugin import GlancesPlugin
|
||||
|
||||
@@ -72,6 +73,7 @@ class Plugin(GlancesPlugin):
|
||||
"""Reset/init the stats."""
|
||||
self.stats = []
|
||||
|
||||
@GlancesPlugin._check_decorator
|
||||
@GlancesPlugin._log_result_decorator
|
||||
def update(self):
|
||||
"""Update network stats using the input method.
|
||||
@@ -90,7 +92,9 @@ class Plugin(GlancesPlugin):
|
||||
except UnicodeDecodeError:
|
||||
return self.stats
|
||||
|
||||
# New in PsUtil 3.0: optionaly import the interface's status (issue #765)
|
||||
# New in PsUtil 3.0
|
||||
# - import the interface's status (issue #765)
|
||||
# - import the interface's speed (issue #718)
|
||||
netstatus = {}
|
||||
try:
|
||||
netstatus = psutil.net_if_stats()
|
||||
@@ -136,11 +140,19 @@ class Plugin(GlancesPlugin):
|
||||
continue
|
||||
else:
|
||||
# Optional stats (only compliant with PsUtil 3.0+)
|
||||
# Interface status
|
||||
try:
|
||||
netstat['is_up'] = netstatus[net].isup
|
||||
except (KeyError, AttributeError):
|
||||
pass
|
||||
# Set the key
|
||||
# Interface speed in Mbps, convert it to bps
|
||||
# Can be always 0 on some OS
|
||||
try:
|
||||
netstat['speed'] = netstatus[net].speed * 1048576
|
||||
except (KeyError, AttributeError):
|
||||
pass
|
||||
|
||||
# Finaly, set the key
|
||||
netstat['key'] = self.get_key()
|
||||
self.stats.append(netstat)
|
||||
|
||||
@@ -212,12 +224,6 @@ class Plugin(GlancesPlugin):
|
||||
# Save stats to compute next bitrate
|
||||
self.network_old = network_new
|
||||
|
||||
# Update the history list
|
||||
self.update_stats_history(self.get_key())
|
||||
|
||||
# Update the view
|
||||
self.update_views()
|
||||
|
||||
return self.stats
|
||||
|
||||
def update_views(self):
|
||||
@@ -229,10 +235,25 @@ class Plugin(GlancesPlugin):
|
||||
# Alert
|
||||
for i in self.stats:
|
||||
ifrealname = i['interface_name'].split(':')[0]
|
||||
self.views[i[self.get_key()]]['rx']['decoration'] = self.get_alert(int(i['rx'] // i['time_since_update'] * 8),
|
||||
header=ifrealname + '_rx')
|
||||
self.views[i[self.get_key()]]['tx']['decoration'] = self.get_alert(int(i['tx'] // i['time_since_update'] * 8),
|
||||
header=ifrealname + '_tx')
|
||||
# Convert rate in bps ( to be able to compare to interface speed)
|
||||
bps_rx = int(i['rx'] // i['time_since_update'] * 8)
|
||||
bps_tx = int(i['tx'] // i['time_since_update'] * 8)
|
||||
# Decorate the bitrate with the configuration file thresolds
|
||||
alert_rx = self.get_alert(bps_rx, header=ifrealname + '_rx')
|
||||
alert_tx = self.get_alert(bps_tx, header=ifrealname + '_tx')
|
||||
# If nothing is define in the configuration file...
|
||||
# ... then use the interface speed (not available on all systems)
|
||||
if alert_rx == 'DEFAULT' and 'speed' in i and i['speed'] != 0:
|
||||
alert_rx = self.get_alert(current=bps_rx,
|
||||
maximum=i['speed'],
|
||||
header='rx')
|
||||
if alert_tx == 'DEFAULT' and 'speed' in i and i['speed'] != 0:
|
||||
alert_tx = self.get_alert(current=bps_tx,
|
||||
maximum=i['speed'],
|
||||
header='tx')
|
||||
# then decorates
|
||||
self.views[i[self.get_key()]]['rx']['decoration'] = alert_rx
|
||||
self.views[i[self.get_key()]]['tx']['decoration'] = alert_tx
|
||||
|
||||
def msg_curse(self, args=None, max_width=None):
|
||||
"""Return the dict to display in the curse interface."""
|
||||
@@ -240,7 +261,7 @@ class Plugin(GlancesPlugin):
|
||||
ret = []
|
||||
|
||||
# Only process if stats exist and display plugin enable...
|
||||
if not self.stats or args.disable_network:
|
||||
if not self.stats or self.is_disable():
|
||||
return ret
|
||||
|
||||
# Max size for the interface name
|
||||
|
||||
@@ -49,6 +49,8 @@ class Plugin(GlancesPlugin):
|
||||
"""Reset/init the stats."""
|
||||
self.stats = []
|
||||
|
||||
@GlancesPlugin._check_decorator
|
||||
@GlancesPlugin._log_result_decorator
|
||||
def update(self):
|
||||
"""Update per-CPU stats using the input method."""
|
||||
# Reset stats
|
||||
@@ -69,10 +71,6 @@ class Plugin(GlancesPlugin):
|
||||
# Init the return message
|
||||
ret = []
|
||||
|
||||
# Only process if plugin not disable
|
||||
if args.disable_cpu:
|
||||
return ret
|
||||
|
||||
# No per CPU stat ? Exit...
|
||||
if not self.stats:
|
||||
msg = 'PER CPU not available'
|
||||
|
||||
@@ -86,6 +86,19 @@ class GlancesPlugin(object):
|
||||
"""Return the key of the list."""
|
||||
return None
|
||||
|
||||
def is_enable(self):
|
||||
"""Return true if plugin is enabled"""
|
||||
try:
|
||||
d = getattr(self.args, 'disable_' + self.plugin_name)
|
||||
except AttributeError:
|
||||
return True
|
||||
else:
|
||||
return d is False
|
||||
|
||||
def is_disable(self):
|
||||
"""Return true if plugin is disabled"""
|
||||
return not self.is_enable()
|
||||
|
||||
def _json_dumps(self, d):
|
||||
"""Return the object 'd' in a JSON format
|
||||
Manage the issue #815 for Windows OS"""
|
||||
@@ -111,8 +124,14 @@ class GlancesPlugin(object):
|
||||
logger.debug("Reset history for plugin {0} (items: {1})".format(self.plugin_name, reset_list))
|
||||
self.stats_history.reset()
|
||||
|
||||
def update_stats_history(self, item_name=''):
|
||||
def update_stats_history(self):
|
||||
"""Update stats history."""
|
||||
# If the plugin data is a dict, the dict's key should be used
|
||||
if self.get_key() is None:
|
||||
item_name = ''
|
||||
else:
|
||||
item_name = self.get_key()
|
||||
# Build the history
|
||||
if self.stats and self._history_enable():
|
||||
for i in self.get_items_history_list():
|
||||
if isinstance(self.stats, list):
|
||||
@@ -393,7 +412,10 @@ class GlancesPlugin(object):
|
||||
if option is None:
|
||||
return item_views[key]
|
||||
else:
|
||||
return item_views[key][option]
|
||||
if option in item_views[key]:
|
||||
return item_views[key][option]
|
||||
else:
|
||||
return 'DEFAULT'
|
||||
|
||||
def load_limits(self, config):
|
||||
"""Load limits from the configuration file, if it exists."""
|
||||
@@ -432,6 +454,13 @@ class GlancesPlugin(object):
|
||||
"""Set the limits to input_limits."""
|
||||
self._limits = input_limits
|
||||
|
||||
def get_stats_action(self):
|
||||
"""Return stats for the action
|
||||
By default return all the stats.
|
||||
Can be overwrite by plugins implementation.
|
||||
For example, Docker will return self.stats['containers']"""
|
||||
return self.stats
|
||||
|
||||
def get_alert(self,
|
||||
current=0,
|
||||
minimum=0,
|
||||
@@ -439,6 +468,7 @@ class GlancesPlugin(object):
|
||||
highlight_zero=True,
|
||||
is_max=False,
|
||||
header="",
|
||||
action_key=None,
|
||||
log=False):
|
||||
"""Return the alert status relative to a current value.
|
||||
|
||||
@@ -454,6 +484,9 @@ class GlancesPlugin(object):
|
||||
If defined 'header' is added between the plugin name and the status.
|
||||
Only useful for stats with several alert status.
|
||||
|
||||
If defined, 'action_key' define the key for the actions.
|
||||
By default, the action_key is equal to the header.
|
||||
|
||||
If log=True than add log if necessary
|
||||
elif log=False than do not log
|
||||
elif log=None than apply the config given in the conf file
|
||||
@@ -480,11 +513,11 @@ class GlancesPlugin(object):
|
||||
# If is_max is set then display the value in MAX
|
||||
ret = 'MAX' if is_max else 'OK'
|
||||
try:
|
||||
if value > self.__get_limit('critical', stat_name=stat_name):
|
||||
if value >= self.get_limit('critical', stat_name=stat_name):
|
||||
ret = 'CRITICAL'
|
||||
elif value > self.__get_limit('warning', stat_name=stat_name):
|
||||
elif value >= self.get_limit('warning', stat_name=stat_name):
|
||||
ret = 'WARNING'
|
||||
elif value > self.__get_limit('careful', stat_name=stat_name):
|
||||
elif value >= self.get_limit('careful', stat_name=stat_name):
|
||||
ret = 'CAREFUL'
|
||||
elif current < minimum:
|
||||
ret = 'CAREFUL'
|
||||
@@ -493,7 +526,7 @@ class GlancesPlugin(object):
|
||||
|
||||
# Manage log
|
||||
log_str = ""
|
||||
if self.__get_limit_log(stat_name=stat_name, default_action=log):
|
||||
if self.get_limit_log(stat_name=stat_name, default_action=log):
|
||||
# Add _LOG to the return string
|
||||
# So stats will be highlited with a specific color
|
||||
log_str = "_LOG"
|
||||
@@ -501,42 +534,61 @@ class GlancesPlugin(object):
|
||||
glances_logs.add(ret, stat_name.upper(), value)
|
||||
|
||||
# Manage action
|
||||
# Here is a command line for the current trigger ?
|
||||
try:
|
||||
command = self.__get_limit_action(ret.lower(), stat_name=stat_name)
|
||||
except KeyError:
|
||||
# Reset the trigger
|
||||
self.actions.set(stat_name, ret.lower())
|
||||
else:
|
||||
# A command line is available for the current alert, run it
|
||||
# Build the {{mustache}} dictionnary
|
||||
if isinstance(self.stats, list):
|
||||
# If the stats are stored in a list of dict (fs plugin for exemple)
|
||||
# Return the dict for the current header
|
||||
mustache_dict = {}
|
||||
for item in self.stats:
|
||||
if item[self.get_key()] == header:
|
||||
mustache_dict = item
|
||||
break
|
||||
else:
|
||||
# Use the stats dict
|
||||
mustache_dict = self.stats
|
||||
# Run the action
|
||||
self.actions.run(
|
||||
stat_name, ret.lower(), command, mustache_dict=mustache_dict)
|
||||
self.manage_action(stat_name, ret.lower(), header, action_key)
|
||||
|
||||
# Default is ok
|
||||
return ret + log_str
|
||||
|
||||
def get_alert_log(self, current=0, minimum=0, maximum=100, header=""):
|
||||
def manage_action(self,
|
||||
stat_name,
|
||||
trigger,
|
||||
header,
|
||||
action_key):
|
||||
"""Manage the action for the current stat"""
|
||||
# Here is a command line for the current trigger ?
|
||||
try:
|
||||
command = self.get_limit_action(trigger, stat_name=stat_name)
|
||||
except KeyError:
|
||||
# Reset the trigger
|
||||
self.actions.set(stat_name, trigger)
|
||||
else:
|
||||
# Define the action key for the stats dict
|
||||
# If not define, then it sets to header
|
||||
if action_key is None:
|
||||
action_key = header
|
||||
|
||||
# A command line is available for the current alert
|
||||
# 1) Build the {{mustache}} dictionnary
|
||||
if isinstance(self.get_stats_action(), list):
|
||||
# If the stats are stored in a list of dict (fs plugin for exemple)
|
||||
# Return the dict for the current header
|
||||
mustache_dict = {}
|
||||
for item in self.get_stats_action():
|
||||
if item[self.get_key()] == action_key:
|
||||
mustache_dict = item
|
||||
break
|
||||
else:
|
||||
# Use the stats dict
|
||||
mustache_dict = self.get_stats_action()
|
||||
# 2) Run the action
|
||||
self.actions.run(
|
||||
stat_name, trigger, command, mustache_dict=mustache_dict)
|
||||
|
||||
def get_alert_log(self,
|
||||
current=0,
|
||||
minimum=0,
|
||||
maximum=100,
|
||||
header="",
|
||||
action_key=None):
|
||||
"""Get the alert log."""
|
||||
return self.get_alert(current=current,
|
||||
minimum=minimum,
|
||||
maximum=maximum,
|
||||
header=header,
|
||||
action_key=action_key,
|
||||
log=True)
|
||||
|
||||
def __get_limit(self, criticity, stat_name=""):
|
||||
def get_limit(self, criticity, stat_name=""):
|
||||
"""Return the limit value for the alert."""
|
||||
# Get the limit for stat + header
|
||||
# Exemple: network_wlan0_rx_careful
|
||||
@@ -552,7 +604,7 @@ class GlancesPlugin(object):
|
||||
# Return the limit
|
||||
return limit
|
||||
|
||||
def __get_limit_action(self, criticity, stat_name=""):
|
||||
def get_limit_action(self, criticity, stat_name=""):
|
||||
"""Return the action for the alert."""
|
||||
# Get the action for stat + header
|
||||
# Exemple: network_wlan0_rx_careful_action
|
||||
@@ -566,7 +618,7 @@ class GlancesPlugin(object):
|
||||
# Return the action list
|
||||
return ret
|
||||
|
||||
def __get_limit_log(self, stat_name, default_action=False):
|
||||
def get_limit_log(self, stat_name, default_action=False):
|
||||
"""Return the log tag for the alert."""
|
||||
# Get the log tag for stat + header
|
||||
# Exemple: network_wlan0_rx_log
|
||||
@@ -746,6 +798,16 @@ class GlancesPlugin(object):
|
||||
value, decimal=decimal_precision, symbol=symbol)
|
||||
return '{!s}'.format(number)
|
||||
|
||||
def _check_decorator(fct):
|
||||
"""Check if the plugin is enabled."""
|
||||
def wrapper(self, *args, **kw):
|
||||
if self.is_enable():
|
||||
ret = fct(self, *args, **kw)
|
||||
else:
|
||||
ret = self.stats
|
||||
return ret
|
||||
return wrapper
|
||||
|
||||
def _log_result_decorator(fct):
|
||||
"""Log (DEBUG) the result of the function fct."""
|
||||
def wrapper(*args, **kw):
|
||||
@@ -758,4 +820,5 @@ class GlancesPlugin(object):
|
||||
return wrapper
|
||||
|
||||
# Mandatory to call the decorator in childs' classes
|
||||
_check_decorator = staticmethod(_check_decorator)
|
||||
_log_result_decorator = staticmethod(_log_result_decorator)
|
||||
|
||||
@@ -23,7 +23,6 @@ import os
|
||||
import subprocess
|
||||
import threading
|
||||
import socket
|
||||
import types
|
||||
import time
|
||||
|
||||
from glances.globals import WINDOWS
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
#
|
||||
# This file is part of Glances.
|
||||
#
|
||||
# Copyright (C) 2015 Nicolargo <nicolas@nicolargo.com>
|
||||
# Copyright (C) 2016 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
|
||||
@@ -80,7 +80,11 @@ class Plugin(GlancesPlugin):
|
||||
self.nb_log_core = 0
|
||||
|
||||
# Get the max values (dict)
|
||||
max_values = glances_processes.max_values()
|
||||
self.max_values = glances_processes.max_values()
|
||||
|
||||
# Get the maximum PID number
|
||||
# Use to optimize space (see https://github.com/nicolargo/glances/issues/959)
|
||||
self.pid_max = glances_processes.pid_max
|
||||
|
||||
# Note: 'glances_processes' is already init in the processes.py script
|
||||
|
||||
@@ -240,7 +244,7 @@ class Plugin(GlancesPlugin):
|
||||
ret.append(self.curse_add_line(msg))
|
||||
ret.append(self.curse_add_line(msg))
|
||||
# PID
|
||||
msg = '{:>6}'.format(p['pid'])
|
||||
msg = '{:>{width}}'.format(p['pid'], width=self.__max_pid_size() + 1)
|
||||
ret.append(self.curse_add_line(msg))
|
||||
# USER
|
||||
if 'username' in p:
|
||||
@@ -480,7 +484,7 @@ class Plugin(GlancesPlugin):
|
||||
ret.append(self.curse_add_line(msg, optional=True))
|
||||
msg = '{:>6}'.format('RES')
|
||||
ret.append(self.curse_add_line(msg, optional=True))
|
||||
msg = '{:>6}'.format('PID')
|
||||
msg = '{:>{width}}'.format('PID', width=self.__max_pid_size() + 1)
|
||||
ret.append(self.curse_add_line(msg))
|
||||
msg = ' {:10}'.format('USER')
|
||||
ret.append(self.curse_add_line(msg, sort_style if process_sort_key == 'username' else 'DEFAULT'))
|
||||
@@ -647,3 +651,11 @@ class Plugin(GlancesPlugin):
|
||||
return sort_stats(self.stats, sortedby,
|
||||
tree=glances_processes.is_tree_enabled(),
|
||||
reverse=glances_processes.sort_reverse)
|
||||
|
||||
def __max_pid_size(self):
|
||||
"""Return the maximum PID size in number of char"""
|
||||
if self.pid_max is not None:
|
||||
return len(str(self.pid_max))
|
||||
else:
|
||||
# By default return 5 (corresponding to 99999 PID number)
|
||||
return 5
|
||||
|
||||
@@ -37,6 +37,8 @@ class Plugin(GlancesPlugin):
|
||||
"""Reset/init the stats."""
|
||||
self.stats = None
|
||||
|
||||
@GlancesPlugin._check_decorator
|
||||
@GlancesPlugin._log_result_decorator
|
||||
def update(self):
|
||||
"""Update the stats."""
|
||||
# Reset stats
|
||||
|
||||
@@ -22,7 +22,6 @@
|
||||
from glances.cpu_percent import cpu_percent
|
||||
from glances.outputs.glances_bars import Bar
|
||||
from glances.plugins.glances_plugin import GlancesPlugin
|
||||
from glances.logger import logger
|
||||
|
||||
import psutil
|
||||
|
||||
@@ -58,6 +57,7 @@ class Plugin(GlancesPlugin):
|
||||
"""Reset/init the stats."""
|
||||
self.stats = {}
|
||||
|
||||
@GlancesPlugin._check_decorator
|
||||
@GlancesPlugin._log_result_decorator
|
||||
def update(self):
|
||||
"""Update quicklook stats using the input method."""
|
||||
@@ -86,9 +86,6 @@ class Plugin(GlancesPlugin):
|
||||
self.stats['cpu_hz_current'] = cpu_info['hz_actual_raw'][0]
|
||||
self.stats['cpu_hz'] = cpu_info['hz_advertised_raw'][0]
|
||||
|
||||
# Update the view
|
||||
self.update_views()
|
||||
|
||||
return self.stats
|
||||
|
||||
def update_views(self):
|
||||
@@ -108,7 +105,7 @@ class Plugin(GlancesPlugin):
|
||||
ret = []
|
||||
|
||||
# Only process if stats exist...
|
||||
if not self.stats or args.disable_quicklook:
|
||||
if not self.stats or self.is_disable():
|
||||
return ret
|
||||
|
||||
# Define the bar
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user