提交 4f133b02 编写于 作者: N Nicolas Hennion

Make the refresh rate configurable per plugin #1870

......@@ -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
......
.\" 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')
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
# Do not take hide disk into account
if self.is_hide(disk):
continue
# 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)
# Save stats to compute next bitrate
self.diskio_old = diskio_new
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}
# Add alias if exist (define in the configuration file)
if self.has_alias(disk) is not None:
diskstat['alias'] = self.has_alias(disk)
# Add the dict key
diskstat['key'] = self.get_key()
# Ad dthe current disk stat to the list
stats.append(diskstat)
# 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]
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册