mirror of https://github.com/nicolargo/glances.git
Make the refresh rate configurable per plugin #1870
This commit is contained in:
commit
4f133b025c
24
Makefile
24
Makefile
|
|
@ -16,4 +16,28 @@ docs-server: docs
|
|||
webui:
|
||||
cd glances/outputs/static/ && npm install && npm audit fix && npm run build
|
||||
|
||||
venv:
|
||||
virtualenv -p /usr/bin/python3 venv
|
||||
./venv/bin/pip install -r requirements.txt
|
||||
./venv/bin/pip install -r optional-requirements.txt
|
||||
|
||||
venv-upgrade:
|
||||
./venv/bin/pip install --upgrade -r requirements.txt
|
||||
./venv/bin/pip install --upgrade -r optional-requirements.txt
|
||||
|
||||
run: venv
|
||||
./venv/bin/python -m glances -C ./conf/glances.conf
|
||||
|
||||
run-debug: venv
|
||||
./venv/bin/python -m glances -C ./conf/glances.conf -d
|
||||
|
||||
run-webserver: venv
|
||||
./venv/bin/python -m glances -C ./conf/glances.conf -w
|
||||
|
||||
run-server: venv
|
||||
./venv/bin/python -m glances -C ./conf/glances.conf -s
|
||||
|
||||
run-client: venv
|
||||
./venv/bin/python -m glances -C ./conf/glances.conf -c localhost
|
||||
|
||||
.PHONY: test docs docs-server
|
||||
|
|
|
|||
|
|
@ -3,6 +3,10 @@
|
|||
##############################################################################
|
||||
|
||||
[global]
|
||||
# Refresh rate (default is a minimum of 2 seconds)
|
||||
# Can be overwrite by the -t <sec> option
|
||||
# It is also possible to overwrite it in each plugin sections
|
||||
refresh=2
|
||||
# Does Glances should check if a newer version is available on PyPI ?
|
||||
check_update=false
|
||||
# History size (maximum number of values)
|
||||
|
|
@ -27,6 +31,8 @@ max_processes_display=30
|
|||
# Set to true to disable a plugin
|
||||
# Note: you can also disable it from the command line (see --disable-plugin <plugin_name>)
|
||||
disable=False
|
||||
# Set a specific refresh rate for this plugin by overwriting the default/refresh value
|
||||
#refresh=3
|
||||
# Graphical percentage char used in the terminal user interface (default is |)
|
||||
percentage_char=|
|
||||
# Define CPU, MEM and SWAP thresholds in %
|
||||
|
|
@ -45,7 +51,7 @@ disable=False
|
|||
# See https://scoutapm.com/blog/slow_server_flow_chart
|
||||
#
|
||||
# I/O wait percentage should be lower than 1/# (# = Logical CPU cores)
|
||||
# Leave commented to just use the default config:
|
||||
# Leave commented to just use the default config:
|
||||
# Careful=1/#*100-20% / Warning=1/#*100-10% / Critical=1/#*100
|
||||
#iowait_careful=30
|
||||
#iowait_warning=40
|
||||
|
|
@ -414,8 +420,8 @@ 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)
|
||||
# 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/
|
||||
|
|
|
|||
|
|
@ -39,8 +39,15 @@ A first section (called global) is available:
|
|||
.. code-block:: ini
|
||||
|
||||
[global]
|
||||
# Does Glances should check if a newer version is available on PyPI?
|
||||
check_update=true
|
||||
# Refresh rate (default is a minimum of 2 seconds)
|
||||
# Can be overwrite by the -t <sec> option
|
||||
# It is also possible to overwrite it in each plugin sections
|
||||
refresh=2
|
||||
# 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
|
||||
|
||||
Each plugin, export module and application monitoring process (AMP) can
|
||||
have a section. Below an example for the CPU plugin:
|
||||
|
|
@ -49,6 +56,7 @@ have a section. Below an example for the CPU plugin:
|
|||
|
||||
[cpu]
|
||||
disable=False
|
||||
refresh=3
|
||||
user_careful=50
|
||||
user_warning=70
|
||||
user_critical=90
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
.\" Man page generated from reStructuredText.
|
||||
.
|
||||
.TH "GLANCES" "1" "May 06, 2021" "3.1.8b1" "Glances"
|
||||
.TH "GLANCES" "1" "May 23, 2021" "3.1.8b3" "Glances"
|
||||
.SH NAME
|
||||
glances \- An eye on your system
|
||||
.
|
||||
|
|
@ -565,8 +565,15 @@ A first section (called global) is available:
|
|||
.nf
|
||||
.ft C
|
||||
[global]
|
||||
# Does Glances should check if a newer version is available on PyPI?
|
||||
check_update=true
|
||||
# Refresh rate (default is a minimum of 2 seconds)
|
||||
# Can be overwrite by the \-t <sec> option
|
||||
# It is also possible to overwrite it in each plugin sections
|
||||
refresh=2
|
||||
# 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
|
||||
.ft P
|
||||
.fi
|
||||
.UNINDENT
|
||||
|
|
@ -581,6 +588,7 @@ have a section. Below an example for the CPU plugin:
|
|||
.ft C
|
||||
[cpu]
|
||||
disable=False
|
||||
refresh=3
|
||||
user_careful=50
|
||||
user_warning=70
|
||||
user_critical=90
|
||||
|
|
|
|||
|
|
@ -44,7 +44,6 @@ 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
|
||||
from glances.timer import Counter
|
||||
# Check locale
|
||||
try:
|
||||
|
|
@ -112,7 +111,7 @@ def start(config, args):
|
|||
# Start the main loop
|
||||
logger.debug("Glances started in {} seconds".format(start_duration.get()))
|
||||
if args.stdout_issue:
|
||||
# Serve once for issue/test mode
|
||||
# Serve once for issue/test mode
|
||||
mode.serve_issue()
|
||||
else:
|
||||
# Serve forever
|
||||
|
|
@ -142,9 +141,9 @@ def main():
|
|||
global core
|
||||
|
||||
# Create the Glances main instance
|
||||
# Glances options from the command line are readed first (in __init__)
|
||||
# then the options from the config file (in parse_args)
|
||||
core = GlancesMain()
|
||||
config = core.get_config()
|
||||
args = core.get_args()
|
||||
|
||||
# Glances can be ran in standalone, client or server mode
|
||||
start(config=config, args=args)
|
||||
start(config=core.get_config(), args= core.get_args())
|
||||
|
|
|
|||
|
|
@ -34,9 +34,9 @@ class CpuPercent(object):
|
|||
|
||||
# cached_time is the minimum time interval between stats updates
|
||||
# since last update is passed (will retrieve old cached info instead)
|
||||
self.cached_time = 0
|
||||
self.timer_cpu = Timer(0)
|
||||
self.timer_percpu = Timer(0)
|
||||
self.cached_time = cached_time
|
||||
|
||||
def get_key(self):
|
||||
"""Return the key of the per CPU list."""
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
#
|
||||
# This file is part of Glances.
|
||||
#
|
||||
# Copyright (C) 2019 Nicolargo <nicolas@nicolargo.com>
|
||||
# Copyright (C) 2021 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
|
||||
|
|
@ -33,8 +33,8 @@ from glances.logger import logger, LOG_FILENAME
|
|||
class GlancesMain(object):
|
||||
"""Main class to manage Glances instance."""
|
||||
|
||||
# Default stats' refresh time is 3 seconds
|
||||
refresh_time = 3
|
||||
# Default stats' minimum refresh time is 2 seconds
|
||||
DEFAULT_REFRESH_TIME = 2
|
||||
# Set the default cache lifetime to 1 second (only for server)
|
||||
cached_time = 1
|
||||
# By default, Glances is ran in standalone mode (no client/server)
|
||||
|
|
@ -67,7 +67,7 @@ Examples of use:
|
|||
Monitor local machine and export stats to a CSV file (standalone mode):
|
||||
$ glances --export csv --export-csv-file /tmp/glances.csv
|
||||
|
||||
Monitor local machine and export stats to a InfluxDB server with 5s refresh time (standalone mode):
|
||||
Monitor local machine and export stats to a InfluxDB server with 5s refresh rate (standalone mode):
|
||||
$ glances -t 5 --export influxdb
|
||||
|
||||
Start a Glances XML-RPC server (server mode):
|
||||
|
|
@ -205,12 +205,14 @@ Examples of use:
|
|||
help='SNMP authentication key (only for SNMPv3)')
|
||||
parser.add_argument('--snmp-force', action='store_true', default=False,
|
||||
dest='snmp_force', help='force SNMP mode')
|
||||
parser.add_argument('-t', '--time', default=self.refresh_time, type=float,
|
||||
dest='time', help='set refresh time in seconds [default: {} sec]'.format(self.refresh_time))
|
||||
parser.add_argument('-t', '--time', default=self.DEFAULT_REFRESH_TIME, type=float,
|
||||
dest='time', help='set minumum refresh rate in seconds [default: {} sec]'.format(
|
||||
self.DEFAULT_REFRESH_TIME))
|
||||
parser.add_argument('-w', '--webserver', action='store_true', default=False,
|
||||
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))
|
||||
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
|
||||
|
|
@ -258,6 +260,8 @@ Examples of use:
|
|||
args = self.init_args().parse_args()
|
||||
|
||||
# Load the configuration file, if it exists
|
||||
# This function should be called after the parse_args
|
||||
# because the configration file path can be defined
|
||||
self.config = Config(args.conf_file)
|
||||
|
||||
# Debug mode
|
||||
|
|
@ -268,6 +272,15 @@ Examples of use:
|
|||
from warnings import simplefilter
|
||||
simplefilter("ignore")
|
||||
|
||||
# Plugins refresh rate
|
||||
if self.config.has_section('global'):
|
||||
global_refresh = self.config.get_float_value('global',
|
||||
'refresh',
|
||||
default=self.DEFAULT_REFRESH_TIME)
|
||||
if args.time == self.DEFAULT_REFRESH_TIME:
|
||||
args.time = global_refresh
|
||||
logger.debug('Global refresh rate is set to {} seconds'.format(args.time))
|
||||
|
||||
# Plugins disable/enable
|
||||
# Allow users to disable plugins from the glances.conf (issue #1378)
|
||||
for s in self.config.sections():
|
||||
|
|
|
|||
|
|
@ -20,10 +20,9 @@
|
|||
"""Curses interface class."""
|
||||
from __future__ import unicode_literals
|
||||
|
||||
import re
|
||||
import sys
|
||||
|
||||
from glances.compat import to_ascii, nativestr, b, u, itervalues, enable, disable
|
||||
from glances.compat import nativestr, u, itervalues, enable, disable
|
||||
from glances.globals import MACOS, WINDOWS
|
||||
from glances.logger import logger
|
||||
from glances.events import glances_events
|
||||
|
|
@ -104,7 +103,7 @@ class _GlancesCurses(object):
|
|||
# "<" (left arrow) navigation through process sort
|
||||
# ">" (right arrow) navigation through process sort
|
||||
# 'UP' > Up in the server list
|
||||
# 'DOWN' > Down in the server list
|
||||
# 'DOWN' > Down in the server list
|
||||
}
|
||||
|
||||
_sort_loop = ['cpu_percent', 'memory_percent', 'username',
|
||||
|
|
@ -666,9 +665,9 @@ class _GlancesCurses(object):
|
|||
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')
|
||||
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'])
|
||||
|
|
@ -684,7 +683,6 @@ class _GlancesCurses(object):
|
|||
'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))
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
#
|
||||
# This file is part of Glances.
|
||||
#
|
||||
# Copyright (C) 2019 Nicolargo <nicolas@nicolargo.com>
|
||||
# Copyright (C) 2021 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
|
||||
|
|
@ -77,7 +77,7 @@ class GlancesStdoutCsv(object):
|
|||
if isinstance(i, dict) and 'key' in i:
|
||||
for k in i.keys():
|
||||
line += '{}.{}.{}{}'.format(plugin,
|
||||
str(i['key']),
|
||||
str(i[i['key']]),
|
||||
str(k),
|
||||
self.separator)
|
||||
else:
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
#
|
||||
# This file is part of Glances.
|
||||
#
|
||||
# Copyright (C) 2019 Nicolargo <nicolas@nicolargo.com>
|
||||
# Copyright (C) 2021 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
|
||||
|
|
@ -21,9 +21,8 @@
|
|||
from __future__ import unicode_literals
|
||||
|
||||
from glances.logger import logger
|
||||
from glances.timer import getTimeSinceLastUpdate
|
||||
from glances.plugins.glances_plugin import GlancesPlugin
|
||||
from glances.compat import n, u, b, nativestr
|
||||
from glances.compat import nativestr
|
||||
|
||||
import psutil
|
||||
|
||||
|
|
|
|||
|
|
@ -40,6 +40,8 @@ class Plugin(GlancesPlugin):
|
|||
# The core number is displayed by the load plugin
|
||||
self.display_curse = False
|
||||
|
||||
@GlancesPlugin._check_decorator
|
||||
@GlancesPlugin._log_result_decorator
|
||||
def update(self):
|
||||
"""Update core stats.
|
||||
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
#
|
||||
# This file is part of Glances.
|
||||
#
|
||||
# Copyright (C) 2019 Nicolargo <nicolas@nicolargo.com>
|
||||
# Copyright (C) 2021 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
|
||||
|
|
@ -79,7 +79,6 @@ class Plugin(GlancesPlugin):
|
|||
@GlancesPlugin._log_result_decorator
|
||||
def update(self):
|
||||
"""Update CPU stats using the input method."""
|
||||
|
||||
# Grab stats into self.stats
|
||||
if self.input_method == 'local':
|
||||
stats = self.update_local()
|
||||
|
|
@ -105,39 +104,41 @@ class Plugin(GlancesPlugin):
|
|||
stats = self.get_init_value()
|
||||
|
||||
stats['total'] = cpu_percent.get()
|
||||
# Grab: 'user', 'system', 'idle', 'nice', 'iowait',
|
||||
# 'irq', 'softirq', 'steal', 'guest', 'guest_nice'
|
||||
cpu_times_percent = psutil.cpu_times_percent(interval=0.0)
|
||||
for stat in ['user', 'system', 'idle', 'nice', 'iowait',
|
||||
'irq', 'softirq', 'steal', 'guest', 'guest_nice']:
|
||||
if hasattr(cpu_times_percent, stat):
|
||||
stats[stat] = getattr(cpu_times_percent, stat)
|
||||
for stat in cpu_times_percent._fields:
|
||||
stats[stat] = getattr(cpu_times_percent, stat)
|
||||
|
||||
# Additional CPU stats (number of events not as a %; psutil>=4.1.0)
|
||||
# ctx_switches: number of context switches (voluntary + involuntary) per second
|
||||
# interrupts: number of interrupts per second
|
||||
# soft_interrupts: number of software interrupts per second. Always set to 0 on Windows and SunOS.
|
||||
# syscalls: number of system calls since boot. Always set to 0 on Linux.
|
||||
# - ctx_switches: number of context switches (voluntary + involuntary) since boot.
|
||||
# - interrupts: number of interrupts since boot.
|
||||
# - soft_interrupts: number of software interrupts since boot. Always set to 0 on Windows and SunOS.
|
||||
# - syscalls: number of system calls since boot. Always set to 0 on Linux.
|
||||
cpu_stats = psutil.cpu_stats()
|
||||
|
||||
# By storing time data we enable Rx/s and Tx/s calculations in the
|
||||
# XML/RPC API, which would otherwise be overly difficult work
|
||||
# for users of the API
|
||||
time_since_update = getTimeSinceLastUpdate('cpu')
|
||||
stats['time_since_update'] = getTimeSinceLastUpdate('cpu')
|
||||
|
||||
# Core number is needed to compute the CTX switch limit
|
||||
stats['cpucore'] = self.nb_log_core
|
||||
|
||||
# Previous CPU stats are stored in the cpu_stats_old variable
|
||||
if not hasattr(self, 'cpu_stats_old'):
|
||||
# First call, we init the cpu_stats_old var
|
||||
self.cpu_stats_old = cpu_stats
|
||||
# Init the stats (needed to have the key name for export)
|
||||
for stat in cpu_stats._fields:
|
||||
# @TODO: better to set it to None but should refactor views and UI...
|
||||
stats[stat] = 0
|
||||
else:
|
||||
# Others calls...
|
||||
for stat in cpu_stats._fields:
|
||||
if getattr(cpu_stats, stat) is not None:
|
||||
stats[stat] = getattr(cpu_stats, stat) - getattr(self.cpu_stats_old, stat)
|
||||
|
||||
stats['time_since_update'] = time_since_update
|
||||
|
||||
# Core number is needed to compute the CTX switch limit
|
||||
stats['cpucore'] = self.nb_log_core
|
||||
|
||||
# Save stats to compute next step
|
||||
self.cpu_stats_old = cpu_stats
|
||||
# Save stats to compute next step
|
||||
self.cpu_stats_old = cpu_stats
|
||||
|
||||
return stats
|
||||
|
||||
|
|
@ -242,11 +243,6 @@ class Plugin(GlancesPlugin):
|
|||
msg = '{:5.1f}%'.format(self.stats['total'])
|
||||
ret.append(self.curse_add_line(
|
||||
msg, self.get_views(key='total', option='decoration')))
|
||||
# if idle_tag:
|
||||
# ret.append(self.curse_add_line(
|
||||
# msg, self.get_views(key='total', option='decoration')))
|
||||
# else:
|
||||
# ret.append(self.curse_add_line(msg))
|
||||
# Idle CPU
|
||||
if 'idle' in self.stats and not idle_tag:
|
||||
msg = ' {:8}'.format('idle:')
|
||||
|
|
|
|||
|
|
@ -52,6 +52,7 @@ 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
|
||||
if config is not None:
|
||||
self.hide_zero = config.get_bool_value(
|
||||
|
|
@ -60,6 +61,10 @@ class Plugin(GlancesPlugin):
|
|||
self.hide_zero = False
|
||||
self.hide_zero_fields = ['read_bytes', 'write_bytes']
|
||||
|
||||
# Force a first update because we need two update to have the first stat
|
||||
self.update()
|
||||
self.refresh_timer.set(0)
|
||||
|
||||
def get_key(self):
|
||||
"""Return the key of the list."""
|
||||
return 'disk_name'
|
||||
|
|
@ -81,61 +86,64 @@ class Plugin(GlancesPlugin):
|
|||
# read_time: time spent reading from disk (in milliseconds)
|
||||
# write_time: time spent writing to disk (in milliseconds)
|
||||
try:
|
||||
diskiocounters = psutil.disk_io_counters(perdisk=True)
|
||||
diskio = psutil.disk_io_counters(perdisk=True)
|
||||
except Exception:
|
||||
return stats
|
||||
|
||||
# Previous disk IO stats are stored in the diskio_old variable
|
||||
if not hasattr(self, 'diskio_old'):
|
||||
# First call, we init the diskio_old var
|
||||
# By storing time data we enable Rx/s and Tx/s calculations in the
|
||||
# XML/RPC API, which would otherwise be overly difficult work
|
||||
# for users of the API
|
||||
time_since_update = getTimeSinceLastUpdate('disk')
|
||||
|
||||
diskio = diskio
|
||||
for disk in diskio:
|
||||
# By default, RamFS is not displayed (issue #714)
|
||||
if self.args is not None and not self.args.diskio_show_ramfs and disk.startswith('ram'):
|
||||
continue
|
||||
|
||||
# Do not take hide disk into account
|
||||
if self.is_hide(disk):
|
||||
continue
|
||||
|
||||
# Compute count and bit rate
|
||||
try:
|
||||
self.diskio_old = diskiocounters
|
||||
except (IOError, UnboundLocalError):
|
||||
pass
|
||||
else:
|
||||
# By storing time data we enable Rx/s and Tx/s calculations in the
|
||||
# XML/RPC API, which would otherwise be overly difficult work
|
||||
# for users of the API
|
||||
time_since_update = getTimeSinceLastUpdate('disk')
|
||||
diskstat = {
|
||||
'time_since_update': time_since_update,
|
||||
'disk_name': n(disk),
|
||||
'read_count': diskio[disk].read_count - \
|
||||
self.diskio_old[disk].read_count,
|
||||
'write_count': diskio[disk].write_count - \
|
||||
self.diskio_old[disk].write_count,
|
||||
'read_bytes': diskio[disk].read_bytes - \
|
||||
self.diskio_old[disk].read_bytes,
|
||||
'write_bytes': diskio[disk].write_bytes - \
|
||||
self.diskio_old[disk].write_bytes
|
||||
}
|
||||
except (KeyError, AttributeError):
|
||||
diskstat = {
|
||||
'time_since_update': time_since_update,
|
||||
'disk_name': n(disk),
|
||||
'read_count': 0,
|
||||
'write_count': 0,
|
||||
'read_bytes': 0,
|
||||
'write_bytes': 0}
|
||||
|
||||
diskio_new = diskiocounters
|
||||
for disk in diskio_new:
|
||||
# By default, RamFS is not displayed (issue #714)
|
||||
if self.args is not None and not self.args.diskio_show_ramfs and disk.startswith('ram'):
|
||||
continue
|
||||
# Add alias if exist (define in the configuration file)
|
||||
if self.has_alias(disk) is not None:
|
||||
diskstat['alias'] = self.has_alias(disk)
|
||||
|
||||
# Do not take hide disk into account
|
||||
if self.is_hide(disk):
|
||||
continue
|
||||
# Add the dict key
|
||||
diskstat['key'] = self.get_key()
|
||||
|
||||
# Compute count and bit rate
|
||||
try:
|
||||
read_count = (diskio_new[disk].read_count -
|
||||
self.diskio_old[disk].read_count)
|
||||
write_count = (diskio_new[disk].write_count -
|
||||
self.diskio_old[disk].write_count)
|
||||
read_bytes = (diskio_new[disk].read_bytes -
|
||||
self.diskio_old[disk].read_bytes)
|
||||
write_bytes = (diskio_new[disk].write_bytes -
|
||||
self.diskio_old[disk].write_bytes)
|
||||
diskstat = {
|
||||
'time_since_update': time_since_update,
|
||||
'disk_name': n(disk),
|
||||
'read_count': read_count,
|
||||
'write_count': write_count,
|
||||
'read_bytes': read_bytes,
|
||||
'write_bytes': write_bytes}
|
||||
# Add alias if exist (define in the configuration file)
|
||||
if self.has_alias(disk) is not None:
|
||||
diskstat['alias'] = self.has_alias(disk)
|
||||
except KeyError:
|
||||
continue
|
||||
else:
|
||||
diskstat['key'] = self.get_key()
|
||||
stats.append(diskstat)
|
||||
# Ad dthe current disk stat to the list
|
||||
stats.append(diskstat)
|
||||
|
||||
# Save stats to compute next bitrate
|
||||
self.diskio_old = diskio_new
|
||||
# Save stats to compute next bitrate
|
||||
try:
|
||||
self.diskio_old = diskio
|
||||
except (IOError, UnboundLocalError):
|
||||
pass
|
||||
elif self.input_method == 'snmp':
|
||||
# Update stats using SNMP
|
||||
# No standard way for the moment...
|
||||
|
|
|
|||
|
|
@ -95,6 +95,10 @@ class Plugin(GlancesPlugin):
|
|||
# value: instance of ThreadDockerGrabber
|
||||
self.thread_list = {}
|
||||
|
||||
# Force a first update because we need two update to have the first stat
|
||||
self.update()
|
||||
self.refresh_timer.set(0)
|
||||
|
||||
def exit(self):
|
||||
"""Overwrite the exit method to close threads."""
|
||||
for t in itervalues(self.thread_list):
|
||||
|
|
@ -303,8 +307,8 @@ class Plugin(GlancesPlugin):
|
|||
precpu_new['system'] = all_stats['precpu_stats'].get(
|
||||
'system_cpu_usage', None)
|
||||
# Issue #1857
|
||||
# If either precpu_stats.online_cpus or cpu_stats.online_cpus is nil
|
||||
# then for compatibility with older daemons the length of
|
||||
# If either precpu_stats.online_cpus or cpu_stats.online_cpus is nil
|
||||
# then for compatibility with older daemons the length of
|
||||
# the corresponding cpu_usage.percpu_usage array should be used.
|
||||
if 'online_cpus' in all_stats['cpu_stats'] and \
|
||||
all_stats['cpu_stats']['online_cpus'] is not None:
|
||||
|
|
@ -558,7 +562,7 @@ class Plugin(GlancesPlugin):
|
|||
# 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'],
|
||||
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))
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
#
|
||||
# This file is part of Glances.
|
||||
#
|
||||
# Copyright (C) 2019 Nicolargo <nicolas@nicolargo.com>
|
||||
# Copyright (C) 2021 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
|
||||
|
|
@ -22,7 +22,7 @@ from __future__ import unicode_literals
|
|||
|
||||
import numbers
|
||||
|
||||
from glances.compat import nativestr, n
|
||||
from glances.compat import nativestr
|
||||
from glances.folder_list import FolderList as glancesFolderList
|
||||
from glances.plugins.glances_plugin import GlancesPlugin
|
||||
from glances.logger import logger
|
||||
|
|
|
|||
|
|
@ -19,6 +19,7 @@
|
|||
|
||||
"""Virtual memory plugin."""
|
||||
|
||||
from glances.logger import logger
|
||||
from glances.compat import iterkeys
|
||||
from glances.plugins.glances_plugin import GlancesPlugin
|
||||
|
||||
|
|
|
|||
|
|
@ -60,6 +60,7 @@ 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
|
||||
if config is not None:
|
||||
self.hide_zero = config.get_bool_value(
|
||||
|
|
@ -68,11 +69,15 @@ class Plugin(GlancesPlugin):
|
|||
self.hide_zero = False
|
||||
self.hide_zero_fields = ['rx', 'tx']
|
||||
|
||||
# Force a first update because we need two update to have the first stat
|
||||
self.update()
|
||||
self.refresh_timer.set(0)
|
||||
|
||||
def get_key(self):
|
||||
"""Return the key of the list."""
|
||||
return 'interface_name'
|
||||
|
||||
@GlancesPlugin._check_decorator
|
||||
# @GlancesPlugin._check_decorator
|
||||
@GlancesPlugin._log_result_decorator
|
||||
def update(self):
|
||||
"""Update network stats using the input method.
|
||||
|
|
|
|||
|
|
@ -34,7 +34,7 @@ from glances.history import GlancesHistory
|
|||
from glances.logger import logger
|
||||
from glances.events import glances_events
|
||||
from glances.thresholds import glances_thresholds
|
||||
from glances.timer import Counter
|
||||
from glances.timer import Counter, Timer
|
||||
|
||||
|
||||
class GlancesPlugin(object):
|
||||
|
|
@ -104,6 +104,9 @@ class GlancesPlugin(object):
|
|||
self.hide_zero = False
|
||||
self.hide_zero_fields = []
|
||||
|
||||
# Set the initial refresh time to display stats the first time
|
||||
self.refresh_timer = Timer(0)
|
||||
|
||||
# Init the stats
|
||||
self.stats_init_value = stats_init_value
|
||||
self.stats = None
|
||||
|
|
@ -584,6 +587,13 @@ class GlancesPlugin(object):
|
|||
"""Set the limits to input_limits."""
|
||||
self._limits = input_limits
|
||||
|
||||
def get_limits(self, item=None):
|
||||
"""Return the limits object."""
|
||||
if item is None:
|
||||
return self._limits
|
||||
else:
|
||||
return self._limits.get('{}_{}'.format(self.plugin_name, item), None)
|
||||
|
||||
def get_stats_action(self):
|
||||
"""Return stats for the action.
|
||||
|
||||
|
|
@ -989,12 +999,29 @@ class GlancesPlugin(object):
|
|||
ret = '\\'
|
||||
return ret
|
||||
|
||||
def get_refresh_time(self):
|
||||
"""Return the plugin refresh time"""
|
||||
ret = self.get_limits(item='refresh')
|
||||
if ret is None:
|
||||
ret = self.args.time
|
||||
return ret
|
||||
|
||||
def _check_decorator(fct):
|
||||
"""Check if the plugin is enabled."""
|
||||
"""Check decorator for update method.
|
||||
It checks:
|
||||
- if the plugin is enabled.
|
||||
- if the refresh_timer is finished
|
||||
"""
|
||||
def wrapper(self, *args, **kw):
|
||||
if self.is_enable():
|
||||
if self.is_enable() and (self.refresh_timer.finished() or self.stats == self.get_init_value):
|
||||
# Run the method
|
||||
ret = fct(self, *args, **kw)
|
||||
# Reset the timer
|
||||
self.refresh_timer.set(self.get_refresh_time())
|
||||
self.refresh_timer.reset()
|
||||
else:
|
||||
# No need to call the method
|
||||
# Return the last result available
|
||||
ret = self.stats
|
||||
return ret
|
||||
return wrapper
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
#
|
||||
# This file is part of Glances.
|
||||
#
|
||||
# Copyright (C) 2019 Nicolargo <nicolas@nicolargo.com>
|
||||
# Copyright (C) 2021 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
|
||||
|
|
@ -60,9 +60,6 @@ class Plugin(GlancesPlugin):
|
|||
self.stats = GlancesPortsList(config=config, args=args).get_ports_list() + \
|
||||
GlancesWebList(config=config, args=args).get_web_list()
|
||||
|
||||
# Init global Timer
|
||||
self.timer_ports = Timer(0)
|
||||
|
||||
# Global Thread running all the scans
|
||||
self._thread = None
|
||||
|
||||
|
|
@ -73,6 +70,7 @@ class Plugin(GlancesPlugin):
|
|||
# Call the father class
|
||||
super(Plugin, self).exit()
|
||||
|
||||
@GlancesPlugin._check_decorator
|
||||
@GlancesPlugin._log_result_decorator
|
||||
def update(self):
|
||||
"""Update the ports list."""
|
||||
|
|
@ -84,15 +82,15 @@ class Plugin(GlancesPlugin):
|
|||
thread_is_running = False
|
||||
else:
|
||||
thread_is_running = self._thread.is_alive()
|
||||
if self.timer_ports.finished() and not thread_is_running:
|
||||
if not thread_is_running:
|
||||
# Run ports scanner
|
||||
self._thread = ThreadScanner(self.stats)
|
||||
self._thread.start()
|
||||
# Restart timer
|
||||
if len(self.stats) > 0:
|
||||
self.timer_ports = Timer(self.stats[0]['refresh'])
|
||||
else:
|
||||
self.timer_ports = Timer(0)
|
||||
# # Restart timer
|
||||
# if len(self.stats) > 0:
|
||||
# self.timer_ports = Timer(self.stats[0]['refresh'])
|
||||
# else:
|
||||
# self.timer_ports = Timer(0)
|
||||
else:
|
||||
# Not available in SNMP mode
|
||||
pass
|
||||
|
|
|
|||
|
|
@ -62,6 +62,7 @@ class Plugin(GlancesPlugin):
|
|||
|
||||
# Note: 'glances_processes' is already init in the glances_processes.py script
|
||||
|
||||
@GlancesPlugin._check_decorator
|
||||
@GlancesPlugin._log_result_decorator
|
||||
def update(self):
|
||||
"""Update processes stats using the input method."""
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
#
|
||||
# This file is part of Glances.
|
||||
#
|
||||
# Copyright (C) 2019 Nicolargo <nicolas@nicolargo.com>
|
||||
# Copyright (C) 2021 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
|
||||
|
|
@ -17,11 +17,10 @@
|
|||
# You should have received a copy of the GNU Lesser General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
import operator
|
||||
import os
|
||||
|
||||
from glances.compat import iteritems, itervalues, listitems, iterkeys
|
||||
from glances.globals import BSD, LINUX, MACOS, SUNOS, WINDOWS, WSL
|
||||
from glances.compat import iterkeys
|
||||
from glances.globals import BSD, LINUX, MACOS, WINDOWS
|
||||
from glances.timer import Timer, getTimeSinceLastUpdate
|
||||
from glances.filter import GlancesFilter
|
||||
from glances.logger import logger
|
||||
|
|
@ -403,7 +402,7 @@ 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..."
|
||||
|
|
|
|||
|
|
@ -92,7 +92,7 @@ class GlancesStandalone(object):
|
|||
# Init screen
|
||||
self.screen = GlancesStdout(config=config, args=args)
|
||||
elif args.stdout_csv:
|
||||
logger.info("Stdout CSV mode is ON, following stats will be displayed: {}".format(args.stdout))
|
||||
logger.info("Stdout CSV mode is ON, following stats will be displayed: {}".format(args.stdout_csv))
|
||||
# Init screen
|
||||
self.screen = GlancesStdoutCsv(config=config, args=args)
|
||||
else:
|
||||
|
|
@ -129,15 +129,14 @@ class GlancesStandalone(object):
|
|||
|
||||
return True if we should continue (no exit key has been pressed)
|
||||
"""
|
||||
# Start a counter used to compute the time needed for
|
||||
# update and export the stats
|
||||
counter = Counter()
|
||||
|
||||
# Update stats
|
||||
# Start a counter used to compute the time needed
|
||||
counter = Counter()
|
||||
self.stats.update()
|
||||
logger.debug('Stats updated duration: {} seconds'.format(counter.get()))
|
||||
|
||||
# Export stats
|
||||
# Start a counter used to compute the time needed
|
||||
counter_export = Counter()
|
||||
self.stats.export(self.stats)
|
||||
logger.debug('Stats exported duration: {} seconds'.format(counter_export.get()))
|
||||
|
|
@ -151,7 +150,8 @@ class GlancesStandalone(object):
|
|||
if not self.quiet:
|
||||
# The update function return True if an exit key 'q' or 'ESC'
|
||||
# has been pressed.
|
||||
ret = not self.screen.update(self.stats, duration=adapted_refresh)
|
||||
ret = not self.screen.update(self.stats,
|
||||
duration=adapted_refresh)
|
||||
else:
|
||||
# Nothing is displayed
|
||||
# Break should be done via a signal (CTRL-C)
|
||||
|
|
@ -162,9 +162,11 @@ class GlancesStandalone(object):
|
|||
|
||||
def serve_forever(self):
|
||||
"""Wrapper to the serve_forever function."""
|
||||
loop = True
|
||||
while loop:
|
||||
loop = self.__serve_once()
|
||||
# loop = True
|
||||
# while loop:
|
||||
# loop = self.__serve_once()
|
||||
while self.__serve_once():
|
||||
pass
|
||||
self.end()
|
||||
|
||||
def end(self):
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
#
|
||||
# This file is part of Glances.
|
||||
#
|
||||
# Copyright (C) 2019 Nicolargo <nicolas@nicolargo.com>
|
||||
# Copyright (C) 2021 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
|
||||
|
|
@ -45,12 +45,9 @@ class GlancesStats(object):
|
|||
self.args = args
|
||||
|
||||
# Load plugins and exports modules
|
||||
self.first_export = True
|
||||
self.load_modules(self.args)
|
||||
|
||||
# Load the limits (for plugins)
|
||||
# Not necessary anymore, configuration file is loaded on init
|
||||
# self.load_limits(self.config)
|
||||
|
||||
def __getattr__(self, item):
|
||||
"""Overwrite the getattr method in case of attribute is not found.
|
||||
|
||||
|
|
@ -229,31 +226,33 @@ class GlancesStats(object):
|
|||
# If current plugin is disable
|
||||
# then continue to next plugin
|
||||
continue
|
||||
start_duration = Counter()
|
||||
# Update the stats...
|
||||
self._plugins[p].update()
|
||||
# ... the history
|
||||
self._plugins[p].update_stats_history()
|
||||
# ... and the views
|
||||
self._plugins[p].update_views()
|
||||
# logger.debug("Plugin {} update duration: {} seconds".format(p,
|
||||
# start_duration.get()))
|
||||
|
||||
def export(self, input_stats=None):
|
||||
"""Export all the stats.
|
||||
|
||||
Each export module is ran in a dedicated thread.
|
||||
"""
|
||||
# threads = []
|
||||
if self.first_export:
|
||||
logger.debug("Do not export stats during the first iteration because some information are missing")
|
||||
self.first_export = False
|
||||
return False
|
||||
|
||||
input_stats = input_stats or {}
|
||||
|
||||
for e in self._exports:
|
||||
logger.debug("Export stats using the %s module" % e)
|
||||
thread = threading.Thread(target=self._exports[e].update,
|
||||
args=(input_stats,))
|
||||
# threads.append(thread)
|
||||
thread.start()
|
||||
|
||||
return True
|
||||
|
||||
def getAll(self):
|
||||
"""Return all the stats (list)."""
|
||||
return [self._plugins[p].get_raw() for p in self._plugins]
|
||||
|
|
|
|||
Loading…
Reference in New Issue