提交 0d35d547 编写于 作者: N nicolargo

version 3.1.6

---
name: Bug report
about: Create a report to help us improve
title: ''
labels: ''
assignees: ''
---
**Describe the bug**
A clear and concise description of what the bug is.
**To Reproduce**
Steps to reproduce the behavior:
1. Start Glances with the followings options '...'
2. Press the key '....'
3. See error
**Expected behavior**
A clear and concise description of what you expected to happen.
**Screenshots**
If applicable, add screenshots to help explain your problem.
**Desktop (please complete the following information):**
- OS: [e.g. GNU/Linux Ubuntu 20.04]
- Glances Version [output of glances -V]
- Glances logs file [output of tail -10 <glances logs file>]
**Additional context**
Add any other context about the problem here.
---
name: Feature request
about: Suggest an idea for this project
title: ''
labels: ''
assignees: ''
---
**Is your feature request related to a problem? Please describe.**
A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
**Describe the solution you'd like**
A clear and concise description of what you want to happen.
**Describe alternatives you've considered**
A clear and concise description of any alternative solutions or features you've considered.
**Additional context**
Add any other context or screenshots about the feature request here.
name: CI
env:
DEFAULT_DOCKER_IMAGE: nicolargo/glances
NODE_ENV: ${{ (contains('refs/heads/master', github.ref) || startsWith(github.ref, 'refs/tags/v')) && 'prod' || 'dev' }}
PUSH_BRANCH: ${{ 'refs/heads/develop' == github.ref || 'refs/heads/master' == github.ref || startsWith(github.ref, 'refs/tags/v') }}
DOCKER_PLATFORMS: linux/amd64,linux/arm/v6,linux/arm/v7,linux/arm64,linux/386
on:
pull_request:
branches: [ develop ]
push:
branches: [ master, develop ]
tags:
- v*
jobs:
buildx:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v2
- name: Cache Docker layers
uses: actions/cache@v2
with:
path: /tmp/.buildx-cache
key: ${{ runner.os }}-buildx-${{ env.NODE_ENV }}-${{ github.sha }}
restore-keys: |
${{ runner.os }}-buildx-${{ env.NODE_ENV }}
- name: Configure ENVs
env:
DOCKER_IMAGE: ${{ secrets.DOCKER_IMAGE || env.DEFAULT_DOCKER_IMAGE }}
DOCKERFILE: ${{ env.NODE_ENV == 'prod' && './docker-files/Dockerfile' || './docker-files/dev.Dockerfile' }}
run: |
ls -la /tmp/.buildx-cache || true
VERSION=latest
if [[ $GITHUB_REF == refs/tags/* ]]; then
VERSION=${GITHUB_REF#refs/tags/v}
fi
if [[ $GITHUB_REF == refs/heads/develop ]]; then
VERSION=dev
fi
echo "DOCKERFILE=${DOCKERFILE}" >> $GITHUB_ENV
echo "VERSION=${VERSION}" >> $GITHUB_ENV
echo "TAGS=${DOCKER_IMAGE}:${VERSION}" >> $GITHUB_ENV
echo "BUILD_DATE=$(date -u +'%Y-%m-%dT%H:%M:%SZ')" >> $GITHUB_ENV
echo "VCS_REF=${GITHUB_SHA::8}" >> $GITHUB_ENV
- name: Set up QEMU
uses: docker/setup-qemu-action@v1
with:
platforms: all
- name: Set up Docker Buildx
id: buildx
uses: docker/setup-buildx-action@v1
with:
version: latest
- name: Login to DockerHub
uses: docker/login-action@v1
if: ${{ env.PUSH_BRANCH == 'true' }}
with:
username: ${{ secrets.DOCKER_USERNAME }}
password: ${{ secrets.DOCKER_PASSWORD }}
- name: Build and push
uses: docker/build-push-action@v2
with:
push: ${{ env.PUSH_BRANCH == 'true' }}
tags: ${{env.TAGS}}
build-args: |
VERSION=${{env.VERSION}}
BUILD_DATE=${{env.BUILD_DATE}}
VCS_REF=${{env.VCS_REF}}
context: .
file: ${{env.DOCKERFILE}}
platforms: ${{env.DOCKER_PLATFORMS}}
cache-from: type=local,src=/tmp/.buildx-cache
cache-to: type=local,dest=/tmp/.buildx-cache,mode=max
......@@ -23,12 +23,22 @@ after_success:
- coveralls
deploy:
provider: pypi
user: nicolargo
password:
secure: Fms23jiiKKq6qJMsZYrmBz5mC753VGrjCxzVrsioENfH3KaFf6kUc9fTYntaLvjLPTNBkU3R2IORfVOikJKmNWqWVZOdJ/nq8zPl6o9MgdNcX7qWTvY8Fi9MW7tIZHrehhm0LvWFVq8ZSc8iYzw3/741lvBh8vpJZSQs3sq/1QI=
on:
tags: true
branch: master
distributions: sdist bdist_wheel
repo: nicolargo/glances
- provider: pypi
user: nicolargo
password:
secure: Fms23jiiKKq6qJMsZYrmBz5mC753VGrjCxzVrsioENfH3KaFf6kUc9fTYntaLvjLPTNBkU3R2IORfVOikJKmNWqWVZOdJ/nq8zPl6o9MgdNcX7qWTvY8Fi9MW7tIZHrehhm0LvWFVq8ZSc8iYzw3/741lvBh8vpJZSQs3sq/1QI=
on:
tags: true
branch: master
distributions: sdist bdist_wheel
repo: nicolargo/glances
- provider: pypi
server: https://test.pypi.org/legacy/
user: nicolargo
password:
secure: kxchYP3VJWe74jun0rJjuEFFpnO2sF3WHsK5Axlz4flJ6dtX0OPeZd9SlqgMX7cv9FHcXxyukVKrw4PHVqUNcWoaKM8TNeddKkGeSjcVY5C7NIExXh5es4SguozdT4cckoJUyN2xXc7cUAM68CHWfxijR6NiDMXIuMJrZumye6c=
on:
tags: false
branch: develop
distributions: sdist bdist_wheel
repo: nicolargo/glances
......@@ -2,6 +2,54 @@
Glances Version 3
==============================================================================
Version 3.1.6
=============
Enhancements and new features:
* Kill a process from the Curses interface #1444
* Manual refresh on F5 in the Curses interface #1753
* Hide function in sensors section #1590
* Enhancement Request: .conf parameter for AMP #1690
* Password for Web/Browser mode #1674
* Unable to connect to Influxdb 2.0 #1776
* ci: fix release process and improve build speeds #1782
* Cache cpuinfo output #1700
* sort by clicking improvements and bug #1578
* Allow embedded AMP python script to be placed in a configurable location #1734
* Add attributes to stdout/stdout-csv plugins #1733
* Do not shorten container names #1723
Bugs corrected:
* Version tag for docker image packaging #1754
* Unusual characters in cmdline cause lines to disappear and corrupt the display #1692
* UnicodeDecodeError on any command with a utf8 character in its name #1676
* Docker image is not up to date install #1662
* Add option to set the strftime format #1785
* fix: docker dev build contains all optional requirements #1779
* GPU information is incomplete via web #1697
* [WebUI] Fix display of null values for GPU plugin #1773
* crash on startup on Illumos when no swap is configured #1767
* Glances crashes with 2 GPUS bug #1683
* [Feature Request] Filter Docker containers#1748
* Error with IP Plugin : object has no attribute #1528
* docker-compose #1760
* [WebUI] Fix sort by disk io #1759
* Connection to MQTT server failst #1705
* Misleading image tag latest-arm needs contributor packaging #1419
* Docker nicolargo/glances:latest missing arm builds? #1746
* Alpine image is broken packaging #1744
* RIP Alpine? needs contributor packaging #1741
* Manpage improvement documentation #1743
* Make build reproducible packaging #1740
* Automated multiarch builds for docker #1716
* web ui of glances is not coming #1721
* fixing command in json.rst #1724
* Fix container rss value #1722
* Alpine Image is broken needs test packaging #1720
* Fix gpu plugin to handle multiple gpus with different reporting capabilities bug #1634
Version 3.1.5
=============
......
......@@ -9,9 +9,13 @@ Glances - An eye on your system
:target: https://github.com/nicolargo/glances/
:alt: Github stars
.. image:: https://img.shields.io/docker/pulls/nicolargo/glances
:target: https://hub.docker.com/r/nicolargo/glances/
:alt: Docker pull
.. image:: https://pepy.tech/badge/glances/month
:target: https://pepy.tech/project/glances
:alt: Downloads
:alt: Pypi downloads
.. image:: https://img.shields.io/travis/nicolargo/glances/master.svg?maxAge=3600&label=Linux%20/%20BSD%20/%20macOS
:target: https://travis-ci.org/nicolargo/glances
......@@ -24,8 +28,8 @@ Glances - An eye on your system
.. image:: https://scrutinizer-ci.com/g/nicolargo/glances/badges/quality-score.png?b=develop
:target: https://scrutinizer-ci.com/g/nicolargo/glances/?branch=develop
.. image:: https://img.shields.io/badge/Donate-PayPal-green.svg
:target: https://www.paypal.me/nicolargo
.. image:: https://img.shields.io/static/v1?label=Sponsor&message=%E2%9D%A4&logo=GitHub&link=https://github.com/sponsors/nicolargo
:target: https://github.com/sponsors/nicolargo
.. image:: https://img.shields.io/twitter/url/https/twitter.com/cloudposse.svg?style=social&label=Follow%20%40nicolargo
:target: https://twitter.com/nicolargo
......@@ -65,7 +69,8 @@ Optional dependencies:
- ``docker`` (for the Docker monitoring support) [Linux/macOS-only]
- ``elasticsearch`` (for the Elastic Search export module)
- ``hddtemp`` (for HDD temperature monitoring support) [Linux-only]
- ``influxdb`` (for the InfluxDB export module)
- ``influxdb`` (for the InfluxDB version 1 export module)
- ``influxdb-client`` (for the InfluxDB version 2 export module) [Only for Python >= 3.6]
- ``kafka-python`` (for the Kafka export module)
- ``netifaces`` (for the IP plugin)
- ``nvidia-ml-py3`` (for the GPU plugin)
......@@ -161,6 +166,13 @@ If you need to install Glances in a specific user location, use:
export PYTHONUSERBASE=~/mylocalpath
pip install --user glances
The current develop branch is also published to the test.pypi.org package index.
If you want to test the develop version, enter:
.. code-block:: console
pip install -i https://test.pypi.org/simple/ Glances
Docker: the funny way
---------------------
......@@ -168,24 +180,30 @@ A Glances container is available. It includes the latest development
HEAD version. You can use it to monitor your server and all your other
containers!
Get the Glances container:
Get the Glances container (latest develop branch):
.. code-block:: console
docker pull nicolargo/glances
docker pull nicolargo/glances:dev
Note, you can choose another branch with :
- nicolargo/glances:latest for the last master branch (included multiple architectures 386, amd64, arm/v7 and arm64)
- nicolargo/glances:dev for the last develop branch (included multiple architectures 386, amd64, arm/v7 and arm64)
- nicolargo/glances:<version> for the specific <version> (included multiple architectures 386, amd64, arm/v7 and arm64)
Run the container in *console mode*:
.. code-block:: console
docker run --rm -v /var/run/docker.sock:/var/run/docker.sock:ro --pid host --network host -it docker.io/nicolargo/glances
docker run --rm -v /var/run/docker.sock:/var/run/docker.sock:ro --pid host --network host -it nicolargo/glances:dev
Additionally, if you want to use your own glances.conf file, you can
create your own Dockerfile:
.. code-block:: console
FROM nicolargo/glances
FROM nicolargo/glances:dev
COPY glances.conf /glances/conf/glances.conf
CMD python -m glances -C /glances/conf/glances.conf $GLANCES_OPT
......@@ -194,7 +212,7 @@ docker run options:
.. code-block:: console
docker run -v `pwd`/glances.conf:/glances/conf/glances.conf -v /var/run/docker.sock:/var/run/docker.sock:ro --pid host -it docker.io/nicolargo/glances
docker run -v `pwd`/glances.conf:/glances/conf/glances.conf -v /var/run/docker.sock:/var/run/docker.sock:ro --pid host -it nicolargo/glances:dev
Where \`pwd\`/glances.conf is a local directory containing your glances.conf file.
......@@ -203,7 +221,7 @@ variable setting parameters for the glances startup command):
.. code-block:: console
docker run -d --restart="always" -p 61208-61209:61208-61209 -e GLANCES_OPT="-w" -v /var/run/docker.sock:/var/run/docker.sock:ro --pid host docker.io/nicolargo/glances
docker run -d --restart="always" -p 61208-61209:61208-61209 -e GLANCES_OPT="-w" -v /var/run/docker.sock:/var/run/docker.sock:ro --pid host nicolargo/glances:dev
GNU/Linux
---------
......@@ -416,8 +434,7 @@ Donation
If this project help you, you can give me a tip ;)
.. image:: https://www.paypalobjects.com/en_US/i/btn/btn_donateCC_LG.gif
:target: https://www.paypal.me/nicolargo
See the sponsors_ page.
Author
======
......@@ -440,3 +457,4 @@ Glances is distributed under the LGPL version 3 license. See ``COPYING`` for mor
.. _forum: https://groups.google.com/forum/?hl=en#!forum/glances-users
.. _wiki: https://github.com/nicolargo/glances/wiki/How-to-contribute-to-Glances-%3F
.. _package: https://repology.org/metapackage/glances/packages
.. _sponsors: https://github.com/sponsors/nicolargo
......@@ -184,7 +184,7 @@ careful=50
warning=70
critical=90
# Allow additional file system types (comma-separated FS type)
#allow=zfs
#allow=shm
[irq]
# Documentation: https://glances.readthedocs.io/en/stable/aoa/irq.html
......@@ -327,6 +327,14 @@ port_default_gateway=True
[docker]
disable=False
# Only show specific containers (comma separeted list of container name or regular expression)
# Comment this line to display all containers (default configuration)
#show=telegraf
# Hide some containers (comma separeted list of container name or regular expression)
# Comment this line to display all containers (default configuration)
#hide=telegraf
# Define the maximum docker size name (default is 20 chars)
max_name_size=20
#cpu_careful=50
# Thresholds for CPU and MEM (in %)
#cpu_warning=70
......@@ -390,6 +398,10 @@ height=600
style=DarkStyle
[influxdb]
# !!!
# Will be DEPRECATED in future release.
# Please have a look on the new influxdb2 export module (compatible with InfluxDB 1.8.x and 2.x)
# !!!
# Configuration for the --export influxdb option
# https://influxdb.com/
host=localhost
......@@ -410,6 +422,27 @@ prefix=localhost
# You can also use dynamic values
#tags=system:`uname -s`
[influxdb2]
# Configuration for the --export influxdb2 option
# https://influxdb.com/
host=localhost
port=8086
protocol=http
org=nicolargo
bucket=glances
token=EjFUTWe8U-MIseEAkaVIgVnej_TrnbdvEcRkaB1imstW7gapSqy6_6-8XD-yd51V0zUUpDy-kAdVD1purDLuxA==
# Prefix will be added for all measurement name
# Ex: prefix=foo
# => foo.cpu
# => foo.mem
# You can also use dynamic values
#prefix=`hostname`
prefix=localhost
# Tags will be added for all measurements
#tags=foo:bar,spam:eggs
# You can also use dynamic values
#tags=system:`uname -s`
[cassandra]
# Configuration for the --export cassandra option
# Also works for the ScyllaDB
......@@ -461,6 +494,7 @@ port=5672
user=guest
password=guest
queue=glances_queue
#protocol=amqps
[mqtt]
# Configuration for the --export mqtt option
......
FROM nicolargo/glances:dev
COPY glances.conf /glances/conf/glances.conf
CMD python -m glances -C /glances/conf/glances.conf $GLANCES_OPT
version: '3.7'
services:
glances:
build:
context: ./
dockerfile: Dockerfile
restart: always
ports:
- "61208:61208"
# - "61209:61209"
environment:
# - GLANCES_OPT="-w"
GLANCES_OPT: "-w"
volumes:
- "/var/run/docker.sock:/var/run/docker.sock:ro"
- "./glances.conf:/glances/conf/glances.conf"
pid: "host"
##############################################################################
# Globals Glances parameters
##############################################################################
[global]
# Does Glances should check if a newer version is available on PyPI ?
check_update=false
# History size (maximum number of values)
# Default is 28800: 1 day with 1 point every 3 seconds
history_size=28800
##############################################################################
# User interface
##############################################################################
[outputs]
# Theme name for the Curses interface: black or white
curse_theme=black
# Limit the number of processes to display in the WebUI
max_processes_display=30
##############################################################################
# plugins
##############################################################################
[quicklook]
# Set to true to disable a plugin
# Note: you can also disable it from the command line (see --disable-plugin <plugin_name>)
disable=False
# Graphical percentage char used in the terminal user interface (default is |)
percentage_char=|
# Define CPU, MEM and SWAP thresholds in %
cpu_careful=50
cpu_warning=70
cpu_critical=90
mem_careful=50
mem_warning=70
mem_critical=90
swap_careful=50
swap_warning=70
swap_critical=90
[cpu]
disable=False
# Default values if not defined: 50/70/90 (except for iowait)
user_careful=50
user_warning=70
user_critical=90
#user_log=False
#user_critical_action=echo {{user}} {{value}} {{max}} > /tmp/cpu.alert
system_careful=50
system_warning=70
system_critical=90
steal_careful=50
steal_warning=70
steal_critical=90
#steal_log=True
# I/O wait percentage should be lower than 1/# (Logical CPU cores)
# Leave commented to just use the default config (1/#-20% / 1/#-10% / 1/#)
#iowait_careful=30
#iowait_warning=40
#iowait_critical=50
# Context switch limit (core / second)
# Leave commented to just use the default config (critical is 50000*# (Logical CPU cores)
#ctx_switches_careful=10000
#ctx_switches_warning=12000
#ctx_switches_critical=14000
[percpu]
disable=False
# Define CPU thresholds in %
# Default values if not defined: 50/70/90
user_careful=50
user_warning=70
user_critical=90
iowait_careful=50
iowait_warning=70
iowait_critical=90
system_careful=50
system_warning=70
system_critical=90
[gpu]
disable=False
# Default processor values if not defined: 50/70/90
proc_careful=50
proc_warning=70
proc_critical=90
# Default memory values if not defined: 50/70/90
mem_careful=50
mem_warning=70
mem_critical=90
[mem]
disable=False
# Define RAM thresholds in %
# Default values if not defined: 50/70/90
careful=50
#careful_action_repeat=echo {{percent}} >> /tmp/memory.alert
warning=70
critical=90
[memswap]
disable=False
# Define SWAP thresholds in %
# Default values if not defined: 50/70/90
careful=50
warning=70
critical=90
[load]
disable=False
# Define LOAD thresholds
# Value * number of cores
# Default values if not defined: 0.7/1.0/5.0 per number of cores
# Source: http://blog.scoutapp.com/articles/2009/07/31/understanding-load-averages
# http://www.linuxjournal.com/article/9001
careful=0.7
warning=1.0
critical=5.0
#log=False
[network]
disable=False
# 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
[connections]
# Display additional information about TCP connections
# This plugin is disabled by default
disable=True
# nf_conntrack thresholds in %
nf_conntrack_percent_careful=70
nf_conntrack_percent_warning=80
nf_conntrack_percent_critical=90
[wifi]
disable=False
# 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]
disable=False
# Define the list of hidden disks (comma-separated regexp)
#hide=sda2,sda5,loop.*
hide=loop.*,/dev/loop*
# Alias for sda1
#sda1_alias=InternalDisk
[fs]
disable=False
# Define the list of hidden file system (comma-separated regexp)
hide=/boot.*,/snap.*
# Define filesystem space thresholds in %
# Default values if not defined: 50/70/90
# It is also possible to define per mount point value
# Example: /_careful=40
careful=50
warning=70
critical=90
# Allow additional file system types (comma-separated FS type)
#allow=shm
[irq]
# Documentation: https://glances.readthedocs.io/en/stable/aoa/irq.html
# This plugin is disabled by default
disable=False
[folders]
# Documentation: https://glances.readthedocs.io/en/stable/aoa/folders.html
disable=False
# Define a folder list to monitor
# The list is composed of items (list_#nb <= 10)
# An item is defined by:
# * path: absolute path
# * careful: optional careful threshold (in MB)
# * warning: optional warning threshold (in MB)
# * critical: optional critical threshold (in MB)
# * refresh: interval in second between two refreshs
#folder_1_path=/tmp
#folder_1_careful=2500
#folder_1_warning=3000
#folder_1_critical=3500
#folder_1_refresh=60
#folder_2_path=/home/nicolargo/Videos
#folder_2_warning=17000
#folder_2_critical=20000
#folder_3_path=/nonexisting
#folder_4_path=/root
[raid]
# Documentation: https://glances.readthedocs.io/en/stable/aoa/raid.html
# This plugin is disabled by default
disable=True
[smart]
# Documentation: https://glances.readthedocs.io/en/stable/aoa/smart.html
# This plugin is disabled by default
disable=True
[hddtemp]
disable=False
# Define hddtemp server IP and port (default is 127.0.0.1 and 7634 (TCP))
host=127.0.0.1
port=7634
[sensors]
# This plugin is disable by default because on some system, the PsUtil
# consume a lot of CPU to grab the stats...
disable=True
# Sensors core thresholds (in Celsius...)
# Default values if not defined: 60/70/80
temperature_core_careful=60
temperature_core_warning=70
temperature_core_critical=80
# Temperatures threshold in °C for hddtemp
# Default values if not defined: 45/52/60
temperature_hdd_careful=45
temperature_hdd_warning=52
temperature_hdd_critical=60
# Battery threshold in %
battery_careful=80
battery_warning=90
battery_critical=95
# Sensors alias
#temp1_alias=Motherboard 0
#temp2_alias=Motherboard 1
#core 0_alias=CPU Core 0
#core 1_alias=CPU Core 1
[processlist]
disable=False
# Sort key: if not defined, the sort is automatically done by Glances (recommended)
# Should be one of the following:
# cpu_percent, memory_percent, io_counters, name, cpu_times, username
#sort_key=memory_percent
# Define CPU/MEM (per process) thresholds in %
# Default values if not defined: 50/70/90
cpu_careful=50
cpu_warning=70
cpu_critical=90
mem_careful=50
mem_warning=70
mem_critical=90
#
# Nice priorities range from -20 to 19.
# Configure nice levels using a comma separated list.
#
# Nice: Example 1, non-zero is warning (default behavior)
nice_warning=-20,-19,-18,-17,-16,-15,-14,-13,-12,-11,-10,-9,-8,-7,-6,-5,-4,-3,-2,-1,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19
#
# Nice: Example 2, low priority processes escalate from careful to critical
#nice_careful=1,2,3,4,5,6,7,8,9
#nice_warning=10,11,12,13,14
#nice_critical=15,16,17,18,19
[ports]
disable=False
# Interval in second between two scans
# Ports scanner plugin configuration
refresh=30
# Set the default timeout (in second) for a scan (can be overwritten in the scan list)
timeout=3
# If port_default_gateway is True, add the default gateway on top of the scan list
port_default_gateway=True
#
# Define the scan list (1 < x < 255)
# port_x_host (name or IP) is mandatory
# port_x_port (TCP port number) is optional (if not set, use ICMP)
# port_x_description is optional (if not set, define to host:port)
# port_x_timeout is optional and overwrite the default timeout value
# port_x_rtt_warning is optional and defines the warning threshold in ms
#
#port_1_host=192.168.0.1
#port_1_port=80
#port_1_description=Home Box
#port_1_timeout=1
#port_2_host=www.free.fr
#port_2_description=My ISP
#port_3_host=www.google.com
#port_3_description=Internet ICMP
#port_3_rtt_warning=1000
#port_4_description=Internet Web
#port_4_host=www.google.com
#port_4_port=80
#port_4_rtt_warning=1000
#
# Define Web (URL) monitoring list (1 < x < 255)
# web_x_url is the URL to monitor (example: http://my.site.com/folder)
# web_x_description is optional (if not set, define to URL)
# web_x_timeout is optional and overwrite the default timeout value
# web_x_rtt_warning is optional and defines the warning respond time in ms (approximatively)
#
#web_1_url=https://blog.nicolargo.com
#web_1_description=My Blog
#web_1_rtt_warning=3000
#web_2_url=https://github.com
#web_3_url=http://www.google.fr
#web_3_description=Google Fr
#web_4_url=https://blog.nicolargo.com/nonexist
#web_4_description=Intranet
[docker]
disable=False
# Only show specific containers (comma separeted list of container name or regular expression)
# Comment this line to display all containers (default configuration)
#show=telegraf
# Hide some containers (comma separeted list of container name or regular expression)
# Comment this line to display all containers (default configuration)
#hide=telegraf
# Define the maximum docker size name (default is 20 chars)
max_name_size=20
#cpu_careful=50
# Thresholds for CPU and MEM (in %)
#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
#
# By default, Glances only display running containers
# Set the following key to True to display all containers
all=False
##############################################################################
# Client/server
##############################################################################
[serverlist]
# Define the static servers list
#server_1_name=localhost
#server_1_alias=My local PC
#server_1_port=61209
#server_2_name=localhost
#server_2_port=61235
#server_3_name=192.168.0.17
#server_3_alias=Another PC on my network
#server_3_port=61209
#server_4_name=pasbon
#server_4_port=61237
server_5_name=172.247.185.114
server_5_port=10089
[passwords]
# Define the passwords list
# Syntax: host=password
# Where: host is the hostname
# password is the clear password
# Additionally (and optionally) a default password could be defined
#localhost=abc
#default=defaultpassword
##############################################################################
# Exports
##############################################################################
[graph]
# Configuration for the --export graph option
# Set the path where the graph (.svg files) will be created
# Can be overwrite by the --graph-path command line option
path=/tmp
# It is possible to generate the graphs automatically by setting the
# generate_every to a non zero value corresponding to the seconds between
# two generation. Set it to 0 to disable graph auto generation.
generate_every=60
# See followings configuration keys definitions in the Pygal lib documentation
# http://pygal.org/en/stable/documentation/index.html
width=800
height=600
style=DarkStyle
[influxdb]
# Configuration for the --export influxdb option
# https://influxdb.com/
host=localhost
port=8086
protocol=http
user=root
password=root
db=glances
# Prefix will be added for all measurement name
# Ex: prefix=foo
# => foo.cpu
# => foo.mem
# You can also use dynamic values
#prefix=`hostname`
prefix=localhost
# Tags will be added for all measurements
#tags=foo:bar,spam:eggs
# You can also use dynamic values
#tags=system:`uname -s`
[cassandra]
# Configuration for the --export cassandra option
# Also works for the ScyllaDB
# https://influxdb.com/ or http://www.scylladb.com/
host=localhost
port=9042
protocol_version=3
keyspace=glances
replication_factor=2
# If not define, table name is set to host key
table=localhost
# If not define, username and password will not be used
#username=cassandra
#password=password
[opentsdb]
# Configuration for the --export opentsdb option
# http://opentsdb.net/
host=localhost
port=4242
#prefix=glances
#tags=foo:bar,spam:eggs
[statsd]
# Configuration for the --export statsd option
# https://github.com/etsy/statsd
host=localhost
port=8125
#prefix=glances
[elasticsearch]
# Configuration for the --export elasticsearch option
# Data are available via the ES RESTful API. ex: URL/<index>/cpu/system
# https://www.elastic.co
host=localhost
port=9200
index=glances
[riemann]
# Configuration for the --export riemann option
# http://riemann.io
host=localhost
port=5555
[rabbitmq]
# Configuration for the --export rabbitmq option
host=localhost
port=5672
user=guest
password=guest
queue=glances_queue
#protocol=amqps
[mqtt]
# Configuration for the --export mqtt option
host=localhost
port=8883
user=guest
password=guest
topic=glances
tls=true
[couchdb]
# Configuration for the --export couchdb option
# https://www.couchdb.org
host=localhost
port=5984
db=glances
# user and password are optional (comment if not configured on the server side)
#user=root
#password=root
[kafka]
# Configuration for the --export kafka option
# http://kafka.apache.org/
host=localhost
port=9092
topic=glances
#compression=gzip
# Tags will be added for all events
#tags=foo:bar,spam:eggs
# You can also use dynamic values
#tags=hostname:`hostname -f`
[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
[prometheus]
# Configuration for the --export prometheus option
# https://prometheus.io
# Create a Prometheus exporter listening on localhost:9091 (default configuration)
# Metric are exporter using the following name:
# <prefix>_<plugin>_<stats>{labelkey:labelvalue}
# Note: You should add this exporter to your Prometheus server configuration:
# scrape_configs:
# - job_name: 'glances_exporter'
# scrape_interval: 5s
# static_configs:
# - targets: ['localhost:9091']
#
# Labels will be added for all measurements (default is src:glances)
# labels=foo:bar,spam:eggs
# You can also use dynamic values
# labels=system:`uname -s`
#
host=localhost
port=9091
#prefix=glances
labels=src:glances
[restful]
# Configuration for the --export restful option
# Example, export to http://localhost:6789/
host=localhost
port=6789
protocol=http
path=/
##############################################################################
# AMPS
# * enable: Enable (true) or disable (false) the AMP
# * regex: Regular expression to filter the process(es)
# * refresh: The AMP is executed every refresh seconds
# * one_line: (optional) Force (if true) the AMP to be displayed in one line
# * command: (optional) command to execute when the process is detected (thk to the regex)
# * countmin: (optional) minimal number of processes
# A warning will be displayed if number of process < count
# * countmax: (optional) maximum number of processes
# A warning will be displayed if number of process > count
# * <foo>: Others variables can be defined and used in the AMP script
##############################################################################
[amp_dropbox]
# Use the default AMP (no dedicated AMP Python script)
# Check if the Dropbox daemon is running
# Every 3 seconds, display the 'dropbox status' command line
enable=false
regex=.*dropbox.*
refresh=3
one_line=false
command=dropbox status
countmin=1
[amp_python]
# Use the default AMP (no dedicated AMP Python script)
# Monitor all the Python scripts
# Alert if more than 20 Python scripts are running
enable=false
regex=.*python.*
refresh=3
countmax=20
[amp_conntrack]
# Use comma separated for multiple commands (no space around the comma)
# If the regex key is not defined, the AMP will be executed every refresh second
# and the process count will not be displayed (countmin and countmax will be ignore)
enable=false
refresh=30
one_line=false
command=sysctl net.netfilter.nf_conntrack_count;sysctl net.netfilter.nf_conntrack_max
[amp_nginx]
# Use the NGinx AMP
# Nginx status page should be enable (https://easyengine.io/tutorials/nginx/status-page/)
enable=false
regex=\/usr\/sbin\/nginx
refresh=60
one_line=false
status_url=http://localhost/nginx_status
[amp_systemd]
# Use the Systemd AMP
enable=false
regex=\/lib\/systemd\/systemd
refresh=30
one_line=true
systemctl_cmd=/bin/systemctl --plain
[amp_systemv]
# Use the Systemv AMP
enable=false
regex=\/sbin\/init
refresh=30
one_line=true
service_cmd=/usr/bin/service --status-all
......@@ -4,9 +4,8 @@
# https://github.com/nicolargo/glances
#
# Pull base image.
FROM ubuntu:20.04
ARG ARCH=
FROM ${ARCH}python:3-slim-buster
# Install package
# Must used calibre package to be able to run external module
......@@ -14,30 +13,22 @@ ENV DEBIAN_FRONTEND noninteractive
RUN \
apt-get update && \
apt-get install -y \
curl \
gcc \
lm-sensors \
wireless-tools \
iputils-ping \
python3-pip \
python3-dev && \
curl \
gcc \
lm-sensors \
wireless-tools \
iputils-ping && \
rm -rf /var/lib/apt/lists/*
## Instal glances
RUN \
pip3 install --upgrade pip && \
pip3 install setuptools \
glances[action,batinfo,browser,cpuinfo,docker,export,folders,gpu,graph,ip,raid,snmp,web,wifi] \
glances
# Force rebuild otherwise it could be cached without rerun
ARG VCS_REF
RUN pip install glances[all]
# Define working directory.
WORKDIR /glances
# EXPOSE PORT (For XMLRPC)
EXPOSE 61209
# EXPOSE PORT (For Web UI)
EXPOSE 61208
# EXPOSE PORT (XMLRPC / WebUI)
EXPOSE 61209 61208
# Define default command.
CMD python3 -m glances -C /glances/conf/glances.conf $GLANCES_OPT
#
# Glances Dockerfile (based on Ubuntu)
#
# https://github.com/nicolargo/glances
#
ARG ARCH=
FROM ${ARCH}python:3-buster
# Install package
# Must used calibre package to be able to run external module
ENV DEBIAN_FRONTEND noninteractive
RUN \
apt-get update && \
apt-get install -y \
curl \
gcc \
git \
lm-sensors \
wireless-tools \
iputils-ping && \
rm -rf /var/lib/apt/lists/*
RUN pip install psutil bottle
# Define working directory
WORKDIR /glances
COPY *requirements.txt .
RUN CASS_DRIVER_NO_CYTHON=1 pip install -r optional-requirements.txt
COPY . /glances
# EXPOSE PORT (XMLRPC / WebUI)
EXPOSE 61209 61208
# Define default command.
CMD python3 -m glances -C /glances/conf/glances.conf $GLANCES_OPT
......@@ -8,8 +8,7 @@
FROM alpine
# Install Glances (develop branch)
RUN apk add python py2-psutil py2-bottle
RUN apk add git
RUN apk add python3 py3-psutil py3-bottle docker-py git
RUN git clone -b develop https://github.com/nicolargo/glances.git
# Define working directory.
......@@ -22,4 +21,4 @@ EXPOSE 61209
EXPOSE 61208
# Define default command.
CMD python -m glances -C /glances/conf/glances.conf $GLANCES_OPT
CMD /usr/bin/python3 -m glances -C /glances/conf/glances.conf $GLANCES_OPT
#
# Glances Dockerfile for ARM (based on Alpine ARM)
#
# https://github.com/nicolargo/glances
#
# Pull base image.
FROM python:2.7-alpine
# Install Glances (develop branch)
RUN apk add --no-cache --virtual .build_deps \
gcc \
musl-dev \
linux-headers \
git \
&& git clone -b develop https://github.com/nicolargo/glances.git \
&& pip install --no-cache-dir -r glances/requirements.txt bottle \
&& apk del .build_deps
# Define working directory.
WORKDIR /glances
# EXPOSE PORT (For Web UI & XMLRPC)
EXPOSE 61208 61209
# Define default command.
CMD python -m glances -C /glances/conf/glances.conf $GLANCES_OPT
#
# Glances Dockerfile based on Ubuntu OS
#
# https://github.com/nicolargo/glances
#
# Pull base image.
FROM ubuntu:20.04
# Install Glances (develop branch)
RUN apt-get update && apt-get -y install curl iputils-ping && rm -rf /var/lib/apt/lists/*
RUN curl -L https://raw.githubusercontent.com/nicolargo/glancesautoinstall/master/install-develop.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
......@@ -20,6 +20,13 @@ under the ``[docker]`` section:
.. code-block:: ini
[docker]
disable=False
# Only show specific containers (comma separeted list of container name or regular expression)
show=thiscontainer,andthisone,andthoseones.*
# Hide some containers (comma separeted list of container name or regular expression)
hide=donotshowthisone,andthose.*
# Define the maximum docker size name (default is 20 chars)
max_name_size=20
# Global containers' thresholds for CPU and MEM (in %)
cpu_careful=50
cpu_warning=70
......
......@@ -27,13 +27,13 @@ User disk space usage Status
By default, the plugin only displays physical devices (hard disks, USB
keys). To allow other file system types, you have to enable them in the
configuration file. For example, if you want to allow the ``zfs`` file
configuration file. For example, if you want to allow the ``shm`` file
system:
.. code-block:: ini
[fs]
allow=zfs
allow=shm
Also, you can hide mount points as well (in the following ``/boot``):
......
......@@ -128,6 +128,9 @@ The extended stats feature can be enabled using the
``--enable-process-extended`` option (command line) or the ``e`` key
(curses interface).
In curses/standalone mode, you can select a process using ``UP`` and ``DOWN`` and press:
- ``k`` to kill the selected process
.. note::
Limit for CPU and MEM percent values can be overwritten in the
configuration file under the ``[processlist]`` section. It is also
......
......@@ -18,3 +18,6 @@ There is no alert on this information.
.. note::
This plugin is disabled by default in the configuration file.
To enable it just use the following option:
# glances --enable-plugin sensors
......@@ -375,6 +375,8 @@ The following commands (key pressed) are supported while in Glances:
Enable/disable mean GPU mode
``/``
Switch between process command line or command name
``F5``
Refresh stats in curses user interface
In the Glances client browser (accessible through the ``--browser``
command line argument):
......
......@@ -54,7 +54,10 @@ master_doc = 'index'
# General information about the project.
project = 'Glances'
author = 'Nicolas Hennion'
year = datetime.now().year
try:
year = datetime.utcfromtimestamp(int(os.environ['SOURCE_DATE_EPOCH'])).year
except (KeyError, ValueError):
year = datetime.now().year
copyright = '%d, %s' % (year, author)
# The version info for the project you're documenting, acts as replacement for
......
......@@ -17,10 +17,10 @@ Location
You can put your own ``glances.conf`` file in the following locations:
==================== =============================================================
``Linux``, ``SunOS`` ~/.config/glances, /etc/glances
``*BSD`` ~/.config/glances, /usr/local/etc/glances
``macOS`` ~/Library/Application Support/glances, /usr/local/etc/glances
``Windows`` %APPDATA%\\glances
``Linux``, ``SunOS`` ~/.config/glances/glances.conf, /etc/glances/glances.conf
``*BSD`` ~/.config/glances/glances.conf, /usr/local/etc/glances/glances.conf
``macOS`` ~/Library/Application Support/glances/glances.conf, /usr/local/etc/glances/glances.conf
``Windows`` %APPDATA%\\glances\glances.conf
==================== =============================================================
- On Windows XP, ``%APPDATA%`` is: ``C:\Documents and Settings\<USERNAME>\Application Data``.
......
......@@ -104,7 +104,6 @@ which will prompt you to answer the following questions:
after which you will need to kill the process by entering ``CTRL+C`` (potentially twice), before leaving the container:
.. code-block:: console
^C^C
exit
You will then need to copy the password file to your host machine:
......
......@@ -4,6 +4,10 @@ InfluxDB
========
You can export statistics to an ``InfluxDB`` server (time series server).
InfluxDB (up to version 1.7.x)
------------------------------
The connection should be defined in the Glances configuration file as
following:
......@@ -16,6 +20,13 @@ following:
user=root
password=root
db=glances
# Prefix will be added for all measurement name
# Ex: prefix=foo
# => foo.cpu
# => foo.mem
# You can also use dynamic values
#prefix=`hostname`
prefix=localhost
# Tags will be added for all measurements
#tags=foo:bar,spam:eggs
# You can also use dynamic values
......@@ -33,6 +44,45 @@ configuration file (no limit on columns number).
Note: if you want to use SSL, please set 'protocol=https'.
InfluxDB v2 (from InfluxDB v1.8.x/Flux and InfluxDB v2.x)
---------------------------------------------------------
Note: The InfluxDB v2 client (https://pypi.org/project/influxdb-client/)
is only available for Python 3.6 or higher.
The connection should be defined in the Glances configuration file as
following:
.. code-block:: ini
[influxdb]
host=localhost
port=8086
protocol=http
org=nicolargo
bucket=glances
token=EjFUTWe8U-MIseEAkaVIgVnej_TrnbdvEcRkaB1imstW7gapSqy6_6-8XD-yd51V0zUUpDy-kAdVD1purDLuxA==
# Prefix will be added for all measurement name
# Ex: prefix=foo
# => foo.cpu
# => foo.mem
# You can also use dynamic values
#prefix=`hostname`
prefix=localhost
# Tags will be added for all measurements
#tags=foo:bar,spam:eggs
# You can also use dynamic values
#tags=system:`uname -s`
and run Glances with:
.. code-block:: console
$ glances --export influxdb2
Note: if you want to use SSL, please set 'protocol=https'.
Grafana
-------
......
......@@ -6,5 +6,5 @@ JSON
It's possible to export stats to a JSON file.
.. code-block:: console
$ glances --export json --export-json-file /tmp/glances.json
$ glances --export json --export-json-file json /tmp/glances.json
......@@ -15,6 +15,7 @@ following:
user=glances
password=glances
queue=glances_queue
#protocol=amqps
and run Glances with:
......
.\" Man page generated from reStructuredText.
.
.TH "GLANCES" "1" "Aug 19, 2020" "3.1.5" "Glances"
.TH "GLANCES" "1" "Jan 23, 2021" "3.1.6" "Glances"
.SH NAME
glances \- An eye on your system
.
......@@ -479,6 +479,9 @@ Enable/disable mean GPU mode
.TP
.B \fB/\fP
Switch between process command line or command name
.TP
.B \fBF5\fP
Refresh stats in curses user interface
.UNINDENT
.sp
In the Glances client browser (accessible through the \fB\-\-browser\fP
......@@ -520,25 +523,25 @@ _
T{
\fBLinux\fP, \fBSunOS\fP
T} T{
~/.config/glances, /etc/glances
~/.config/glances/glances.conf, /etc/glances/glances.conf
T}
_
T{
\fB*BSD\fP
T} T{
~/.config/glances, /usr/local/etc/glances
~/.config/glances/glances.conf, /usr/local/etc/glances/glances.conf
T}
_
T{
\fBmacOS\fP
T} T{
~/Library/Application Support/glances, /usr/local/etc/glances
~/Library/Application Support/glances/glances.conf, /usr/local/etc/glances/glances.conf
T}
_
T{
\fBWindows\fP
T} T{
%APPDATA%\eglances
%APPDATA%\eglancesglances.conf
T}
_
.TE
......@@ -838,6 +841,6 @@ $ glances –browser
.sp
Nicolas Hennion aka Nicolargo <\fI\%contact@nicolargo.com\fP>
.SH COPYRIGHT
2020, Nicolas Hennion
2021, Nicolas Hennion
.\" Generated by docutils manpage writer.
.
......@@ -27,7 +27,9 @@ import signal
import sys
# Global name
__version__ = '3.1.5'
# Version should start and end with a numerical char
# See https://packaging.python.org/specifications/core-metadata/#version
__version__ = '3.1.6'
__author__ = 'Nicolas Hennion <nicolas@nicolargo.com>'
__license__ = 'LGPLv3'
......
......@@ -107,7 +107,11 @@ class Config(object):
# Re patern for optimize research of `foo`
self.re_pattern = re.compile(r'(\`.+?\`)')
self.parser = ConfigParser()
try:
self.parser = ConfigParser(interpolation=None)
except TypeError:
self.parser = ConfigParser()
self.read()
def config_file_paths(self):
......@@ -153,6 +157,16 @@ class Config(object):
self._loaded_config_file = config_file
break
# Globals
if not self.parser.has_section('global'):
self.parser.add_section('global')
self.set_default('global', 'strftime_format', '')
# check_update
if not self.parser.has_section('global'):
self.parser.add_section('global')
self.set_default('global', 'check_update', 'false')
# Quicklook
if not self.parser.has_section('quicklook'):
self.parser.add_section('quicklook')
......
......@@ -17,7 +17,7 @@
# 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/>.
"""InfluxDB interface class."""
"""InfluxDB (up to InfluxDB 1.7.x) interface class."""
import sys
......
# -*- coding: utf-8 -*-
#
# This file is part of Glances.
#
# Copyright (C) 2020 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/>.
"""InfluxDB (from to InfluxDB 1.8+) interface class."""
import sys
from glances.logger import logger
from glances.exports.glances_export import GlancesExport
from influxdb_client import InfluxDBClient, WriteOptions
class Export(GlancesExport):
"""This class manages the InfluxDB export module."""
def __init__(self, config=None, args=None):
"""Init the InfluxDB export IF."""
super(Export, self).__init__(config=config, args=args)
# Mandatories configuration keys (additional to host and port)
self.org = None
self.bucket = None
self.token = None
# Optionals configuration keys
self.protocol = 'http'
self.prefix = None
self.tags = None
# Load the InfluxDB configuration file
self.export_enable = self.load_conf('influxdb2',
mandatories=['host', 'port',
'user', 'password',
'org', 'bucket', 'token'],
options=['protocol',
'prefix',
'tags'])
if not self.export_enable:
sys.exit(2)
# Init the InfluxDB client
self.client = self.init()
def init(self):
"""Init the connection to the InfluxDB server."""
if not self.export_enable:
return None
url = '{}://{}:{}'.format(self.protocol, self.host, self.port)
try:
client = InfluxDBClient(url=url,
enable_gzip=False,
org=self.org,
token=self.token)
except Exception as e:
logger.critical("Cannot connect to InfluxDB server '%s' (%s)" % (url, e))
sys.exit(2)
else:
logger.info("Connected to InfluxDB server version {} ({})".format(client.health().version,
client.health().message))
# Create the write client
write_client = client.write_api(write_options=WriteOptions(batch_size=500,
flush_interval=10000,
jitter_interval=2000,
retry_interval=5000,
max_retries=5,
max_retry_delay=30000,
exponential_base=2))
return write_client
def _normalize(self, name, columns, points):
"""Normalize data for the InfluxDB's data model."""
for i, _ in enumerate(points):
# Supported type:
# https://docs.influxdata.com/influxdb/v2.0/reference/syntax/line-protocol/
if points[i] is None:
# Ignore points with None value
del(points[i])
del(columns[i])
continue
try:
points[i] = float(points[i])
except (TypeError, ValueError):
pass
else:
continue
try:
points[i] = str(points[i])
except (TypeError, ValueError):
pass
else:
continue
return [{'measurement': name,
'tags': self.parse_tags(self.tags),
'fields': dict(zip(columns, points))}]
def export(self, name, columns, points):
"""Write the points to the InfluxDB server."""
# Manage prefix
if self.prefix is not None:
name = self.prefix + '.' + name
# Write input to the InfluxDB database
if len(points) == 0:
logger.debug("Cannot export empty {} stats to InfluxDB".format(name))
else:
try:
self.client.write(self.bucket,
self.org,
self._normalize(name, columns, points),
time_precision="s")
except Exception as e:
# Log level set to debug instead of error (see: issue #1561)
logger.debug("Cannot export {} stats to InfluxDB ({})".format(name, e))
else:
logger.debug("Export {} stats to InfluxDB".format(name))
......@@ -254,6 +254,9 @@ Examples of use:
# Globals options
parser.add_argument('--disable-check-update', action='store_true', default=False,
dest='disable_check_update', help='disable online Glances version ckeck')
parser.add_argument('--strftime', dest='strftime_format', default='',
help='strftime format string for displaying current date in standalone mode')
return parser
def parse_args(self):
......@@ -419,6 +422,13 @@ Examples of use:
disable(args, 'hddtemp')
logger.debug("Sensors and HDDTemp are disabled")
# Let the plugins known the Glances mode
self.args.is_standalone = self.is_standalone()
self.args.is_client = self.is_client()
self.args.is_client_browser = self.is_client_browser()
self.args.is_server = self.is_server()
self.args.is_webserver = self.is_webserver()
return args
def is_standalone(self):
......
......@@ -50,10 +50,13 @@ class _GlancesCurses(object):
"""
_hotkeys = {
# 'ENTER' > Edit the process filter
'0': {'switch': 'disable_irix'},
'1': {'switch': 'percpu'},
'2': {'switch': 'disable_left_sidebar'},
'3': {'switch': 'disable_quicklook'},
# '4' > Enable or disable quicklook
# '5' > Enable or disable top menu
'6': {'switch': 'meangpu'},
'/': {'switch': 'process_short_name'},
'a': {'sort_key': 'auto'},
......@@ -64,13 +67,17 @@ class _GlancesCurses(object):
'C': {'switch': 'disable_cloud'},
'd': {'switch': 'disable_diskio'},
'D': {'switch': 'disable_docker'},
# 'e' > Enable/Disable process extended
# 'E' > Erase the process filter
# 'f' > Show/hide fs / folder stats
'F': {'switch': 'fs_free_space'},
'g': {'switch': 'generate_graph'},
'G': {'switch': 'disable_gpu'},
'h': {'switch': 'help_tag'},
'i': {'sort_key': 'io_counters'},
'I': {'switch': 'disable_ip'},
'k': {'switch': 'disable_connections'},
# 'k' > Kill selected process
'K': {'switch': 'disable_connections'},
'l': {'switch': 'disable_alert'},
'm': {'sort_key': 'memory_percent'},
'M': {'switch': 'reset_minmax_tag'},
......@@ -78,6 +85,7 @@ class _GlancesCurses(object):
'N': {'switch': 'disable_now'},
'p': {'sort_key': 'name'},
'P': {'switch': 'disable_ports'},
# 'q' or ESCAPE > Quit
'Q': {'switch': 'enable_irq'},
'r': {'switch': 'disable_smart'},
'R': {'switch': 'disable_raid'},
......@@ -87,7 +95,14 @@ class _GlancesCurses(object):
'T': {'switch': 'network_sum'},
'u': {'sort_key': 'username'},
'U': {'switch': 'network_cumul'},
# 'w' > Delete finished warning logs
'W': {'switch': 'disable_wifi'},
# 'x' > Delete finished warning and critical logs
# 'z' > Enable or disable processes
# "<" (left arrow) navigation through process sort
# ">" (right arrow) navigation through process sort
# 'UP' > Up in the server list
# 'DOWN' > Down in the server list
}
_sort_loop = ['cpu_percent', 'memory_percent', 'username',
......@@ -144,9 +159,15 @@ class _GlancesCurses(object):
# Init edit filter tag
self.edit_filter = False
# Init kill process tag
self.kill_process = False
# Init the process min/max reset
self.args.reset_minmax_tag = False
# Init cursor
self.args.cursor_position = 0
# Catch key pressed with non blocking mode
self.term_window.keypad(1)
self.term_window.nodelay(1)
......@@ -188,6 +209,8 @@ class _GlancesCurses(object):
try:
if hasattr(curses, 'start_color'):
curses.start_color()
logger.debug(
'Curses interface compatible with {} colors'.format(curses.COLORS))
if hasattr(curses, 'use_default_colors'):
curses.use_default_colors()
except Exception as e:
......@@ -226,35 +249,35 @@ class _GlancesCurses(object):
curses.init_pair(8, curses.COLOR_BLUE, -1)
# Colors text styles
if curses.COLOR_PAIRS > 8:
try:
curses.init_pair(9, curses.COLOR_MAGENTA, -1)
except Exception:
if self.is_theme('white'):
curses.init_pair(9, curses.COLOR_BLACK, -1)
else:
curses.init_pair(9, curses.COLOR_WHITE, -1)
try:
curses.init_pair(10, curses.COLOR_CYAN, -1)
except Exception:
if self.is_theme('white'):
curses.init_pair(10, curses.COLOR_BLACK, -1)
else:
curses.init_pair(10, curses.COLOR_WHITE, -1)
self.ifWARNING_color2 = curses.color_pair(9) | A_BOLD
self.ifCRITICAL_color2 = curses.color_pair(6) | A_BOLD
self.filter_color = curses.color_pair(10) | A_BOLD
self.no_color = curses.color_pair(1)
self.default_color = curses.color_pair(3) | A_BOLD
self.nice_color = curses.color_pair(9)
self.cpu_time_color = curses.color_pair(9)
self.nice_color = curses.color_pair(5)
self.cpu_time_color = curses.color_pair(5)
self.ifCAREFUL_color = curses.color_pair(4) | A_BOLD
self.ifWARNING_color = curses.color_pair(5) | A_BOLD
self.ifCRITICAL_color = curses.color_pair(2) | A_BOLD
self.default_color2 = curses.color_pair(7)
self.ifCAREFUL_color2 = curses.color_pair(8) | A_BOLD
self.ifWARNING_color2 = curses.color_pair(5) | A_BOLD
self.ifCRITICAL_color2 = curses.color_pair(6) | A_BOLD
self.filter_color = A_BOLD
self.selected_color = A_BOLD
if curses.COLOR_PAIRS > 8:
colors_list = [curses.COLOR_MAGENTA, curses.COLOR_CYAN, curses.COLOR_YELLOW]
for i in range(0, 3):
try:
curses.init_pair(i + 9, colors_list[i], -1)
except Exception:
if self.is_theme('white'):
curses.init_pair(i + 9, curses.COLOR_BLACK, -1)
else:
curses.init_pair(i + 9, curses.COLOR_WHITE, -1)
self.nice_color = curses.color_pair(9)
self.cpu_time_color = curses.color_pair(9)
self.ifWARNING_color2 = curses.color_pair(9) | A_BOLD
self.filter_color = curses.color_pair(10) | A_BOLD
self.selected_color = curses.color_pair(11) | A_BOLD
else:
# The screen is NOT compatible with a colored design
......@@ -271,6 +294,7 @@ class _GlancesCurses(object):
self.ifWARNING_color2 = A_BOLD
self.ifCRITICAL_color2 = curses.A_REVERSE
self.filter_color = A_BOLD
self.selected_color = A_BOLD
# Define the colors list (hash table) for stats
self.colors_list = {
......@@ -283,6 +307,7 @@ class _GlancesCurses(object):
'FILTER': self.filter_color,
'TITLE': self.title_color,
'PROCESS': self.default_color2,
'PROCESS_SELECTED': self.default_color2 | curses.A_UNDERLINE,
'STATUS': self.default_color2,
'NICE': self.nice_color,
'CPU_TIME': self.cpu_time_color,
......@@ -293,7 +318,8 @@ class _GlancesCurses(object):
'CAREFUL_LOG': self.ifCAREFUL_color,
'WARNING_LOG': self.ifWARNING_color,
'CRITICAL_LOG': self.ifCRITICAL_color,
'PASSWORD': curses.A_PROTECT
'PASSWORD': curses.A_PROTECT,
'SELECTED': self.selected_color
}
def set_cursor(self, value):
......@@ -331,22 +357,18 @@ class _GlancesCurses(object):
self._hotkeys[hotkey]['sort_key'] == 'auto')
# Other actions...
if self.pressedkey == ord('\x1b') or self.pressedkey == ord('q'):
# 'ESC'|'q' > Quit
if return_to_browser:
logger.info("Stop Glances client and return to the browser")
else:
logger.info("Stop Glances (keypressed: {})".format(self.pressedkey))
elif self.pressedkey == ord('\n'):
if self.pressedkey == ord('\n'):
# 'ENTER' > Edit the process filter
self.edit_filter = not self.edit_filter
elif self.pressedkey == ord('4'):
# '4' > Enable or disable quicklook
self.args.full_quicklook = not self.args.full_quicklook
if self.args.full_quicklook:
self.enable_fullquicklook()
else:
self.disable_fullquicklook()
elif self.pressedkey == ord('5'):
# '5' > Enable or disable top menu
self.args.disable_top = not self.args.disable_top
if self.args.disable_top:
self.disable_top()
......@@ -366,6 +388,9 @@ class _GlancesCurses(object):
# 'f' > Show/hide fs / folder stats
self.args.disable_fs = not self.args.disable_fs
self.args.disable_folders = not self.args.disable_folders
elif self.pressedkey == ord('k'):
# 'k' > Kill selected process (after confirmation)
self.kill_process = not self.kill_process
elif self.pressedkey == ord('w'):
# 'w' > Delete finished warning logs
glances_events.clean()
......@@ -387,6 +412,25 @@ class _GlancesCurses(object):
# ">" (right arrow) navigation through process sort
next_sort = (self.loop_position() + 1) % len(self._sort_loop)
glances_processes.set_sort_key(self._sort_loop[next_sort], False)
elif self.pressedkey == curses.KEY_UP or self.pressedkey == 65:
# 'UP' > Up in the server list
if self.args.cursor_position > 0:
self.args.cursor_position -= 1
elif self.pressedkey == curses.KEY_DOWN or self.pressedkey == 66:
# 'DOWN' > Down in the server list
# if self.args.cursor_position < glances_processes.max_processes - 2:
if self.args.cursor_position < glances_processes.processes_count:
self.args.cursor_position += 1
elif self.pressedkey == ord('\x1b') or self.pressedkey == ord('q'):
# 'ESC'|'q' > Quit
if return_to_browser:
logger.info("Stop Glances client and return to the browser")
else:
logger.info(
"Stop Glances (keypressed: {})".format(self.pressedkey))
elif self.pressedkey == curses.KEY_F5:
# "F5" manual refresh requested
pass
# Return the key code
return self.pressedkey
......@@ -591,13 +635,39 @@ class _GlancesCurses(object):
'- cmdline:.*glances.*\n' +
'- username:nicolargo\n' +
'- username:^root ',
is_input=True,
popup_type='input',
input_value=glances_processes.process_filter_input)
glances_processes.process_filter = new_filter
elif self.edit_filter and cs_status is not None:
self.display_popup('Process filter only available in standalone mode')
self.edit_filter = False
# Display kill process confirmation popup
# Only in standalone mode (cs_status is None)
if self.kill_process and cs_status is None:
selected_process_raw = stats.get_plugin('processlist').get_raw()[
self.args.cursor_position]
confirm = self.display_popup(
'Kill process: {} (pid: {}) ?\n\nConfirm ([y]es/[n]o): '.format(
selected_process_raw['name'],
selected_process_raw['pid']),
popup_type='yesno')
if confirm.lower().startswith('y'):
try:
ret_kill = glances_processes.kill(selected_process_raw['pid'])
except Exception as e:
logger.error('Can not kill process {} ({})'.format(
selected_process_raw['name'], e))
else:
logger.info('Kill signal has been sent to process {} (return code: {})'.format(
selected_process_raw['name'], ret_kill))
elif self.kill_process and cs_status is not None:
self.display_popup(
'Kill process only available in standalone mode')
self.kill_process = False
# Display graph generation popup
if self.args.generate_graph:
self.display_popup('Generate graph in {}'.format(self.args.export_graph_path))
......@@ -753,30 +823,37 @@ class _GlancesCurses(object):
def display_popup(self, message,
size_x=None, size_y=None,
duration=3,
is_input=False,
popup_type='info',
input_size=30,
input_value=None):
"""
Display a centered popup.
If is_input is False:
popup_type='info'
Just an infotmation popup, no user interaction
Display a centered popup with the given message during duration seconds
If size_x and size_y: set the popup size
else set it automatically
Return True if the popup could be displayed
If is_input is True:
popup_type='input'
Display a centered popup with the given message and a input field
If size_x and size_y: set the popup size
else set it automatically
Return the input string or None if the field is empty
popup_type='yesno'
Display a centered popup with the given message
If size_x and size_y: set the popup size
else set it automatically
Return True (yes) or False (no)
"""
# Center the popup
sentence_list = message.split('\n')
if size_x is None:
size_x = len(max(sentence_list, key=len)) + 4
# Add space for the input field
if is_input:
if popup_type == 'input':
size_x += input_size
if size_y is None:
size_y = len(sentence_list) + 4
......@@ -795,10 +872,15 @@ class _GlancesCurses(object):
popup.border()
# Add the message
for y, m in enumerate(message.split('\n')):
for y, m in enumerate(sentence_list):
popup.addnstr(2 + y, 2, m, len(m))
if is_input:
if popup_type == 'info':
# Display the popup
popup.refresh()
self.wait(duration * 1000)
return True
elif popup_type == 'input':
# Create a subwindow for the text field
subpop = popup.derwin(1, input_size, 2, 2 + len(m))
subpop.attron(self.colors_list['FILTER'])
......@@ -811,10 +893,10 @@ class _GlancesCurses(object):
# Create the textbox inside the subwindows
self.set_cursor(2)
self.term_window.keypad(1)
textbox = GlancesTextbox(subpop, insert_mode=False)
textbox = GlancesTextbox(subpop, insert_mode=True)
textbox.edit()
self.set_cursor(0)
self.term_window.keypad(0)
# self.term_window.keypad(0)
if textbox.gather() != '':
logger.debug(
"User enters the following string: %s" % textbox.gather())
......@@ -822,11 +904,23 @@ class _GlancesCurses(object):
else:
logger.debug("User centers an empty string")
return None
else:
elif popup_type == 'yesno':
# # Create a subwindow for the text field
subpop = popup.derwin(1, 2, len(sentence_list) + 1, len(m) + 2)
subpop.attron(self.colors_list['FILTER'])
# Init the field with the current value
subpop.addnstr(0, 0, '', 0)
# Display the popup
popup.refresh()
self.wait(duration * 1000)
return True
subpop.refresh()
# Create the textbox inside the subwindows
self.set_cursor(2)
self.term_window.keypad(1)
textbox = GlancesTextboxYesNo(subpop, insert_mode=False)
textbox.edit()
self.set_cursor(0)
# self.term_window.keypad(0)
return textbox.gather()
def display_plugin(self, plugin_stats,
display_optional=True,
......@@ -981,6 +1075,9 @@ class _GlancesCurses(object):
pressedkey = self.__catch_key(return_to_browser=return_to_browser)
# Is it an exit key ?
exitkey = (pressedkey == ord('\x1b') or pressedkey == ord('q'))
if pressedkey == curses.KEY_F5:
# were asked to refresh
return exitkey
if not exitkey and pressedkey > -1:
# Redraw display
self.flush(stats, cs_status=cs_status)
......@@ -1049,3 +1146,12 @@ class GlancesTextbox(Textbox, object):
if ch == 127: # Back
return 8
return super(GlancesTextbox, self).do_command(ch)
class GlancesTextboxYesNo(Textbox, object):
def __init__(self, *args, **kwargs):
super(GlancesTextboxYesNo, self).__init__(*args, **kwargs)
def do_command(self, ch):
return super(GlancesTextboxYesNo, self).do_command(ch)
......@@ -148,7 +148,7 @@ body {
}
}
#amps-plugin .process-result {
#amps .process-result {
max-width: 300px;
overflow: hidden;
white-space: pre-wrap;
......@@ -156,7 +156,7 @@ body {
text-overflow: ellipsis;
}
#gpu-plugin .gpu-name {
#gpu .gpu-name {
white-space: nowrap;
overflow: hidden;
width: 100%;
......
......@@ -22,7 +22,7 @@ export default function GlancesPluginAmpsController($scope, GlancesStats, favico
}, this);
};
vm.getDescriptionDecoration = function (process) {
vm.getNameDecoration = function (process) {
var count = process.count;
var countMin = process.countmin;
var countMax = process.countmax;
......
<section id="amps" class="plugin">
<div class="table">
<div class="table-row" ng-repeat="process in vm.processes">
<div class="table-cell text-left" ng-class="vm.getDescriptionDecoration(process)">{{ process.name }}</div>
<div class="table-cell text-left">{{ process.count }}</div>
<div class="table-cell text-left" ng-class="vm.getNameDecoration(process)">{{ process.name }}</div>
<div class="table-cell text-left" ng-if="process.regex">{{ process.count }}</div>
<div class="table-cell text-left process-result" ng-bind-html="process.result|nl2br"></div>
</div>
</div>
......
......@@ -19,7 +19,7 @@ export default function GlancesPluginDockerController($scope, GlancesStats) {
'status': containerData.Status,
'cpu': containerData.cpu.total,
'memory': containerData.memory.usage != undefined ? containerData.memory.usage : '?',
'rss': containerData.memory.rss != undefined ? containerData.memory.usage: '?',
'rss': containerData.memory.rss != undefined ? containerData.memory.rss : '?',
'ior': containerData.io.ior != undefined ? containerData.io.ior : '?',
'iow': containerData.io.iow != undefined ? containerData.io.iow : '?',
'io_time_since_update': containerData.io.time_since_update,
......
......@@ -5,27 +5,26 @@
<div class="table">
<div class="table-row" ng-if="arguments.meangpu || vm.gpus.length === 1">
<div class="table-cell text-left">proc:</div>
<div class="table-cell" ng-class="vm.getMeanDecoration('proc')" ng-if="vm.mean.proc">{{ vm.mean.proc |
<div class="table-cell" ng-class="vm.getMeanDecoration('proc')" ng-if="vm.mean.proc != null">{{ vm.mean.proc |
number : 0 }}%
</div>
<div class="table-cell" ng-if="!vm.mean.proc">N/A</div>
<div class="table-cell" ng-if="vm.mean.proc == null">N/A</div>
</div>
<div class="table-row" ng-if="arguments.meangpu || vm.gpus.length === 1">
<div class="table-cell text-left">mem:</div>
<div class="table-cell" ng-class="vm.getMeanDecoration('mem')" ng-if="vm.mean.mem">{{ vm.mean.mem | number :
<div class="table-cell" ng-class="vm.getMeanDecoration('mem')" ng-if="vm.mean.mem != null">{{ vm.mean.mem | number :
0 }}%
</div>
<div class="table-cell" ng-if="!vm.mean.mem">N/A</div>
<div class="table-cell" ng-if="vm.mean.mem == null">N/A</div>
</div>
<div class="table-row" ng-if="!arguments.meangpu && vm.gpus.length > 1" ng-repeat="gpu in vm.gpus">
<div class="table-cell text-left">
{{ gpu.gpu_id }}:
<span ng-class="vm.getDecoration(gpu.gpu_id, 'proc')"
ng-if="gpu.proc">{{ gpu.proc | number : 0 }}%</span>
<span ng-if="!gpu.proc">N/A</span>
<span ng-class="vm.getDecoration(gpu.gpu_id, 'proc')" ng-if="gpu.proc != null">{{ gpu.proc | number : 0 }}%</span>
<span ng-if="gpu.proc == null">N/A</span>
mem:
<span ng-class="vm.getDecoration(gpu.gpu_id, 'mem')" ng-if="gpu.mem">{{ gpu.mem | number : 0 }}%</span>
<span ng-if="!gpu.mem">N/A</span>
<span ng-class="vm.getDecoration(gpu.gpu_id, 'mem')" ng-if="gpu.mem != null">{{ gpu.mem | number : 0 }}%</span>
<span ng-if="gpu.mem == null">N/A</span>
</div>
</div>
</div>
......
......@@ -10,7 +10,7 @@ export default function GlancesPluginProcessController(ARGUMENTS, hotkeys) {
return !(column === 'username' || column === 'name');
},
getColumnLabel: function (column) {
if (_.isEqual(column, ['io_read', 'io_write'])) {
if (column === 'io_read' || column === 'io_write') {
return 'io_counters';
} else {
return column;
......
......@@ -37,35 +37,26 @@ export default function GlancesPluginProcesslistController($scope, GlancesStats,
}
if (process.num_threads === null) {
process.num_threads = -1;
process.num_threads = -1;
}
if (process.cpu_percent === null) {
process.cpu_percent = -1;
process.cpu_percent = -1;
}
if (process.memory_percent === null) {
process.memory_percent = -1;
if (process.memory_percent === null) {
process.memory_percent = -1;
}
process.ioRead = null;
process.ioWrite = null;
process.io_read = null;
process.io_write = null;
if (process.io_counters) {
vm.ioReadWritePresent = true;
process.ioRead = (process.io_counters[0] - process.io_counters[2]) / process.time_since_update;
if (process.ioRead != 0) {
process.ioRead = $filter('bytes')(process.ioRead);
}
process.ioWrite = (process.io_counters[1] - process.io_counters[3]) / process.time_since_update;
if (process.ioWrite != 0) {
process.ioWrite = $filter('bytes')(process.ioWrite);
}
process.io_read = (process.io_counters[0] - process.io_counters[2]) / process.time_since_update;
process.io_write = (process.io_counters[1] - process.io_counters[3]) / process.time_since_update;
}
process.isNice = process.nice !== undefined && ((data.stats.isWindows && process.nice != 32) || (!data.stats.isWindows && process.nice != 0));
......@@ -81,7 +72,7 @@ export default function GlancesPluginProcesslistController($scope, GlancesStats,
if (data.isWindows && process.username !== null) {
process.username = _.last(process.username.split('\\'));
}
vm.processes.push(process);
}
}
......
......@@ -32,8 +32,8 @@
<div class="table-cell text-left hidden-xs hidden-sm">{{ process.num_threads == -1 ? '?' : process.num_threads }}</div>
<div class="table-cell" ng-class="{nice: process.isNice}">{{process.nice | exclamation}}</div>
<div class="table-cell" ng-class="{status: process.status == 'R'}">{{process.status}}</div>
<div class="table-cell hidden-xs hidden-sm" ng-show="vm.ioReadWritePresent">{{process.ioRead}}</div>
<div class="table-cell text-left hidden-xs hidden-sm" ng-show="vm.ioReadWritePresent">{{process.ioWrite}}</div>
<div class="table-cell hidden-xs hidden-sm" ng-show="vm.ioReadWritePresent">{{process.io_read | bytes}}</div>
<div class="table-cell text-left hidden-xs hidden-sm" ng-show="vm.ioReadWritePresent">{{process.io_write | bytes}}</div>
<div class="table-cell text-left" ng-show="vm.arguments.process_short_name">{{process.name}}</div>
<div class="table-cell text-left" ng-show="!vm.arguments.process_short_name">{{process.cmdline}}</div>
</div>
......
......@@ -83,9 +83,9 @@
"dev": true
},
"angular": {
"version": "1.7.9",
"resolved": "https://registry.npmjs.org/angular/-/angular-1.7.9.tgz",
"integrity": "sha512-5se7ZpcOtu0MBFlzGv5dsM1quQDoDeUTwZrWjGtTNA7O88cD8TEk5IEKCTDa3uECV9XnvKREVUr7du1ACiWGFQ=="
"version": "1.8.0",
"resolved": "https://registry.npmjs.org/angular/-/angular-1.8.0.tgz",
"integrity": "sha512-VdaMx+Qk0Skla7B5gw77a8hzlcOakwF8mjlW13DpIWIDlfqwAbSSLfd8N/qZnzEmQF4jC4iofInd3gE7vL8ZZg=="
},
"angular-hotkeys": {
"version": "1.7.0",
......@@ -403,7 +403,6 @@
"resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz",
"integrity": "sha1-pDAdOJtqQ/m2f/PKEaP2Y342Dp4=",
"dev": true,
"optional": true,
"requires": {
"tweetnacl": "^0.14.3"
}
......@@ -707,7 +706,7 @@
},
"chalk": {
"version": "1.1.3",
"resolved": "http://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz",
"resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz",
"integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=",
"dev": true,
"requires": {
......@@ -1395,7 +1394,6 @@
"resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz",
"integrity": "sha1-OoOpBOVDUyh4dMVkt1SThoSamMk=",
"dev": true,
"optional": true,
"requires": {
"jsbn": "~0.1.0",
"safer-buffer": "^2.1.0"
......@@ -1408,9 +1406,9 @@
"dev": true
},
"elliptic": {
"version": "6.4.1",
"resolved": "https://registry.npmjs.org/elliptic/-/elliptic-6.4.1.tgz",
"integrity": "sha512-BsXLz5sqX8OHcsh7CqBMztyXARmGQ3LWPtGjJi6DiJHq5C/qvi9P3OqgswKSDftbu8+IoI/QDTAm2fFnQ9SZSQ==",
"version": "6.5.3",
"resolved": "https://registry.npmjs.org/elliptic/-/elliptic-6.5.3.tgz",
"integrity": "sha512-IMqzv5wNQf+E6aHeIqATs0tOLeOTwj1QKbRcS3jBbYkl5oLAserA8yJTT7/VyHUYG91PRmPyeQDObKLPpeS4dw==",
"dev": true,
"requires": {
"bn.js": "^4.4.0",
......@@ -1936,7 +1934,7 @@
"dependencies": {
"combined-stream": {
"version": "1.0.6",
"resolved": "http://registry.npmjs.org/combined-stream/-/combined-stream-1.0.6.tgz",
"resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.6.tgz",
"integrity": "sha1-cj599ugBrFYTETp+RFqbactjKBg=",
"dev": true,
"requires": {
......@@ -3305,8 +3303,7 @@
"version": "0.1.1",
"resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz",
"integrity": "sha1-peZUwuWi3rXyAdls77yoDA7y9RM=",
"dev": true,
"optional": true
"dev": true
},
"jsesc": {
"version": "0.5.0",
......@@ -3475,9 +3472,9 @@
}
},
"lodash": {
"version": "4.17.15",
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.15.tgz",
"integrity": "sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A=="
"version": "4.17.19",
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.19.tgz",
"integrity": "sha512-JNvd8XER9GQX0v2qJgsaN/mzFCNA5BRe/j8JN9d+tWyGLSodKQHKFicdwNYzWwI3wjRnaKPsGj1XkBjx/F96DQ=="
},
"lodash.camelcase": {
"version": "4.3.0",
......@@ -5774,9 +5771,9 @@
"dev": true
},
"sshpk": {
"version": "1.14.2",
"resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.14.2.tgz",
"integrity": "sha1-xvxhZIo9nE52T9P8306hBeSSupg=",
"version": "1.16.1",
"resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.16.1.tgz",
"integrity": "sha512-HXXqVUq7+pcKeLqqZj6mHFUMvXtOJt1uoUx09pFW6011inTMxqI8BA8PM95myrIyyKwdnzjdFjLiE6KBPVtJIg==",
"dev": true,
"requires": {
"asn1": "~0.2.3",
......@@ -6104,8 +6101,7 @@
"version": "0.14.5",
"resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz",
"integrity": "sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q=",
"dev": true,
"optional": true
"dev": true
},
"typedarray": {
"version": "0.0.6",
......@@ -6143,7 +6139,7 @@
},
"yargs": {
"version": "3.10.0",
"resolved": "http://registry.npmjs.org/yargs/-/yargs-3.10.0.tgz",
"resolved": "https://registry.npmjs.org/yargs/-/yargs-3.10.0.tgz",
"integrity": "sha1-9+572FfdfB0tOMDnTvvWgdFDH9E=",
"dev": true,
"requires": {
......@@ -6432,7 +6428,7 @@
},
"load-json-file": {
"version": "2.0.0",
"resolved": "http://registry.npmjs.org/load-json-file/-/load-json-file-2.0.0.tgz",
"resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-2.0.0.tgz",
"integrity": "sha1-eUfkIUmvgNaWy/eXvKq8/h/inKg=",
"dev": true,
"requires": {
......
{
"private": true,
"dependencies": {
"angular": "^1.7.9",
"angular": "^1.8.0",
"angular-hotkeys": "^1.7.0",
"bootstrap": "^3.4.1",
"favico.js": "^0.3.10",
"lodash": "^4.17.15"
"lodash": "^4.17.19"
},
"devDependencies": {
"clean-webpack-plugin": "^0.1.19",
......
此差异已折叠。
......@@ -23,6 +23,7 @@ from __future__ import unicode_literals
from glances.compat import nativestr, n
from glances.timer import getTimeSinceLastUpdate
from glances.plugins.glances_plugin import GlancesPlugin
from glances.logger import logger
import psutil
......@@ -51,6 +52,9 @@ class Plugin(GlancesPlugin):
# We want to display the stat in the curse interface
self.display_curse = True
# Hide stats if it has never been != 0
self.hide_zero = True
self.hide_zero_fields = ['read_bytes', 'write_bytes']
def get_key(self):
"""Return the key of the list."""
......@@ -143,9 +147,12 @@ class Plugin(GlancesPlugin):
# Call the father's method
super(Plugin, self).update_views()
# Check if the stats should be hidden
self.update_views_hidden()
# Add specifics informations
# Alert
for i in self.stats:
for i in self.get_raw():
disk_real_name = i['disk_name']
self.views[i[self.get_key()]]['read_bytes']['decoration'] = self.get_alert(int(i['read_bytes'] // i['time_since_update']),
header=disk_real_name + '_rx')
......@@ -179,6 +186,9 @@ class Plugin(GlancesPlugin):
ret.append(self.curse_add_line(msg))
# Disk list (sorted by name)
for i in self.sorted_stats():
# Hide stats if never be different from 0 (issue #1787)
if all([self.get_views(item=i[self.get_key()], key=f, option='hidden') for f in self.hide_zero_fields]):
continue
# Is there an alias for the disk name ?
disk_real_name = i['disk_name']
disk_name = self.has_alias(i['disk_name'])
......
......@@ -81,6 +81,9 @@ class Plugin(GlancesPlugin):
# The plgin can be disable using: args.disable_docker
self.args = args
# Default config keys
self.config = config
# We want to display the stat in the curse interface
self.display_curse = True
......@@ -207,6 +210,14 @@ class Plugin(GlancesPlugin):
# Get stats for all containers
stats['containers'] = []
for container in containers:
# Only show specific containers
if not self.is_show(nativestr(container.name)):
continue
# Do not take hiden container into account
if self.is_hide(nativestr(container.name)):
continue
# Init the stats for the current container
container_stats = {}
# The key is the container name and not the Id
......@@ -524,8 +535,11 @@ class Plugin(GlancesPlugin):
ret.append(self.curse_new_line())
# Header
ret.append(self.curse_new_line())
# Get the maximum containers name (cutted to 20 char max)
name_max_width = min(20, len(max(self.stats['containers'], key=lambda x: len(x['name']))['name']))
# Get the maximum containers name
# Max size is configurable. See feature request #1723.
name_max_width = min(self.config.get_int_value('docker', 'max_name_size', default=20),
len(max(self.stats['containers'],
key=lambda x: len(x['name']))['name']))
msg = ' {:{width}}'.format('Name', width=name_max_width)
ret.append(self.curse_add_line(msg))
msg = '{:>10}'.format('Status')
......
......@@ -103,8 +103,6 @@ class Plugin(GlancesPlugin):
return self.stats
# Optionnal hack to allow logicals mounts points (issue #448)
# Ex: Had to put 'allow=zfs' in the [fs] section of the conf file
# to allow zfs monitoring
for fstype in self.get_conf_value('allow'):
try:
fs_stat += [f for f in psutil.disk_partitions(all=True) if f.fstype.find(fstype) >= 0]
......
......@@ -2,7 +2,7 @@
#
# This file is part of Glances.
#
# Copyright (C) 2018 Kirby Banman <kirby.banman@gmail.com>
# Copyright (C) 2020 Kirby Banman <kirby.banman@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
......@@ -226,11 +226,11 @@ class Plugin(GlancesPlugin):
id_msg = '{}'.format(gpu_stats['gpu_id'])
try:
proc_msg = '{:>3.0f}%'.format(gpu_stats['proc'])
except ValueError:
except (ValueError, TypeError):
proc_msg = '{:>4}'.format('N/A')
try:
mem_msg = '{:>3.0f}%'.format(gpu_stats['mem'])
except ValueError:
except (ValueError, TypeError):
mem_msg = '{:>4}'.format('N/A')
msg = '{}: {} mem: {}'.format(id_msg,
proc_msg,
......
......@@ -150,6 +150,9 @@ class Plugin(GlancesPlugin):
"""
# Thanks to @Atticfire
# See https://github.com/nicolargo/glances/issues/1417#issuecomment-469894399
if ip is None:
# Correct issue #1528
return 0
return sum(bin(int(x)).count('1') for x in ip.split('.'))
......
......@@ -66,20 +66,24 @@ class Plugin(GlancesPlugin):
if self.input_method == 'local':
# Update stats using the standard system lib
# Grab SWAP using the psutil swap_memory method
sm_stats = psutil.swap_memory()
# Get all the swap stats (copy/paste of the psutil documentation)
# total: total swap memory in bytes
# used: used swap memory in bytes
# free: free swap memory in bytes
# percent: the percentage usage
# sin: the number of bytes the system has swapped in from disk (cumulative)
# sout: the number of bytes the system has swapped out from disk
# (cumulative)
for swap in ['total', 'used', 'free', 'percent',
'sin', 'sout']:
if hasattr(sm_stats, swap):
stats[swap] = getattr(sm_stats, swap)
try:
sm_stats = psutil.swap_memory()
except RuntimeError:
# Crash on startup on Illumos when no swap is configured #1767
pass
else:
# Get all the swap stats (copy/paste of the psutil documentation)
# total: total swap memory in bytes
# used: used swap memory in bytes
# free: free swap memory in bytes
# percent: the percentage usage
# sin: the number of bytes the system has swapped in from disk (cumulative)
# sout: the number of bytes the system has swapped out from disk
# (cumulative)
for swap in ['total', 'used', 'free', 'percent',
'sin', 'sout']:
if hasattr(sm_stats, swap):
stats[swap] = getattr(sm_stats, swap)
elif self.input_method == 'snmp':
# Update stats using SNMP
if self.short_system_name == 'windows':
......@@ -135,7 +139,8 @@ class Plugin(GlancesPlugin):
# Add specifics informations
# Alert and log
self.views['used']['decoration'] = self.get_alert_log(self.stats['used'], maximum=self.stats['total'])
if 'used' in self.stats and 'total' in self.stats:
self.views['used']['decoration'] = self.get_alert_log(self.stats['used'], maximum=self.stats['total'])
def msg_curse(self, args=None, max_width=None):
"""Return the dict to display in the curse interface."""
......
......@@ -61,6 +61,9 @@ class Plugin(GlancesPlugin):
# We want to display the stat in the curse interface
self.display_curse = True
# Hide stats if it has never been != 0
self.hide_zero = True
self.hide_zero_fields = ['rx', 'tx']
def get_key(self):
"""Return the key of the list."""
......@@ -223,13 +226,17 @@ class Plugin(GlancesPlugin):
# Call the father's method
super(Plugin, self).update_views()
# Check if the stats should be hidden
self.update_views_hidden()
# Add specifics informations
# Alert
for i in self.stats:
for i in self.get_raw():
ifrealname = i['interface_name'].split(':')[0]
# Convert rate in bps ( to be able to compare to interface speed)
# 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')
......@@ -290,6 +297,9 @@ class Plugin(GlancesPlugin):
# Do not display interface in down state (issue #765)
if ('is_up' in i) and (i['is_up'] is False):
continue
# Hide stats if never be different from 0 (issue #1787)
if all([self.get_views(item=i[self.get_key()], key=f, option='hidden') for f in self.hide_zero_fields]):
continue
# Format stats
# Is there an alias for the interface name ?
ifrealname = i['interface_name'].split(':')[0]
......
......@@ -41,6 +41,12 @@ class Plugin(GlancesPlugin):
# Set the message position
self.align = 'bottom'
if args.strftime_format:
self.strftime = args.strftime_format
elif config is not None:
if 'global' in config.as_dict():
self.strftime = config.as_dict()['global']['strftime_format']
def reset(self):
"""Reset/init the stats."""
self.stats = ''
......@@ -49,10 +55,14 @@ class Plugin(GlancesPlugin):
"""Update current date/time."""
# Had to convert it to string because datetime is not JSON serializable
# Add the time zone (issue #1249 / #1337 / #1598)
if (len(tzname[1]) > 6):
self.stats = strftime('%Y-%m-%d %H:%M:%S %z')
if self.strftime:
self.stats = strftime(self.strftime)
else:
self.stats = strftime('%Y-%m-%d %H:%M:%S %Z')
if (len(tzname[1]) > 6):
self.stats = strftime('%Y-%m-%d %H:%M:%S %z')
else:
self.stats = strftime('%Y-%m-%d %H:%M:%S %Z')
return self.stats
......
......@@ -99,6 +99,11 @@ class GlancesPlugin(object):
# Init the views
self.views = dict()
# Hide stats if all the hide_zero_fields has never been != 0
# Default is False, always display stats
self.hide_zero = False
self.hide_zero_fields = []
# Init the stats
self.stats_init_value = stats_init_value
self.stats = None
......@@ -422,16 +427,61 @@ class GlancesPlugin(object):
"Cannot get item({})=value({}) ({})".format(item, value, e))
return None
def update_views_hidden(self):
"""If the self.hide_zero is set then update the hidden field of the view
It will check if all fields values are already be different from 0
In this case, the hidden field is set to True
Note: This function should be called by plugin (in the update_views method)
Example (for network plugin):
__Init__
self.hide_zero_fields = ['rx', 'tx']
Update views
...
self.update_views_hidden()
"""
if not self.hide_zero:
return False
if (isinstance(self.get_raw(), list) and
self.get_raw() is not None and
self.get_key() is not None):
# Stats are stored in a list of dict (ex: NETWORK, FS...)
for i in self.get_raw():
if any([i[f] for f in self.hide_zero_fields]):
for f in self.hide_zero_fields:
self.views[i[self.get_key(
)]][f]['_zero'] = self.views[i[self.get_key()]][f]['hidden']
for f in self.hide_zero_fields:
self.views[i[self.get_key(
)]][f]['hidden'] = self.views[i[self.get_key()]][f]['_zero'] and i[f] == 0
elif isinstance(self.get_raw(), dict) and self.get_raw() is not None:
#
# Warning: This code has never been tested because
# no plugin with dict instance use the hidden function...
# vvvv
#
# Stats are stored in a dict (ex: CPU, LOAD...)
for key in listkeys(self.get_raw()):
if any([self.get_raw()[f] for f in self.hide_zero_fields]):
for f in self.hide_zero_fields:
self.views[f]['_zero'] = self.views[f]['hidden']
for f in self.hide_zero_fields:
self.views[f]['hidden'] = self.views['_zero'] and self.views[f] == 0
return True
def update_views(self):
"""Update the stats views.
The V of MVC
A dict of dict with the needed information to display the stats.
Example for the stat xxx:
'xxx': {'decoration': 'DEFAULT',
'optional': False,
'additional': False,
'splittable': False}
'xxx': {'decoration': 'DEFAULT', >>> The decoration of the stats
'optional': False, >>> Is the stat optional
'additional': False, >>> Is the stat provide additional information
'splittable': False, >>> Is the stat can be cut (like process lon name)
'hidden': False, >>> Is the stats should be hidden in the UI
'_zero': True} >>> For internal purpose only
"""
ret = {}
......@@ -440,12 +490,15 @@ class GlancesPlugin(object):
self.get_key() is not None):
# Stats are stored in a list of dict (ex: NETWORK, FS...)
for i in self.get_raw():
# i[self.get_key()] is the interface name (example for NETWORK)
ret[i[self.get_key()]] = {}
for key in listkeys(i):
value = {'decoration': 'DEFAULT',
'optional': False,
'additional': False,
'splittable': False}
'splittable': False,
'hidden': False,
'_zero': self.views[i[self.get_key()]][key]['_zero'] if i[self.get_key()] in self.views and key in self.views[i[self.get_key()]] else True}
ret[i[self.get_key()]][key] = value
elif isinstance(self.get_raw(), dict) and self.get_raw() is not None:
# Stats are stored in a dict (ex: CPU, LOAD...)
......@@ -453,7 +506,9 @@ class GlancesPlugin(object):
value = {'decoration': 'DEFAULT',
'optional': False,
'additional': False,
'splittable': False}
'splittable': False,
'hidden': False,
'_zero': self.views[key]['_zero'] if key in self.views and '_zero' in self.views[key] else True}
ret[key] = value
self.views = ret
......@@ -752,6 +807,21 @@ class GlancesPlugin(object):
except KeyError:
return default
def is_show(self, value, header=""):
"""Return True if the value is in the show configuration list.
If the show value is empty, return True (show by default)
The show configuration list is defined in the glances.conf file.
It is a comma separed list of regexp.
Example for diskio:
show=sda.*
"""
# @TODO: possible optimisation: create a re.compile list
if self.get_conf_value('show', header=header) == []:
return True
else:
return any(j for j in [re.match(i, value) for i in self.get_conf_value('show', header=header)])
def is_hide(self, value, header=""):
"""Return True if the value is in the hide configuration list.
......@@ -760,9 +830,7 @@ class GlancesPlugin(object):
Example for diskio:
hide=sda2,sda5,loop.*
"""
# TODO: possible optimisation: create a re.compile list
# Old version (see issue #1691)
#return not all(j is None for j in [re.match(i, value.lower()) for i in self.get_conf_value('hide', header=header)])
# @TODO: possible optimisation: create a re.compile list
return any(j for j in [re.match(i, value) for i in self.get_conf_value('hide', header=header)])
def has_alias(self, header):
......
......@@ -70,12 +70,13 @@ class Plugin(GlancesPlugin):
'status': '{:>1} ',
'ior': '{:>4} ',
'iow': '{:<4} ',
'command': '{}',
'command': '{} {}',
}
# Define the stat layout of the processes list columns
layout_stat = {
'cpu': '{:<6.1f} ',
'cpu': '{:<6.1f}',
'cpu_no_digit': '{:<6.0f}',
'mem': '{:<5.1f} ',
'virt': '{:<5} ',
'res': '{:<5} ',
......@@ -172,19 +173,26 @@ class Plugin(GlancesPlugin):
pass
return 'DEFAULT'
def get_process_curses_data(self, p, first, args):
def get_process_curses_data(self, p, selected, args):
"""Get curses data to display for a process.
- p is the process to display
- first is a tag=True if the process is the first on the list
- selected is a tag=True if the selected process
"""
ret = [self.curse_new_line()]
# When a process is selected:
# * display a special caracter at the beginning of the line
# * underline the command name
if args.is_standalone:
ret.append(self.curse_add_line('>' if selected else ' ', 'SELECTED'))
# CPU
if 'cpu_percent' in p and p['cpu_percent'] is not None and p['cpu_percent'] != '':
cpu_layout = self.layout_stat['cpu'] if p['cpu_percent'] < 100 else self.layout_stat['cpu_no_digit']
if args.disable_irix and self.nb_log_core != 0:
msg = self.layout_stat['cpu'].format(p['cpu_percent'] / float(self.nb_log_core))
msg = cpu_layout.format(
p['cpu_percent'] / float(self.nb_log_core))
else:
msg = self.layout_stat['cpu'].format(p['cpu_percent'])
msg = cpu_layout.format(p['cpu_percent'])
alert = self.get_alert(p['cpu_percent'],
highlight_zero=False,
is_max=(p['cpu_percent'] == self.max_values['cpu_percent']),
......@@ -321,28 +329,34 @@ class Plugin(GlancesPlugin):
else:
cmdline = '?'
try:
process_decoration = 'PROCESS_SELECTED' if (selected and args.is_standalone) else 'PROCESS'
if cmdline:
path, cmd, arguments = split_cmdline(cmdline)
# Manage end of line in arguments (see #1692)
arguments.replace('\r\n', ' ')
arguments.replace('\n', ' ')
if os.path.isdir(path) and not args.process_short_name:
msg = self.layout_stat['command'].format(path) + os.sep
ret.append(self.curse_add_line(msg, splittable=True))
ret.append(self.curse_add_line(cmd, decoration='PROCESS', splittable=True))
ret.append(self.curse_add_line(
cmd, decoration=process_decoration, splittable=True))
else:
msg = self.layout_stat['command'].format(cmd)
ret.append(self.curse_add_line(msg, decoration='PROCESS', splittable=True))
ret.append(self.curse_add_line(
msg, decoration=process_decoration, splittable=True))
if arguments:
msg = ' ' + self.layout_stat['command'].format(arguments)
ret.append(self.curse_add_line(msg, splittable=True))
else:
msg = self.layout_stat['name'].format(p['name'])
ret.append(self.curse_add_line(msg, splittable=True))
ret.append(self.curse_add_line(msg, decoration=process_decoration, splittable=True))
except (TypeError, UnicodeEncodeError) as e:
# Avoid crach after running fine for several hours #1335
logger.debug("Can not decode command line '{}' ({})".format(cmdline, e))
ret.append(self.curse_add_line('', splittable=True))
# Add extended stats but only for the top processes
if first and 'extended_stats' in p and args.enable_process_extended:
if args.cursor_position == 0 and 'extended_stats' in p and args.enable_process_extended:
# Left padding
xpad = ' ' * 13
# First line is CPU affinity
......@@ -429,11 +443,13 @@ class Plugin(GlancesPlugin):
# Process list
# Loop over processes (sorted by the sort key previously compute)
first = True
i = 0
for p in self.__sort_stats(process_sort_key):
ret.extend(self.get_process_curses_data(p, first, args))
# End of extended stats
first = False
ret.extend(self.get_process_curses_data(
p, i == args.cursor_position, args))
i += 1
# A filter is set Display the stats summaries
if glances_processes.process_filter is not None:
if args.reset_minmax_tag:
args.reset_minmax_tag = not args.reset_minmax_tag
......@@ -478,7 +494,8 @@ class Plugin(GlancesPlugin):
ret.append(self.curse_add_line(msg, sort_style if process_sort_key == 'io_counters' else 'DEFAULT', optional=True, additional=True))
msg = self.layout_header['iow'].format('W/s')
ret.append(self.curse_add_line(msg, sort_style if process_sort_key == 'io_counters' else 'DEFAULT', optional=True, additional=True))
msg = self.layout_header['command'].format('Command')
msg = self.layout_header['command'].format('Command',
"('k' to kill)" if args.is_standalone else "")
ret.append(self.curse_add_line(msg, sort_style if process_sort_key == 'name' else 'DEFAULT'))
def __msg_curse_sum(self, ret, sep_char='_', mmm=None, args=None):
......
......@@ -81,7 +81,11 @@ class Plugin(GlancesPlugin):
stats['percpu'] = cpu_percent.get(percpu=True)
# Use the psutil lib for the memory (virtual and swap)
stats['mem'] = psutil.virtual_memory().percent
stats['swap'] = psutil.swap_memory().percent
try:
stats['swap'] = psutil.swap_memory().percent
except RuntimeError:
# Correct issue in Illumos OS (see #1767)
stats['swap'] = None
elif self.input_method == 'snmp':
# Not available
pass
......@@ -99,8 +103,12 @@ class Plugin(GlancesPlugin):
stats['cpu_name'] = cpu_info.get('brand', 'CPU')
if 'hz_actual_raw' in cpu_info:
stats['cpu_hz_current'] = cpu_info['hz_actual_raw'][0]
elif 'hz_actual' in cpu_info:
stats['cpu_hz_current'] = cpu_info['hz_actual'][0]
if 'hz_advertised_raw' in cpu_info:
stats['cpu_hz'] = cpu_info['hz_advertised_raw'][0]
elif 'hz_advertised' in cpu_info:
stats['cpu_hz'] = cpu_info['hz_advertised'][0]
# Update the stats
self.stats = stats
......
......@@ -176,6 +176,11 @@ class GlancesProcesses(object):
else:
return None
@property
def processes_count(self):
"""Get the current number of processes showed in the UI."""
return min(self._max_processes - 2, glances_processes.processcount['total'] - 1)
@property
def max_processes(self):
"""Get the maximum number of processes showed in the UI."""
......@@ -398,6 +403,14 @@ class GlancesProcesses(object):
else:
self.auto_sort = auto
self._sort_key = key
def kill(self, pid, timeout=3):
"""Kill process with pid"""
assert pid != os.getpid(), "Glances can kill itself..."
p = psutil.Process(pid)
logger.debug('Send kill signal to process: {}'.format(p))
p.kill()
return p.wait(timeout)
def weighted(value):
......
......@@ -54,7 +54,7 @@ class GlancesStaticServer(object):
for s in ['name', 'port', 'alias']:
new_server[s] = config.get_value(self._section, '%s%s' % (postfix, s))
if new_server['name'] is not None:
# Manage optionnal information
# Manage optional information
if new_server['port'] is None:
new_server['port'] = '61209'
new_server['username'] = 'glances'
......
# install with base requirements file
-r requirements.txt
bernhard
bottle
cassandra-driver
......@@ -5,6 +8,7 @@ couchdb
docker>=2.0.0
elasticsearch
influxdb
influxdb-client; python_version >= "3.6"
kafka-python
netifaces
py3nvml; python_version >= "3.0"
......@@ -12,7 +16,7 @@ paho-mqtt
pika
potsdb
prometheus_client
py-cpuinfo
py-cpuinfo<=4.0.0
pygal
pymdstat
pysnmp
......
......@@ -55,7 +55,7 @@ def get_install_extras_require():
# Zeroconf 0.19.1 is the latest one compatible with Python 2 (issue #1293)
'browser': ['zeroconf==0.19.1' if PY2 else 'zeroconf>=0.19.1'],
'cloud': ['requests'],
'cpuinfo': ['py-cpuinfo'],
'cpuinfo': ['py-cpuinfo<=4.0.0'],
'docker': ['docker>=2.0.0'],
'export': ['bernhard', 'cassandra-driver', 'couchdb', 'elasticsearch',
'influxdb>=1.0.0', 'kafka-python', 'pika', 'paho-mqtt', 'potsdb',
......@@ -135,6 +135,7 @@ setup(
'Programming Language :: Python :: 3.6',
'Programming Language :: Python :: 3.7',
'Programming Language :: Python :: 3.8',
'Programming Language :: Python :: 3.9',
'Topic :: System :: Monitoring'
]
)
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册