mirror of
https://github.com/nicolargo/glances.git
synced 2024-12-26 10:42:29 +03:00
Merge branch 'develop' into feature/issue480
This commit is contained in:
commit
ac3d68e393
2
NEWS
2
NEWS
@ -9,6 +9,8 @@ Enhancements and news features:
|
||||
|
||||
* Grab FAN speed in the Glances sensors plugin (issue #501)
|
||||
* Allow logical mounts points in the FS plugin (issue #448)
|
||||
* Add a --disable-hddtemp to disable HDD temperature module at startup (issue #515)
|
||||
* Add a quiet mode (-q). Can be usefull if you need a Statsd or Influxdb provider only.
|
||||
|
||||
Bugs corrected:
|
||||
|
||||
|
@ -27,7 +27,7 @@ It uses the `psutil`_ library to get information from your system.
|
||||
Requirements
|
||||
============
|
||||
|
||||
- ``python >= 2.6`` (tested with version 2.6, 2.7, 3.3, 3.4)
|
||||
- ``python >= 2.6`` or ``>= 3.3`` (tested with version 2.6, 2.7, 3.3, 3.4)
|
||||
- ``psutil >= 2.0.0``
|
||||
- ``setuptools``
|
||||
|
||||
|
1140
conf/glances-grafana.json
Normal file
1140
conf/glances-grafana.json
Normal file
File diff suppressed because it is too large
Load Diff
@ -180,6 +180,7 @@ port=8086
|
||||
user=root
|
||||
password=root
|
||||
db=glances
|
||||
#prefix=localhost
|
||||
|
||||
[statsd]
|
||||
host=localhost
|
||||
|
@ -171,6 +171,7 @@ port=8086
|
||||
user=root
|
||||
password=root
|
||||
db=glances
|
||||
#prefix=localhost
|
||||
|
||||
[statsd]
|
||||
host=localhost
|
||||
|
@ -2,11 +2,11 @@
|
||||
Glances
|
||||
=======
|
||||
|
||||
This manual describes *Glances* version 2.3.
|
||||
This manual describes *Glances* version 2.4.
|
||||
|
||||
Copyright © 2011-2015 Nicolas Hennion <nicolas@nicolargo.com>
|
||||
|
||||
January 2015
|
||||
April 2015
|
||||
|
||||
.. contents:: Table of Contents
|
||||
|
||||
@ -143,6 +143,7 @@ Command-Line Options
|
||||
--disable-fs disable filesystem module
|
||||
--disable-network disable network module
|
||||
--disable-sensors disable sensors module
|
||||
--disable-hddtemp disable HDDTemp module
|
||||
--disable-left-sidebar
|
||||
disable left sidebar
|
||||
--disable-process disable process module
|
||||
@ -187,6 +188,7 @@ Command-Line Options
|
||||
--snmp-force force SNMP mode
|
||||
-t TIME, --time TIME set refresh time in seconds [default: 3 sec]
|
||||
-w, --webserver run Glances in web server mode
|
||||
-q, --quiet run Glances in quiet mode (nothing is displayed)
|
||||
-f PROCESS_FILTER, --process-filter PROCESS_FILTER
|
||||
set the process filter patern (regular expression)
|
||||
--process-short-name force short name for processes name
|
||||
@ -397,7 +399,7 @@ Disconnected:
|
||||
|
||||
.. image:: images/disconnected.png
|
||||
|
||||
QUICKLOOK
|
||||
QuickLook
|
||||
---------
|
||||
|
||||
The quicklook plugin is only display on wide screen and propose a bar view for CPU and memory (virtual and swap).
|
||||
@ -789,6 +791,10 @@ and run Glances with:
|
||||
|
||||
$ glances --export-influxdb
|
||||
|
||||
For Grafana users', Glances provides a dedicated `dashboard`_. Just import the file in your Grafana Web interface.
|
||||
|
||||
.. image:: images/grafana.png
|
||||
|
||||
*Statsd*
|
||||
|
||||
You can export statistics to a Statsd server (welcome to Graphite !). The connection should be defined in the Glances configuration file as following:
|
||||
@ -847,3 +853,4 @@ Feel free to contribute !
|
||||
.. _XML-RPC server: http://docs.python.org/2/library/simplexmlrpcserver.html
|
||||
.. _RESTFUL-JSON: http://jsonapi.org/
|
||||
.. _forum: https://groups.google.com/forum/?hl=en#!forum/glances-users
|
||||
.. _forum: https://github.com/nicolargo/glances/blob/master/conf/glances-grafana.json
|
||||
|
BIN
docs/images/grafana.png
Normal file
BIN
docs/images/grafana.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 198 KiB |
@ -44,21 +44,17 @@ from glances.core.glances_globals import gettext_domain, locale_dir
|
||||
from glances.core.glances_logging import logger
|
||||
from glances.core.glances_main import GlancesMain
|
||||
|
||||
# Get PSutil version
|
||||
psutil_min_version = (2, 0, 0)
|
||||
psutil_version = tuple([int(num) for num in __psutil_version.split('.')])
|
||||
|
||||
# First log with Glances and PSUtil version
|
||||
logger.info('Start Glances {0}'.format(__version__))
|
||||
logger.info('{0} {1} and PSutil {2} detected'.format(platform.python_implementation(),
|
||||
platform.python_version(),
|
||||
__psutil_version))
|
||||
|
||||
# Check PSutil version
|
||||
if psutil_version < psutil_min_version:
|
||||
logger.critical('PSutil 2.0 or higher is needed. Glances cannot start.')
|
||||
# Check Python version
|
||||
if sys.version_info < (2, 6) or (3, 0) <= sys.version_info < (3, 3):
|
||||
print('Glances requires at least Python 2.6 or 3.3 to run.')
|
||||
sys.exit(1)
|
||||
|
||||
# Check PSutil version
|
||||
psutil_min_version = (2, 0, 0)
|
||||
psutil_version = tuple([int(num) for num in __psutil_version.split('.')])
|
||||
if psutil_version < psutil_min_version:
|
||||
print('PSutil 2.0 or higher is needed. Glances cannot start.')
|
||||
sys.exit(1)
|
||||
|
||||
def __signal_handler(signal, frame):
|
||||
"""Callback for CTRL-C."""
|
||||
@ -94,8 +90,23 @@ def main():
|
||||
Select the mode (standalone, client or server)
|
||||
Run it...
|
||||
"""
|
||||
# Log Glances and PSutil version
|
||||
logger.info('Start Glances {0}'.format(__version__))
|
||||
logger.info('{0} {1} and PSutil {2} detected'.format(
|
||||
platform.python_implementation(),
|
||||
platform.python_version(),
|
||||
__psutil_version))
|
||||
|
||||
# Setup translations
|
||||
locale.setlocale(locale.LC_ALL, '')
|
||||
try:
|
||||
locale.setlocale(locale.LC_ALL, '')
|
||||
except locale.Error:
|
||||
# Issue #517
|
||||
# Setting LC_ALL to '' should not generate an error unless LC_ALL is not
|
||||
# defined in the user environment, which can be the case when used via SSH.
|
||||
# So simply skip this error, as python will use the C locale by default.
|
||||
logger.warning("No locale LC_ALL variable found. Use the default C locale.")
|
||||
pass
|
||||
gettext.install(gettext_domain, locale_dir)
|
||||
|
||||
# Share global var
|
||||
|
@ -28,11 +28,6 @@ try:
|
||||
except ImportError:
|
||||
# Python 2
|
||||
from xmlrpclib import Transport, ServerProxy, ProtocolError, Fault
|
||||
try:
|
||||
import http.client as httplib
|
||||
except ImportError:
|
||||
# Python 2
|
||||
import httplib
|
||||
|
||||
# Import Glances libs
|
||||
from glances.core.glances_globals import version
|
||||
@ -58,8 +53,8 @@ class GlancesClient(object):
|
||||
self.args = args
|
||||
self.config = config
|
||||
|
||||
# Client mode:
|
||||
self.set_mode()
|
||||
# Default client mode
|
||||
self._client_mode = 'glances'
|
||||
|
||||
# Return to browser or exit
|
||||
self.return_to_browser = return_to_browser
|
||||
@ -89,22 +84,19 @@ class GlancesClient(object):
|
||||
else:
|
||||
logger.error(msg)
|
||||
|
||||
def set_mode(self, mode='glances'):
|
||||
@property
|
||||
def client_mode(self):
|
||||
"""Get the client mode."""
|
||||
return self._client_mode
|
||||
|
||||
@client_mode.setter
|
||||
def client_mode(self, mode):
|
||||
"""Set the client mode.
|
||||
|
||||
- 'glances' = Glances server (default)
|
||||
- 'snmp' = SNMP (fallback)
|
||||
"""
|
||||
self.mode = mode
|
||||
return self.mode
|
||||
|
||||
def get_mode(self):
|
||||
"""Get the client mode.
|
||||
|
||||
- 'glances' = Glances server (default)
|
||||
- 'snmp' = SNMP (fallback)
|
||||
"""
|
||||
return self.mode
|
||||
self._client_mode = mode
|
||||
|
||||
def login(self):
|
||||
"""Logon to the server."""
|
||||
@ -112,15 +104,14 @@ class GlancesClient(object):
|
||||
|
||||
if not self.args.snmp_force:
|
||||
# First of all, trying to connect to a Glances server
|
||||
self.set_mode('glances')
|
||||
client_version = None
|
||||
try:
|
||||
client_version = self.client.init()
|
||||
except socket.error as err:
|
||||
# Fallback to SNMP
|
||||
logger.error("Connection to Glances server failed (%s)" % err)
|
||||
self.set_mode('snmp')
|
||||
fallbackmsg = _("Trying fallback to SNMP...")
|
||||
self.client_mode = 'snmp'
|
||||
logger.error("Connection to Glances server failed: {0}".format(err))
|
||||
fallbackmsg = _("No Glances server found. Trying fallback to SNMP...")
|
||||
if not self.return_to_browser:
|
||||
print(fallbackmsg)
|
||||
else:
|
||||
@ -134,22 +125,25 @@ class GlancesClient(object):
|
||||
self.log_and_exit(msg)
|
||||
return False
|
||||
|
||||
if self.get_mode() == 'glances' and version.split('.')[0] == client_version.split('.')[0]:
|
||||
# Init stats
|
||||
self.stats = GlancesStatsClient(config=self.config, args=self.args)
|
||||
self.stats.set_plugins(json.loads(self.client.getAllPlugins()))
|
||||
logger.debug(
|
||||
"Client version: %s / Server version: %s" % (version, client_version))
|
||||
elif self.get_mode() == 'glances':
|
||||
self.log_and_exit("Client and server not compatible: Client version: %s / Server version: %s" % (version, client_version))
|
||||
return False
|
||||
if self.client_mode == 'glances':
|
||||
# Check that both client and server are in the same major version
|
||||
if version.split('.')[0] == client_version.split('.')[0]:
|
||||
# Init stats
|
||||
self.stats = GlancesStatsClient(config=self.config, args=self.args)
|
||||
self.stats.set_plugins(json.loads(self.client.getAllPlugins()))
|
||||
logger.debug("Client version: {0} / Server version: {1}".format(version, client_version))
|
||||
else:
|
||||
self.log_and_exit("Client and server not compatible: \
|
||||
Client version: {0} / Server version: {1}".format(version, client_version))
|
||||
return False
|
||||
|
||||
else:
|
||||
self.set_mode('snmp')
|
||||
self.client_mode = 'snmp'
|
||||
|
||||
if self.get_mode() == 'snmp':
|
||||
# SNMP mode
|
||||
if self.client_mode == 'snmp':
|
||||
logger.info("Trying to grab stats by SNMP...")
|
||||
# Fallback to SNMP if needed
|
||||
|
||||
from glances.core.glances_stats import GlancesStatsClientSNMP
|
||||
|
||||
# Init stats
|
||||
@ -172,13 +166,13 @@ class GlancesClient(object):
|
||||
|
||||
def update(self):
|
||||
"""Update stats from Glances/SNMP server."""
|
||||
if self.get_mode() == 'glances':
|
||||
if self.client_mode == 'glances':
|
||||
return self.update_glances()
|
||||
elif self.get_mode() == 'snmp':
|
||||
elif self.client_mode == 'snmp':
|
||||
return self.update_snmp()
|
||||
else:
|
||||
self.end()
|
||||
logger.critical("Unknown server mode: {0}".format(self.get_mode()))
|
||||
logger.critical("Unknown server mode: {0}".format(self.client_mode))
|
||||
sys.exit(2)
|
||||
|
||||
def update_glances(self):
|
||||
@ -237,7 +231,7 @@ class GlancesClient(object):
|
||||
# Export stats using export modules
|
||||
self.stats.export(self.stats)
|
||||
|
||||
return self.get_mode()
|
||||
return self.client_mode
|
||||
|
||||
def end(self):
|
||||
"""End of the client session."""
|
||||
|
@ -146,42 +146,40 @@ class GlancesClientBrowser(object):
|
||||
"Server list dictionnary change inside the loop (wait next update)")
|
||||
|
||||
# Update the screen (list or Glances client)
|
||||
if self.screen.get_active() is None:
|
||||
if self.screen.active_server is None:
|
||||
# Display the Glances browser
|
||||
self.screen.update(self.get_servers_list())
|
||||
else:
|
||||
# Display the Glances client for the selected server
|
||||
logger.debug("Selected server: %s" % self.get_servers_list()[self.screen.get_active()])
|
||||
logger.debug("Selected server: {0}".format(self.get_servers_list()[self.screen.active_server]))
|
||||
|
||||
# Connection can take time
|
||||
# Display a popup
|
||||
self.screen.display_popup(_("Connect to %s:%s" % (v['name'], v['port'])), duration=1)
|
||||
|
||||
# A password is needed to access to the server's stats
|
||||
if self.get_servers_list()[self.screen.get_active()]['password'] is None:
|
||||
if self.get_servers_list()[self.screen.active_server]['password'] is None:
|
||||
from hashlib import sha256
|
||||
# Display a popup to enter password
|
||||
clear_password = self.screen.display_popup(_("Password needed for %s: " % v['name']), is_input=True)
|
||||
# Hash with SHA256
|
||||
encoded_password = sha256(clear_password).hexdigest()
|
||||
encoded_password = sha256(clear_password.encode('utf-8')).hexdigest()
|
||||
# Store the password for the selected server
|
||||
self.set_in_selected('password', encoded_password)
|
||||
|
||||
# Display the Glance client on the selected server
|
||||
logger.info("Connect Glances client to the %s server" %
|
||||
self.get_servers_list()[self.screen.get_active()]['key'])
|
||||
logger.info("Connect Glances client to the {0} server".format(
|
||||
self.get_servers_list()[self.screen.active_server]['key']))
|
||||
|
||||
# Init the client
|
||||
args_server = self.args
|
||||
|
||||
# Overwrite connection setting
|
||||
args_server.client = self.get_servers_list()[self.screen.get_active()]['ip']
|
||||
args_server.port = self.get_servers_list()[self.screen.get_active()]['port']
|
||||
args_server.username = self.get_servers_list()[self.screen.get_active()]['username']
|
||||
args_server.password = self.get_servers_list()[self.screen.get_active()]['password']
|
||||
client = GlancesClient(config=self.config,
|
||||
args=args_server,
|
||||
return_to_browser=True)
|
||||
args_server.client = self.get_servers_list()[self.screen.active_server]['ip']
|
||||
args_server.port = self.get_servers_list()[self.screen.active_server]['port']
|
||||
args_server.username = self.get_servers_list()[self.screen.active_server]['username']
|
||||
args_server.password = self.get_servers_list()[self.screen.active_server]['password']
|
||||
client = GlancesClient(config=self.config, args=args_server, return_to_browser=True)
|
||||
|
||||
# Test if client and server are in the same major version
|
||||
if not client.login():
|
||||
@ -195,8 +193,8 @@ class GlancesClientBrowser(object):
|
||||
connection_type = client.serve_forever()
|
||||
|
||||
try:
|
||||
logger.debug("Disconnect Glances client from the %s server" %
|
||||
self.get_servers_list()[self.screen.get_active()]['key'])
|
||||
logger.debug("Disconnect Glances client from the {0} server".format(
|
||||
self.get_servers_list()[self.screen.active_server]['key']))
|
||||
except IndexError:
|
||||
# Server did not exist anymore
|
||||
pass
|
||||
@ -208,19 +206,17 @@ class GlancesClientBrowser(object):
|
||||
self.set_in_selected('status', 'ONLINE')
|
||||
|
||||
# Return to the browser (no server selected)
|
||||
self.screen.set_active(None)
|
||||
self.screen.active_server = None
|
||||
|
||||
def set_in_selected(self, key, value):
|
||||
"""Set the (key, value) for the selected server in the list"""
|
||||
"""Set the (key, value) for the selected server in the list."""
|
||||
# Static list then dynamic one
|
||||
if self.screen.get_active() >= len(self.static_server.get_servers_list()):
|
||||
self.autodiscover_server.set_server(self.screen.get_active() - len(self.static_server.get_servers_list()),
|
||||
key,
|
||||
value)
|
||||
if self.screen.active_server >= len(self.static_server.get_servers_list()):
|
||||
self.autodiscover_server.set_server(
|
||||
self.screen.active_server - len(self.static_server.get_servers_list()),
|
||||
key, value)
|
||||
else:
|
||||
self.static_server.set_server(self.screen.get_active(),
|
||||
key,
|
||||
value)
|
||||
self.static_server.set_server(self.screen.active_server, key, value)
|
||||
|
||||
def end(self):
|
||||
"""End of the client browser session."""
|
||||
|
@ -17,10 +17,15 @@
|
||||
# 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/>.
|
||||
|
||||
"""Custom logging class"""
|
||||
"""Custom logging class."""
|
||||
|
||||
import logging
|
||||
import logging.config
|
||||
try:
|
||||
# Python 2.6
|
||||
from logutils.dictconfig import dictConfig
|
||||
except ImportError:
|
||||
# Python >= 2.7
|
||||
from logging.config import dictConfig
|
||||
import os
|
||||
import tempfile
|
||||
|
||||
@ -72,29 +77,24 @@ LOGGING_CFG = {
|
||||
|
||||
|
||||
def tempfile_name():
|
||||
"""Return the tempfile name (full path)"""
|
||||
"""Return the tempfile name (full path)."""
|
||||
ret = os.path.join(tempfile.gettempdir(), 'glances.log')
|
||||
if os.access(ret, os.F_OK) and not os.access(ret, os.W_OK):
|
||||
print("Warning: can't write logs to file {} (permission denied)".format(ret))
|
||||
print("WARNING: Couldn't write to log file {0}: (Permission denied)".format(ret))
|
||||
ret = tempfile.mkstemp(prefix='glances', suffix='.tmp', text=True)
|
||||
print("Create a new log file: {}".format(ret[1]))
|
||||
print("Create a new log file: {0}".format(ret[1]))
|
||||
return ret[1]
|
||||
|
||||
return ret
|
||||
|
||||
|
||||
def glances_logger():
|
||||
"""Build and return the logger"""
|
||||
"""Build and return the logger."""
|
||||
temp_path = tempfile_name()
|
||||
_logger = logging.getLogger()
|
||||
try:
|
||||
LOGGING_CFG['handlers']['file']['filename'] = temp_path
|
||||
logging.config.dictConfig(LOGGING_CFG)
|
||||
except AttributeError:
|
||||
# dictConfig is only available for Python 2.7 or higher
|
||||
# Minimal configuration for Python 2.6
|
||||
logging.basicConfig(filename=temp_path,
|
||||
level=logging.DEBUG,
|
||||
format='%(asctime)s -- %(levelname)s -- %(message)s')
|
||||
LOGGING_CFG['handlers']['file']['filename'] = temp_path
|
||||
dictConfig(LOGGING_CFG)
|
||||
|
||||
return _logger
|
||||
|
||||
logger = glances_logger()
|
||||
|
@ -87,22 +87,17 @@ class GlancesLogs(object):
|
||||
else:
|
||||
# Default sort is...
|
||||
process_auto_by = 'cpu_percent'
|
||||
glances_processes.setautosortkey(process_auto_by)
|
||||
|
||||
return process_auto_by
|
||||
glances_processes.auto_sort = True
|
||||
glances_processes.sort_key = process_auto_by
|
||||
|
||||
def reset_process_sort(self):
|
||||
"""Reset the process_auto_by variable."""
|
||||
"""Reset the process auto sort key."""
|
||||
# Default sort is...
|
||||
process_auto_by = 'cpu_percent'
|
||||
glances_processes.setautosortkey(process_auto_by)
|
||||
glances_processes.setmanualsortkey(None)
|
||||
|
||||
return process_auto_by
|
||||
glances_processes.auto_sort = True
|
||||
glances_processes.sort_key = 'cpu_percent'
|
||||
|
||||
def add(self, item_state, item_type, item_value,
|
||||
proc_list=[], proc_desc="",
|
||||
peak_time=3):
|
||||
proc_list=None, proc_desc="", peak_time=6):
|
||||
"""Add a new item to the logs list.
|
||||
|
||||
If 'item' is a 'new one', add the new item at the beginning of the logs
|
||||
@ -110,6 +105,8 @@ class GlancesLogs(object):
|
||||
If 'item' is not a 'new one', update the existing item.
|
||||
If event < peak_time the the alert is not setoff
|
||||
"""
|
||||
proc_list = proc_list or []
|
||||
|
||||
# Add or update the log
|
||||
item_index = self.__itemexist__(item_type)
|
||||
if item_index < 0:
|
||||
@ -121,24 +118,23 @@ class GlancesLogs(object):
|
||||
# Create the new log item
|
||||
# Time is stored in Epoch format
|
||||
# Epoch -> DMYHMS = datetime.fromtimestamp(epoch)
|
||||
item = []
|
||||
# START DATE
|
||||
item.append(time.mktime(datetime.now().timetuple()))
|
||||
item.append(-1) # END DATE
|
||||
item.append(item_state) # STATE: WARNING|CRITICAL
|
||||
item.append(item_type) # TYPE: CPU, LOAD, MEM...
|
||||
item.append(item_value) # MAX
|
||||
item.append(item_value) # AVG
|
||||
item.append(item_value) # MIN
|
||||
item.append(item_value) # SUM
|
||||
item.append(1) # COUNT
|
||||
# Process list is sorted automaticaly
|
||||
# Overwrite the user choise
|
||||
# topprocess = sorted(proc_list, key=lambda process: process[process_auto_by],
|
||||
# reverse=True)
|
||||
# item.append(topprocess[0:3]) # TOP 3 PROCESS LIST
|
||||
item.append([]) # TOP 3 PROCESS LIST
|
||||
item.append(proc_desc) # MONITORED PROCESSES DESC
|
||||
item = [
|
||||
time.mktime(datetime.now().timetuple()), # START DATE
|
||||
-1, # END DATE
|
||||
item_state, # STATE: WARNING|CRITICAL
|
||||
item_type, # TYPE: CPU, LOAD, MEM...
|
||||
item_value, # MAX
|
||||
item_value, # AVG
|
||||
item_value, # MIN
|
||||
item_value, # SUM
|
||||
1, # COUNT
|
||||
# Process list is sorted automatically
|
||||
# Overwrite the user choice
|
||||
# topprocess = sorted(proc_list, key=lambda process: process[process_auto_by],
|
||||
# reverse=True)
|
||||
# topprocess[0:3], # TOP 3 PROCESS LIST
|
||||
[], # TOP 3 PROCESS LIST
|
||||
proc_desc] # MONITORED PROCESSES DESC
|
||||
|
||||
# Add the item to the list
|
||||
self.logs_list.insert(0, item)
|
||||
|
@ -110,6 +110,8 @@ Start the client browser (browser mode):\n\
|
||||
dest='disable_fs', help=_('disable filesystem module'))
|
||||
parser.add_argument('--disable-sensors', action='store_true', default=False,
|
||||
dest='disable_sensors', help=_('disable sensors module'))
|
||||
parser.add_argument('--disable-hddtemp', action='store_true', default=False,
|
||||
dest='disable_hddtemp', help=_('disable HD Temperature module'))
|
||||
parser.add_argument('--disable-raid', action='store_true', default=False,
|
||||
dest='disable_raid', help=_('disable RAID module'))
|
||||
parser.add_argument('--disable-docker', action='store_true', default=False,
|
||||
@ -171,6 +173,8 @@ Start the client browser (browser mode):\n\
|
||||
parser.add_argument('-w', '--webserver', action='store_true', default=False,
|
||||
dest='webserver', help=_('run Glances in web server mode (need Bootle lib)'))
|
||||
# Display options
|
||||
parser.add_argument('-q', '--quiet', default=False, action='store_true',
|
||||
dest='quiet', help=_('Do not display the Curse interface'))
|
||||
parser.add_argument('-f', '--process-filter', default=None, type=str,
|
||||
dest='process_filter', help=_('set the process filter pattern (regular expression)'))
|
||||
parser.add_argument('--process-short-name', action='store_true', default=False,
|
||||
@ -187,7 +191,7 @@ Start the client browser (browser mode):\n\
|
||||
parser.add_argument('--fs-free-space', action='store_false', default=False,
|
||||
dest='fs_free_space', help=_('display FS free space instead of used'))
|
||||
parser.add_argument('--theme-white', action='store_true', default=False,
|
||||
dest='theme_white', help=_('optimize display for white background'))
|
||||
dest='theme_white', help=_('optimize display colors for white background'))
|
||||
|
||||
return parser
|
||||
|
||||
@ -264,6 +268,11 @@ Start the client browser (browser mode):\n\
|
||||
sys.exit(2)
|
||||
logger.debug("History output path is set to {0}".format(args.path_history))
|
||||
|
||||
# Disable HDDTemp if sensors are disabled
|
||||
if args.disable_sensors:
|
||||
args.disable_hddtemp = True
|
||||
logger.debug("Sensors and HDDTemp are disabled")
|
||||
|
||||
return args
|
||||
|
||||
def __hash_password(self, plain_password):
|
||||
|
@ -74,7 +74,6 @@ class MonitorList(object):
|
||||
countmax = self.config.get_raw_option(section, key + "countmax")
|
||||
except Exception as e:
|
||||
logger.error("Cannot read monitored list: {0}".format(e))
|
||||
pass
|
||||
else:
|
||||
if description is not None and regex is not None:
|
||||
# Build the new item
|
||||
|
@ -250,11 +250,11 @@ class GlancesProcesses(object):
|
||||
self.process_tree = None
|
||||
|
||||
# Init stats
|
||||
self.resetsort()
|
||||
self.auto_sort = True
|
||||
self._sort_key = 'cpu_percent'
|
||||
self.allprocesslist = []
|
||||
self.processlist = []
|
||||
self.processcount = {
|
||||
'total': 0, 'running': 0, 'sleeping': 0, 'thread': 0}
|
||||
self.processcount = {'total': 0, 'running': 0, 'sleeping': 0, 'thread': 0}
|
||||
|
||||
# Tag to enable/disable the processes stats (to reduce the Glances CPU consumption)
|
||||
# Default is to enable the processes stats
|
||||
@ -263,13 +263,12 @@ class GlancesProcesses(object):
|
||||
# Extended stats for top process is enable by default
|
||||
self.disable_extended_tag = False
|
||||
|
||||
# Maximum number of processes showed in the UI interface
|
||||
# None if no limit
|
||||
self.max_processes = None
|
||||
# Maximum number of processes showed in the UI (None if no limit)
|
||||
self._max_processes = None
|
||||
|
||||
# Process filter is a regular expression
|
||||
self.process_filter = None
|
||||
self.process_filter_re = None
|
||||
self._process_filter = None
|
||||
self._process_filter_re = None
|
||||
|
||||
# Whether or not to hide kernel threads
|
||||
self.no_kernel_threads = False
|
||||
@ -292,48 +291,49 @@ class GlancesProcesses(object):
|
||||
"""Disable extended process stats."""
|
||||
self.disable_extended_tag = True
|
||||
|
||||
def set_max_processes(self, value):
|
||||
"""Set the maximum number of processes showed in the UI interfaces"""
|
||||
self.max_processes = value
|
||||
return self.max_processes
|
||||
@property
|
||||
def max_processes(self):
|
||||
"""Get the maximum number of processes showed in the UI."""
|
||||
return self._max_processes
|
||||
|
||||
def get_max_processes(self):
|
||||
"""Get the maximum number of processes showed in the UI interfaces"""
|
||||
return self.max_processes
|
||||
@max_processes.setter
|
||||
def max_processes(self, value):
|
||||
"""Set the maximum number of processes showed in the UI."""
|
||||
self._max_processes = value
|
||||
|
||||
def set_process_filter(self, value):
|
||||
"""Set the process filter"""
|
||||
@property
|
||||
def process_filter(self):
|
||||
"""Get the process filter."""
|
||||
return self._process_filter
|
||||
|
||||
@process_filter.setter
|
||||
def process_filter(self, value):
|
||||
"""Set the process filter."""
|
||||
logger.info("Set process filter to {0}".format(value))
|
||||
self.process_filter = value
|
||||
self._process_filter = value
|
||||
if value is not None:
|
||||
try:
|
||||
self.process_filter_re = re.compile(value)
|
||||
logger.debug(
|
||||
"Process filter regex compilation OK: {0}".format(self.get_process_filter()))
|
||||
self._process_filter_re = re.compile(value)
|
||||
logger.debug("Process filter regex compilation OK: {0}".format(self.process_filter))
|
||||
except Exception:
|
||||
logger.error(
|
||||
"Cannot compile process filter regex: {0}".format(value))
|
||||
self.process_filter_re = None
|
||||
logger.error("Cannot compile process filter regex: {0}".format(value))
|
||||
self._process_filter_re = None
|
||||
else:
|
||||
self.process_filter_re = None
|
||||
return self.process_filter
|
||||
self._process_filter_re = None
|
||||
|
||||
def get_process_filter(self):
|
||||
"""Get the process filter"""
|
||||
return self.process_filter
|
||||
|
||||
def get_process_filter_re(self):
|
||||
"""Get the process regular expression compiled"""
|
||||
return self.process_filter_re
|
||||
@property
|
||||
def process_filter_re(self):
|
||||
"""Get the process regular expression compiled."""
|
||||
return self._process_filter_re
|
||||
|
||||
def is_filtered(self, value):
|
||||
"""Return True if the value should be filtered"""
|
||||
if self.get_process_filter() is None:
|
||||
if self.process_filter is None:
|
||||
# No filter => Not filtered
|
||||
return False
|
||||
else:
|
||||
# logger.debug(self.get_process_filter() + " <> " + value + " => " + str(self.get_process_filter_re().match(value) is None))
|
||||
return self.get_process_filter_re().match(value) is None
|
||||
# logger.debug(self.process_filter + " <> " + value + " => " + str(self.process_filter_re.match(value) is None))
|
||||
return self.process_filter_re.match(value) is None
|
||||
|
||||
def disable_kernel_threads(self):
|
||||
""" Ignore kernel threads in process list. """
|
||||
@ -541,8 +541,7 @@ class GlancesProcesses(object):
|
||||
"""
|
||||
# Reset the stats
|
||||
self.processlist = []
|
||||
self.processcount = {
|
||||
'total': 0, 'running': 0, 'sleeping': 0, 'thread': 0}
|
||||
self.processcount = {'total': 0, 'running': 0, 'sleeping': 0, 'thread': 0}
|
||||
|
||||
# Do not process if disable tag is set
|
||||
if self.disable_tag:
|
||||
@ -558,11 +557,11 @@ class GlancesProcesses(object):
|
||||
if self.no_kernel_threads and not is_windows and is_kernel_thread(proc):
|
||||
continue
|
||||
|
||||
# If self.get_max_processes() is None: Only retreive mandatory stats
|
||||
# If self.max_processes is None: Only retreive mandatory stats
|
||||
# Else: retreive mandatory and standard stats
|
||||
s = self.__get_process_stats(proc,
|
||||
mandatory_stats=True,
|
||||
standard_stats=self.get_max_processes() is None)
|
||||
standard_stats=self.max_processes is None)
|
||||
# Continue to the next process if it has to be filtered
|
||||
if s is None or (self.is_filtered(s['cmdline']) and self.is_filtered(s['name'])):
|
||||
continue
|
||||
@ -571,8 +570,10 @@ class GlancesProcesses(object):
|
||||
# ignore the 'idle' process on Windows and *BSD
|
||||
# ignore the 'kernel_task' process on OS X
|
||||
# waiting for upstream patch from psutil
|
||||
if is_bsd and processdict[proc]['name'] == 'idle' or is_windows and processdict[proc]['name'] == 'System Idle Process' or is_mac and processdict[proc]['name'] == 'kernel_task':
|
||||
continue
|
||||
if (is_bsd and processdict[proc]['name'] == 'idle' or
|
||||
is_windows and processdict[proc]['name'] == 'System Idle Process' or
|
||||
is_mac and processdict[proc]['name'] == 'kernel_task'):
|
||||
continue
|
||||
# Update processcount (global statistics)
|
||||
try:
|
||||
self.processcount[str(proc.status())] += 1
|
||||
@ -594,12 +595,12 @@ class GlancesProcesses(object):
|
||||
|
||||
if self._enable_tree:
|
||||
self.process_tree = ProcessTreeNode.build_tree(processdict,
|
||||
self.getsortkey(),
|
||||
self.sort_key,
|
||||
self.no_kernel_threads)
|
||||
|
||||
for i, node in enumerate(self.process_tree):
|
||||
# Only retreive stats for visible processes (get_max_processes)
|
||||
if self.get_max_processes() is not None and i >= self.get_max_processes():
|
||||
# Only retreive stats for visible processes (max_processes)
|
||||
if self.max_processes is not None and i >= self.max_processes:
|
||||
break
|
||||
|
||||
# add standard stats
|
||||
@ -615,22 +616,21 @@ class GlancesProcesses(object):
|
||||
|
||||
else:
|
||||
# Process optimization
|
||||
# Only retreive stats for visible processes (get_max_processes)
|
||||
if self.get_max_processes() is not None:
|
||||
# Only retreive stats for visible processes (max_processes)
|
||||
if self.max_processes is not None:
|
||||
# Sort the internal dict and cut the top N (Return a list of tuple)
|
||||
# tuple=key (proc), dict (returned by __get_process_stats)
|
||||
try:
|
||||
processiter = sorted(
|
||||
processdict.items(), key=lambda x: x[1][self.getsortkey()], reverse=True)
|
||||
processdict.items(), key=lambda x: x[1][self.sort_key], reverse=True)
|
||||
except (KeyError, TypeError) as e:
|
||||
logger.error(
|
||||
"Cannot sort process list by %s (%s)" % (self.getsortkey(), e))
|
||||
logger.error("Cannot sort process list by {0}: {1}".format(self.sort_key, e))
|
||||
logger.error("%s" % str(processdict.items()[0]))
|
||||
# Fallback to all process (issue #423)
|
||||
processloop = processdict.items()
|
||||
first = False
|
||||
else:
|
||||
processloop = processiter[0:self.get_max_processes()]
|
||||
processloop = processiter[0:self.max_processes]
|
||||
first = True
|
||||
else:
|
||||
# Get all processes stats
|
||||
@ -640,7 +640,7 @@ class GlancesProcesses(object):
|
||||
for i in processloop:
|
||||
# Already existing mandatory stats
|
||||
procstat = i[1]
|
||||
if self.get_max_processes() is not None:
|
||||
if self.max_processes is not None:
|
||||
# Update with standard stats
|
||||
# and extended stats but only for TOP (first) process
|
||||
s = self.__get_process_stats(i[0],
|
||||
@ -687,37 +687,17 @@ class GlancesProcesses(object):
|
||||
"""Get the process tree."""
|
||||
return self.process_tree
|
||||
|
||||
def getsortkey(self):
|
||||
"""Get the current sort key"""
|
||||
if self.getmanualsortkey() is not None:
|
||||
return self.getmanualsortkey()
|
||||
else:
|
||||
return self.getautosortkey()
|
||||
@property
|
||||
def sort_key(self):
|
||||
"""Get the current sort key."""
|
||||
return self._sort_key
|
||||
|
||||
def getmanualsortkey(self):
|
||||
"""Get the current sort key for manual sort."""
|
||||
return self.processmanualsort
|
||||
|
||||
def getautosortkey(self):
|
||||
"""Get the current sort key for automatic sort."""
|
||||
return self.processautosort
|
||||
|
||||
def setmanualsortkey(self, sortedby):
|
||||
"""Set the current sort key for manual sort."""
|
||||
self.processmanualsort = sortedby
|
||||
if self._enable_tree and (self.process_tree is not None):
|
||||
self.process_tree.set_sorting(sortedby, sortedby != "name")
|
||||
return self.processmanualsort
|
||||
|
||||
def setautosortkey(self, sortedby):
|
||||
"""Set the current sort key for automatic sort."""
|
||||
self.processautosort = sortedby
|
||||
return self.processautosort
|
||||
|
||||
def resetsort(self):
|
||||
"""Set the default sort: Auto"""
|
||||
self.setmanualsortkey(None)
|
||||
self.setautosortkey('cpu_percent')
|
||||
@sort_key.setter
|
||||
def sort_key(self, key):
|
||||
"""Set the current sort key."""
|
||||
self._sort_key = key
|
||||
if not self.auto_sort and self._enable_tree and self.process_tree is not None:
|
||||
self.process_tree.set_sorting(key, key != "name")
|
||||
|
||||
def getsortlist(self, sortedby=None):
|
||||
"""Get the sorted processlist."""
|
||||
|
@ -100,7 +100,7 @@ class GlancesXMLRPCHandler(SimpleXMLRPCRequestHandler):
|
||||
self.send_error(401, 'Authentication failed')
|
||||
return False
|
||||
|
||||
def log_message(self, format, *args):
|
||||
def log_message(self, log_format, *args):
|
||||
# No message displayed on the server side
|
||||
pass
|
||||
|
||||
|
@ -32,12 +32,12 @@ class GlancesStandalone(object):
|
||||
"""This class creates and manages the Glances standalone session."""
|
||||
|
||||
def __init__(self, config=None, args=None):
|
||||
# Quiet mode
|
||||
self._quiet = args.quiet
|
||||
|
||||
# Init stats
|
||||
self.stats = GlancesStats(config=config, args=args)
|
||||
|
||||
# Default number of processes to displayed is set to 50
|
||||
glances_processes.set_max_processes(50)
|
||||
|
||||
# If process extended stats is disabled by user
|
||||
if not args.enable_process_extended:
|
||||
logger.debug("Extended stats for top process are disabled")
|
||||
@ -48,7 +48,7 @@ class GlancesStandalone(object):
|
||||
|
||||
# Manage optionnal process filter
|
||||
if args.process_filter is not None:
|
||||
glances_processes.set_process_filter(args.process_filter)
|
||||
glances_processes.process_filter = args.process_filter
|
||||
|
||||
if (not is_windows) and args.no_kernel_threads:
|
||||
# Ignore kernel threads in process list
|
||||
@ -61,8 +61,20 @@ class GlancesStandalone(object):
|
||||
# Initial system informations update
|
||||
self.stats.update()
|
||||
|
||||
# Init screen
|
||||
self.screen = GlancesCursesStandalone(args=args)
|
||||
if self.quiet:
|
||||
logger.info("Quiet mode is ON: Nothing will be displayed")
|
||||
# In quiet mode, nothing is displayed
|
||||
glances_processes.max_processes = 0
|
||||
else:
|
||||
# Default number of processes to displayed is set to 50
|
||||
glances_processes.max_processes = 50
|
||||
|
||||
# Init screen
|
||||
self.screen = GlancesCursesStandalone(args=args)
|
||||
|
||||
@property
|
||||
def quiet(self):
|
||||
return self._quiet
|
||||
|
||||
def serve_forever(self):
|
||||
"""Main loop for the CLI."""
|
||||
@ -71,14 +83,16 @@ class GlancesStandalone(object):
|
||||
self.stats.update()
|
||||
|
||||
# Update the screen
|
||||
self.screen.update(self.stats)
|
||||
if not self.quiet:
|
||||
self.screen.update(self.stats)
|
||||
|
||||
# Export stats using export modules
|
||||
self.stats.export(self.stats)
|
||||
|
||||
def end(self):
|
||||
"""End of the standalone CLI."""
|
||||
self.screen.end()
|
||||
if not self.quiet:
|
||||
self.screen.end()
|
||||
|
||||
# Exit from export modules
|
||||
self.stats.end()
|
||||
|
@ -155,10 +155,12 @@ class GlancesStats(object):
|
||||
# logger.debug("Update %s stats" % p)
|
||||
self._plugins[p].update()
|
||||
|
||||
def export(self, input_stats={}):
|
||||
def export(self, input_stats=None):
|
||||
"""Export all the stats.
|
||||
Each export module is ran in a dedicated thread."""
|
||||
# threads = []
|
||||
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,
|
||||
@ -181,13 +183,13 @@ class GlancesStats(object):
|
||||
|
||||
def getAllLimits(self):
|
||||
"""Return the plugins limits list."""
|
||||
return [self._plugins[p].get_limits() for p in self._plugins]
|
||||
return [self._plugins[p].limits for p in self._plugins]
|
||||
|
||||
def getAllLimitsAsDict(self):
|
||||
"""Return all the stats limits (dict)"""
|
||||
ret = {}
|
||||
for p in self._plugins:
|
||||
ret[p] = self._plugins[p].get_limits()
|
||||
ret[p] = self._plugins[p].limits
|
||||
return ret
|
||||
|
||||
def getAllViews(self):
|
||||
@ -203,7 +205,7 @@ class GlancesStats(object):
|
||||
|
||||
def get_plugin_list(self):
|
||||
"""Return the plugin list."""
|
||||
self._plugins
|
||||
return self._plugins
|
||||
|
||||
def get_plugin(self, plugin_name):
|
||||
"""Return the plugin name."""
|
||||
@ -231,8 +233,10 @@ class GlancesStatsServer(GlancesStats):
|
||||
# all_stats is a dict of dicts filled by the server
|
||||
self.all_stats = collections.defaultdict(dict)
|
||||
|
||||
def update(self, input_stats={}):
|
||||
def update(self, input_stats=None):
|
||||
"""Update the stats."""
|
||||
input_stats = input_stats or {}
|
||||
|
||||
# Force update of all the stats
|
||||
GlancesStats.update(self)
|
||||
|
||||
@ -383,7 +387,8 @@ class GlancesStatsClientSNMP(GlancesStats):
|
||||
# For each plugins, call the update method
|
||||
for p in self._plugins:
|
||||
# Set the input method to SNMP
|
||||
self._plugins[p].set_input('snmp', self.system_name)
|
||||
self._plugins[p].input_method = 'snmp'
|
||||
self._plugins[p].short_system_name = self.system_name
|
||||
try:
|
||||
self._plugins[p].update()
|
||||
except Exception as e:
|
||||
|
@ -58,8 +58,10 @@ class GlancesExport(object):
|
||||
|
||||
def update(self, stats):
|
||||
"""Update stats to a server.
|
||||
The method buil two list: names and values
|
||||
and call the export method to export the stats"""
|
||||
|
||||
The method builds two lists: names and values
|
||||
and calls the export method to export the stats.
|
||||
"""
|
||||
if not self.export_enable:
|
||||
return False
|
||||
|
||||
@ -67,20 +69,17 @@ class GlancesExport(object):
|
||||
all_stats = stats.getAll()
|
||||
plugins = stats.getAllPlugins()
|
||||
|
||||
# Loop over available plugin
|
||||
i = 0
|
||||
for plugin in plugins:
|
||||
# Loop over available plugins
|
||||
for i, plugin in enumerate(plugins):
|
||||
if plugin in self.plugins_to_export():
|
||||
if type(all_stats[i]) is list:
|
||||
for item in all_stats[i]:
|
||||
export_names = map(
|
||||
lambda x: item[item['key']] + '.' + x, item.keys())
|
||||
export_values = item.values()
|
||||
export_names = list(map(lambda x: item[item['key']] + '.' + x, item.keys()))
|
||||
export_values = list(item.values())
|
||||
self.export(plugin, export_names, export_values)
|
||||
elif type(all_stats[i]) is dict:
|
||||
export_names = all_stats[i].keys()
|
||||
export_values = all_stats[i].values()
|
||||
export_names = list(all_stats[i].keys())
|
||||
export_values = list(all_stats[i].values())
|
||||
self.export(plugin, export_names, export_values)
|
||||
i += 1
|
||||
|
||||
return True
|
||||
|
@ -176,8 +176,7 @@ class GlancesHistory(object):
|
||||
fig.set_size_inches(20, 10)
|
||||
plt.legend(handles, labels, loc=1, prop={'size': 9})
|
||||
plt.xlabel('Date')
|
||||
plt.savefig(
|
||||
os.path.join(self.output_folder, 'glances_%s.png' % (p)), dpi=72)
|
||||
plt.savefig(os.path.join(self.output_folder, 'glances_%s.png' % p), dpi=72)
|
||||
index_all += 1
|
||||
|
||||
plt.close()
|
||||
|
@ -20,14 +20,19 @@
|
||||
"""InfluxDB interface class."""
|
||||
|
||||
# Import sys libs
|
||||
from influxdb import InfluxDBClient, client
|
||||
import sys
|
||||
try:
|
||||
from configparser import NoOptionError, NoSectionError
|
||||
except ImportError: # Python 2
|
||||
from ConfigParser import NoOptionError, NoSectionError
|
||||
|
||||
# Import Glances lib
|
||||
from glances.core.glances_logging import logger
|
||||
from ConfigParser import NoSectionError, NoOptionError
|
||||
from glances.exports.glances_export import GlancesExport
|
||||
|
||||
from influxdb import InfluxDBClient, client
|
||||
from influxdb.influxdb08 import InfluxDBClient as InfluxDBClient_Legacy
|
||||
|
||||
|
||||
class Export(GlancesExport):
|
||||
|
||||
@ -38,11 +43,12 @@ class Export(GlancesExport):
|
||||
GlancesExport.__init__(self, config=config, args=args)
|
||||
|
||||
# Load the InfluxDB configuration file
|
||||
self.influxdb_host = None
|
||||
self.influxdb_port = None
|
||||
self.influxdb_user = None
|
||||
self.influxdb_password = None
|
||||
self.influxdb_db = None
|
||||
self.host = None
|
||||
self.port = None
|
||||
self.user = None
|
||||
self.password = None
|
||||
self.db = None
|
||||
self.prefix = None
|
||||
self.export_enable = self.load_conf()
|
||||
if not self.export_enable:
|
||||
sys.exit(2)
|
||||
@ -55,11 +61,11 @@ class Export(GlancesExport):
|
||||
if self.config is None:
|
||||
return False
|
||||
try:
|
||||
self.influxdb_host = self.config.get_raw_option(section, "host")
|
||||
self.influxdb_port = self.config.get_raw_option(section, "port")
|
||||
self.influxdb_user = self.config.get_raw_option(section, "user")
|
||||
self.influxdb_password = self.config.get_raw_option(section, "password")
|
||||
self.influxdb_db = self.config.get_raw_option(section, "db")
|
||||
self.host = self.config.get_raw_option(section, "host")
|
||||
self.port = self.config.get_raw_option(section, "port")
|
||||
self.user = self.config.get_raw_option(section, "user")
|
||||
self.password = self.config.get_raw_option(section, "password")
|
||||
self.db = self.config.get_raw_option(section, "db")
|
||||
except NoSectionError:
|
||||
logger.critical("No InfluxDB configuration found")
|
||||
return False
|
||||
@ -68,39 +74,61 @@ class Export(GlancesExport):
|
||||
return False
|
||||
else:
|
||||
logger.debug("Load InfluxDB from the Glances configuration file")
|
||||
# Prefix is optional
|
||||
try:
|
||||
self.prefix = self.config.get_raw_option(section, "prefix")
|
||||
except NoOptionError as e:
|
||||
pass
|
||||
return True
|
||||
|
||||
def init(self):
|
||||
"""Init the connection to the InfluxDB server"""
|
||||
if not self.export_enable:
|
||||
return None
|
||||
db = InfluxDBClient(self.influxdb_host,
|
||||
self.influxdb_port,
|
||||
self.influxdb_user,
|
||||
self.influxdb_password,
|
||||
self.influxdb_db)
|
||||
try:
|
||||
get_all_db = db.get_database_list()[0].values()
|
||||
except client.InfluxDBClientError as e:
|
||||
logger.critical("Can not connect to InfluxDB database '%s' (%s)" % (self.influxdb_db, e))
|
||||
sys.exit(2)
|
||||
|
||||
if self.influxdb_db in get_all_db:
|
||||
try:
|
||||
db = InfluxDBClient(host=self.host,
|
||||
port=self.port,
|
||||
username=self.user,
|
||||
password=self.password,
|
||||
database=self.db)
|
||||
get_all_db = [i['name'] for i in db.get_list_database()]
|
||||
except client.InfluxDBClientError as e:
|
||||
try:
|
||||
# https://github.com/influxdb/influxdb-python/issues/138
|
||||
logger.info("Trying fallback to InfluxDB v0.8")
|
||||
db = InfluxDBClient_Legacy(host=self.host,
|
||||
port=self.port,
|
||||
username=self.user,
|
||||
password=self.password,
|
||||
database=self.db)
|
||||
get_all_db = [i['name'] for i in db.get_list_database()]
|
||||
except:
|
||||
logger.critical("Can not connect to InfluxDB database '%s' (%s)" % (self.db, e))
|
||||
sys.exit(2)
|
||||
|
||||
if self.db in get_all_db:
|
||||
logger.info(
|
||||
"Stats will be exported to InfluxDB server: {0}".format(db._baseurl))
|
||||
else:
|
||||
logger.critical("InfluxDB database '%s' did not exist. Please create it" % self.influxdb_db)
|
||||
logger.critical("InfluxDB database '%s' did not exist. Please create it" % self.db)
|
||||
sys.exit(2)
|
||||
return db
|
||||
|
||||
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
|
||||
# logger.info(self.prefix)
|
||||
# Create DB input
|
||||
data = [
|
||||
{
|
||||
"name": name,
|
||||
"columns": columns,
|
||||
"points": [points]
|
||||
}]
|
||||
# Write input to the InfluxDB database
|
||||
try:
|
||||
self.client.write_points(data)
|
||||
except Exception as e:
|
||||
|
@ -20,15 +20,19 @@
|
||||
"""Statsd interface class."""
|
||||
|
||||
# Import sys libs
|
||||
from statsd import StatsClient
|
||||
from numbers import Number
|
||||
import sys
|
||||
from numbers import Number
|
||||
try:
|
||||
from configparser import NoOptionError, NoSectionError
|
||||
except ImportError: # Python 2
|
||||
from ConfigParser import NoOptionError, NoSectionError
|
||||
|
||||
# Import Glances lib
|
||||
from glances.core.glances_logging import logger
|
||||
from ConfigParser import NoSectionError, NoOptionError
|
||||
from glances.exports.glances_export import GlancesExport
|
||||
|
||||
from statsd import StatsClient
|
||||
|
||||
|
||||
class Export(GlancesExport):
|
||||
|
||||
|
@ -33,7 +33,7 @@ class Bar(object):
|
||||
import time
|
||||
b = Bar(10)
|
||||
for p in range(0, 100):
|
||||
b.set_percent(p)
|
||||
b.percent = p
|
||||
print("\r%s" % b),
|
||||
time.sleep(0.1)
|
||||
sys.stdout.flush()
|
||||
@ -43,7 +43,8 @@ class Bar(object):
|
||||
def __init__(self, size,
|
||||
pre_char='[',
|
||||
post_char=']',
|
||||
empty_char='_'):
|
||||
empty_char='_',
|
||||
with_text=True):
|
||||
# Bar size
|
||||
self.__size = size
|
||||
# Bar current percent
|
||||
@ -52,29 +53,38 @@ class Bar(object):
|
||||
self.__pre_char = pre_char
|
||||
self.__post_char = post_char
|
||||
self.__empty_char = empty_char
|
||||
self.__with_text = with_text
|
||||
|
||||
def get_size(self):
|
||||
return self.__size
|
||||
@property
|
||||
def size(self, with_decoration=False):
|
||||
# Return the bar size, with or without decoration
|
||||
if with_decoration:
|
||||
return self.__size
|
||||
if self.__with_text:
|
||||
return self.__size - 6
|
||||
|
||||
def set_size(self, size):
|
||||
self.__size = size
|
||||
return self.__size
|
||||
# @size.setter
|
||||
# def size(self, value):
|
||||
# self.__size = value
|
||||
|
||||
def get_percent(self):
|
||||
@property
|
||||
def percent(self):
|
||||
return self.__percent
|
||||
|
||||
def set_percent(self, percent):
|
||||
assert percent >= 0
|
||||
assert percent <= 100
|
||||
self.__percent = percent
|
||||
return self.__percent
|
||||
@percent.setter
|
||||
def percent(self, value):
|
||||
assert value >= 0
|
||||
assert value <= 100
|
||||
self.__percent = value
|
||||
|
||||
def __str__(self):
|
||||
"""Return the bars"""
|
||||
frac, whole = modf(self.get_size() * self.get_percent() / 100.0)
|
||||
"""Return the bars."""
|
||||
frac, whole = modf(self.size * self.percent / 100.0)
|
||||
ret = curses_bars[8] * int(whole)
|
||||
if frac > 0:
|
||||
ret += curses_bars[int(frac * 8)]
|
||||
whole += 1
|
||||
ret += self.__empty_char * int(self.get_size() - whole)
|
||||
ret += self.__empty_char * int(self.size - whole)
|
||||
if self.__with_text:
|
||||
ret = '{0}{1:>5}%'.format(ret, self.percent)
|
||||
return self.__pre_char + ret + self.__post_char
|
||||
|
@ -279,7 +279,7 @@ class GlancesBottle(object):
|
||||
|
||||
try:
|
||||
# Get the JSON value of the stat limits
|
||||
ret = self.stats.get_plugin(plugin).get_limits()
|
||||
ret = self.stats.get_plugin(plugin).limits
|
||||
except Exception as e:
|
||||
abort(404, "Cannot get limits for plugin %s (%s)" % (plugin, str(e)))
|
||||
return ret
|
||||
|
@ -80,10 +80,10 @@ class Screen(object):
|
||||
def subwin(self, x, y):
|
||||
return self
|
||||
|
||||
def keypad(self, id):
|
||||
def keypad(self, screen_id):
|
||||
return None
|
||||
|
||||
def nodelay(self, id):
|
||||
def nodelay(self, screen_id):
|
||||
return None
|
||||
|
||||
def getch(self):
|
||||
@ -170,8 +170,8 @@ class WCurseLight(object):
|
||||
def napms(self, t):
|
||||
time.sleep(t / 1000 if t > 1000 else 1)
|
||||
|
||||
def init_pair(self, id, fg, bk):
|
||||
self.colors[id] = [max(fg, 0), max(bk, 0)]
|
||||
def init_pair(self, color_id, fg, bk):
|
||||
self.colors[color_id] = [max(fg, 0), max(bk, 0)]
|
||||
|
||||
def color_pair(self, id):
|
||||
return id
|
||||
def color_pair(self, color_id):
|
||||
return color_id
|
||||
|
@ -177,9 +177,6 @@ class _GlancesCurses(object):
|
||||
# Init refresh time
|
||||
self.__refresh_time = args.time
|
||||
|
||||
# Init process sort method
|
||||
self.args.process_sorted_by = 'auto'
|
||||
|
||||
# Init edit filter tag
|
||||
self.edit_filter = False
|
||||
|
||||
@ -257,17 +254,17 @@ class _GlancesCurses(object):
|
||||
# '/' > Switch between short/long name for processes
|
||||
self.args.process_short_name = not self.args.process_short_name
|
||||
elif self.pressedkey == ord('a'):
|
||||
# 'a' > Sort processes automatically
|
||||
self.args.process_sorted_by = 'auto'
|
||||
glances_processes.resetsort()
|
||||
# 'a' > Sort processes automatically and reset to 'cpu_percent'
|
||||
glances_processes.auto_sort = True
|
||||
glances_processes.sort_key = 'cpu_percent'
|
||||
elif self.pressedkey == ord('b'):
|
||||
# 'b' > Switch between bit/s and Byte/s for network IO
|
||||
# self.net_byteps_tag = not self.net_byteps_tag
|
||||
self.args.byte = not self.args.byte
|
||||
elif self.pressedkey == ord('c'):
|
||||
# 'c' > Sort processes by CPU usage
|
||||
self.args.process_sorted_by = 'cpu_percent'
|
||||
glances_processes.setmanualsortkey(self.args.process_sorted_by)
|
||||
glances_processes.auto_sort = False
|
||||
glances_processes.sort_key = 'cpu_percent'
|
||||
elif self.pressedkey == ord('d'):
|
||||
# 'd' > Show/hide disk I/O stats
|
||||
self.args.disable_diskio = not self.args.disable_diskio
|
||||
@ -295,8 +292,8 @@ class _GlancesCurses(object):
|
||||
self.args.help_tag = not self.args.help_tag
|
||||
elif self.pressedkey == ord('i'):
|
||||
# 'i' > Sort processes by IO rate (not available on OS X)
|
||||
self.args.process_sorted_by = 'io_counters'
|
||||
glances_processes.setmanualsortkey(self.args.process_sorted_by)
|
||||
glances_processes.auto_sort = False
|
||||
glances_processes.sort_key = 'io_counters'
|
||||
elif self.pressedkey == ord('I'):
|
||||
# 'I' > Show/hide IP module
|
||||
self.args.disable_ip = not self.args.disable_ip
|
||||
@ -305,15 +302,15 @@ class _GlancesCurses(object):
|
||||
self.args.disable_log = not self.args.disable_log
|
||||
elif self.pressedkey == ord('m'):
|
||||
# 'm' > Sort processes by MEM usage
|
||||
self.args.process_sorted_by = 'memory_percent'
|
||||
glances_processes.setmanualsortkey(self.args.process_sorted_by)
|
||||
glances_processes.auto_sort = False
|
||||
glances_processes.sort_key = 'memory_percent'
|
||||
elif self.pressedkey == ord('n'):
|
||||
# 'n' > Show/hide network stats
|
||||
self.args.disable_network = not self.args.disable_network
|
||||
elif self.pressedkey == ord('p'):
|
||||
# 'p' > Sort processes by name
|
||||
self.args.process_sorted_by = 'name'
|
||||
glances_processes.setmanualsortkey(self.args.process_sorted_by)
|
||||
glances_processes.auto_sort = False
|
||||
glances_processes.sort_key = 'name'
|
||||
elif self.pressedkey == ord('r'):
|
||||
# 'r' > Reset history
|
||||
self.reset_history_tag = not self.reset_history_tag
|
||||
@ -325,8 +322,8 @@ class _GlancesCurses(object):
|
||||
self.args.disable_sensors = not self.args.disable_sensors
|
||||
elif self.pressedkey == ord('t'):
|
||||
# 't' > Sort processes by TIME usage
|
||||
self.args.process_sorted_by = 'cpu_times'
|
||||
glances_processes.setmanualsortkey(self.args.process_sorted_by)
|
||||
glances_processes.auto_sort = False
|
||||
glances_processes.sort_key = 'cpu_times'
|
||||
elif self.pressedkey == ord('T'):
|
||||
# 'T' > View network traffic as sum Rx+Tx
|
||||
self.args.network_sum = not self.args.network_sum
|
||||
@ -389,7 +386,7 @@ class _GlancesCurses(object):
|
||||
"""New column in the curses interface"""
|
||||
self.column = self.next_column
|
||||
|
||||
def display(self, stats, cs_status="None"):
|
||||
def display(self, stats, cs_status=None):
|
||||
"""Display stats on the screen.
|
||||
|
||||
stats: Stats database to display
|
||||
@ -464,11 +461,10 @@ class _GlancesCurses(object):
|
||||
max_processes_displayed -= 4
|
||||
if max_processes_displayed < 0:
|
||||
max_processes_displayed = 0
|
||||
if glances_processes.get_max_processes() is None or \
|
||||
glances_processes.get_max_processes() != max_processes_displayed:
|
||||
logger.debug("Set number of displayed processes to %s" %
|
||||
max_processes_displayed)
|
||||
glances_processes.set_max_processes(max_processes_displayed)
|
||||
if (glances_processes.max_processes is None or
|
||||
glances_processes.max_processes != max_processes_displayed):
|
||||
logger.debug("Set number of displayed processes to {0}".format(max_processes_displayed))
|
||||
glances_processes.max_processes = max_processes_displayed
|
||||
|
||||
stats_processlist = stats.get_plugin(
|
||||
'processlist').get_stats_display(args=self.args)
|
||||
@ -600,7 +596,7 @@ class _GlancesCurses(object):
|
||||
self.display_plugin(stats_docker)
|
||||
self.new_line()
|
||||
self.display_plugin(stats_processcount)
|
||||
if glances_processes.get_process_filter() is None and cs_status == 'None':
|
||||
if glances_processes.process_filter is None and cs_status is None:
|
||||
# Do not display stats monitor list if a filter exist
|
||||
self.new_line()
|
||||
self.display_plugin(stats_monitor)
|
||||
@ -635,12 +631,12 @@ class _GlancesCurses(object):
|
||||
self.reset_history_tag = False
|
||||
|
||||
# Display edit filter popup
|
||||
# Only in standalone mode (cs_status == 'None')
|
||||
if self.edit_filter and cs_status == 'None':
|
||||
# Only in standalone mode (cs_status is None)
|
||||
if self.edit_filter and cs_status is None:
|
||||
new_filter = self.display_popup(_("Process filter pattern: "),
|
||||
is_input=True,
|
||||
input_value=glances_processes.get_process_filter())
|
||||
glances_processes.set_process_filter(new_filter)
|
||||
input_value=glances_processes.process_filter)
|
||||
glances_processes.process_filter = new_filter
|
||||
elif self.edit_filter and cs_status != 'None':
|
||||
self.display_popup(
|
||||
_("Process filter only available in standalone mode"))
|
||||
@ -765,7 +761,7 @@ class _GlancesCurses(object):
|
||||
# New line
|
||||
if m['msg'].startswith('\n'):
|
||||
# Go to the next line
|
||||
y = y + 1
|
||||
y += 1
|
||||
# Return to the first column
|
||||
x = display_x
|
||||
continue
|
||||
@ -802,7 +798,7 @@ class _GlancesCurses(object):
|
||||
# Python 3: strings are strings and bytes are bytes, all is
|
||||
# good
|
||||
offset = len(m['msg'])
|
||||
x = x + offset
|
||||
x += offset
|
||||
if x > x_max:
|
||||
x_max = x
|
||||
|
||||
@ -815,7 +811,7 @@ class _GlancesCurses(object):
|
||||
"""Erase the content of the screen."""
|
||||
self.term_window.erase()
|
||||
|
||||
def flush(self, stats, cs_status="None"):
|
||||
def flush(self, stats, cs_status=None):
|
||||
"""Clear and update the screen.
|
||||
|
||||
stats: Stats database to display
|
||||
@ -827,7 +823,7 @@ class _GlancesCurses(object):
|
||||
self.erase()
|
||||
self.display(stats, cs_status=cs_status)
|
||||
|
||||
def update(self, stats, cs_status="None", return_to_browser=False):
|
||||
def update(self, stats, cs_status=None, return_to_browser=False):
|
||||
"""Update the screen.
|
||||
|
||||
Wait for __refresh_time sec / catch key every 100 ms.
|
||||
@ -936,32 +932,30 @@ class GlancesCursesBrowser(_GlancesCurses):
|
||||
self.__refresh_time = args.time
|
||||
|
||||
# Init the cursor position for the client browser
|
||||
self.cursor_init()
|
||||
self.cursor_position = 0
|
||||
|
||||
# Active Glances server number
|
||||
self.set_active()
|
||||
self._active_server = None
|
||||
|
||||
def set_active(self, index=None):
|
||||
"""Set the active server or None if no server selected"""
|
||||
self.active_server = index
|
||||
return self.active_server
|
||||
@property
|
||||
def active_server(self):
|
||||
"""Return the active server or None if it's the browser list."""
|
||||
return self._active_server
|
||||
|
||||
def get_active(self):
|
||||
"""Return the active server (the one display in front) or None if it is the browser list"""
|
||||
return self.active_server
|
||||
@active_server.setter
|
||||
def active_server(self, index):
|
||||
"""Set the active server or None if no server selected."""
|
||||
self._active_server = index
|
||||
|
||||
def cursor_init(self):
|
||||
"""Init the cursor position to the top of the list"""
|
||||
return self.cursor_set(0)
|
||||
|
||||
def cursor_set(self, pos):
|
||||
"""Set the cursor position and return it"""
|
||||
self.cursor_position = pos
|
||||
@property
|
||||
def cursor(self):
|
||||
"""Get the cursor position."""
|
||||
return self.cursor_position
|
||||
|
||||
def cursor_get(self):
|
||||
"""Return the cursor position"""
|
||||
return self.cursor_position
|
||||
@cursor.setter
|
||||
def cursor(self, position):
|
||||
"""Set the cursor position."""
|
||||
self.cursor_position = position
|
||||
|
||||
def cursor_up(self, servers_list):
|
||||
"""Set the cursor to position N-1 in the list"""
|
||||
@ -969,7 +963,6 @@ class GlancesCursesBrowser(_GlancesCurses):
|
||||
self.cursor_position -= 1
|
||||
else:
|
||||
self.cursor_position = len(servers_list) - 1
|
||||
return self.cursor_position
|
||||
|
||||
def cursor_down(self, servers_list):
|
||||
"""Set the cursor to position N-1 in the list"""
|
||||
@ -977,7 +970,6 @@ class GlancesCursesBrowser(_GlancesCurses):
|
||||
self.cursor_position += 1
|
||||
else:
|
||||
self.cursor_position = 0
|
||||
return self.cursor_position
|
||||
|
||||
def __catch_key(self, servers_list):
|
||||
# Catch the browser pressed key
|
||||
@ -991,11 +983,10 @@ class GlancesCursesBrowser(_GlancesCurses):
|
||||
sys.exit(0)
|
||||
elif self.pressedkey == 10:
|
||||
# 'ENTER' > Run Glances on the selected server
|
||||
logger.debug("Server number %s selected" % (self.cursor_get() + 1))
|
||||
self.set_active(self.cursor_get())
|
||||
logger.debug("Server number {0} selected".format(self.cursor + 1))
|
||||
self.active_server = self.cursor
|
||||
elif self.pressedkey == 259:
|
||||
# 'UP' > Up in the server list
|
||||
logger
|
||||
self.cursor_up(servers_list)
|
||||
elif self.pressedkey == 258:
|
||||
# 'DOWN' > Down in the server list
|
||||
@ -1029,7 +1020,7 @@ class GlancesCursesBrowser(_GlancesCurses):
|
||||
# Wait 100ms...
|
||||
curses.napms(100)
|
||||
|
||||
return self.get_active()
|
||||
return self.active_server
|
||||
|
||||
def flush(self, servers_list):
|
||||
"""Update the servers' list screen.
|
||||
@ -1110,9 +1101,9 @@ class GlancesCursesBrowser(_GlancesCurses):
|
||||
|
||||
# If a servers has been deleted from the list...
|
||||
# ... and if the cursor is in the latest position
|
||||
if self.cursor_get() > len(servers_list) - 1:
|
||||
if self.cursor > len(servers_list) - 1:
|
||||
# Set the cursor position to the latest item
|
||||
self.cursor_set(len(servers_list) - 1)
|
||||
self.cursor = len(servers_list) - 1
|
||||
|
||||
# Display table
|
||||
line = 0
|
||||
@ -1138,25 +1129,18 @@ class GlancesCursesBrowser(_GlancesCurses):
|
||||
xc = x
|
||||
|
||||
# Is the line selected ?
|
||||
if line == self.cursor_get():
|
||||
if line == self.cursor:
|
||||
# Display cursor
|
||||
self.term_window.addnstr(y, xc,
|
||||
">",
|
||||
screen_x - xc,
|
||||
self.colors_list['BOLD'])
|
||||
|
||||
# Display alias instead of name
|
||||
server_stat
|
||||
self.term_window.addnstr(
|
||||
y, xc, ">", screen_x - xc, self.colors_list['BOLD'])
|
||||
|
||||
# Display the line
|
||||
xc += 2
|
||||
for c in column_def:
|
||||
if xc < screen_x and y < screen_y and c[1] is not None:
|
||||
# Display server stats
|
||||
self.term_window.addnstr(y, xc,
|
||||
"%s" % server_stat[c[0]],
|
||||
c[2],
|
||||
self.colors_list[v['status']])
|
||||
self.term_window.addnstr(
|
||||
y, xc, format(server_stat[c[0]]), c[2], self.colors_list[v['status']])
|
||||
xc += c[2] + self.space_between_column
|
||||
cpt += 1
|
||||
# Next line, next server...
|
||||
|
@ -42,7 +42,7 @@ class Plugin(GlancesPlugin):
|
||||
self.display_curse = True
|
||||
|
||||
# Set the message position
|
||||
self.set_align('bottom')
|
||||
self.align = 'bottom'
|
||||
|
||||
# Init the stats
|
||||
self.reset()
|
||||
|
@ -28,7 +28,6 @@ try:
|
||||
import batinfo
|
||||
except ImportError:
|
||||
logger.debug("Batinfo library not found. Glances cannot grab battery info.")
|
||||
pass
|
||||
|
||||
|
||||
class Plugin(GlancesPlugin):
|
||||
@ -62,12 +61,12 @@ class Plugin(GlancesPlugin):
|
||||
# Reset stats
|
||||
self.reset()
|
||||
|
||||
if self.get_input() == 'local':
|
||||
if self.input_method == 'local':
|
||||
# Update stats
|
||||
self.glancesgrabbat.update()
|
||||
self.stats = self.glancesgrabbat.get()
|
||||
|
||||
elif self.get_input() == 'snmp':
|
||||
elif self.input_method == 'snmp':
|
||||
# Update stats using SNMP
|
||||
# Not avalaible
|
||||
pass
|
||||
@ -94,7 +93,7 @@ class GlancesGrabBat(object):
|
||||
"""Update the stats."""
|
||||
if self.initok:
|
||||
self.bat.update()
|
||||
self.bat_list = [{'label': _("Battery"), 'value': self.getcapacitypercent(), 'unit': '%'}]
|
||||
self.bat_list = [{'label': _("Battery"), 'value': self.battery_percent, 'unit': '%'}]
|
||||
else:
|
||||
self.bat_list = []
|
||||
|
||||
@ -102,7 +101,8 @@ class GlancesGrabBat(object):
|
||||
"""Get the stats."""
|
||||
return self.bat_list
|
||||
|
||||
def getcapacitypercent(self):
|
||||
@property
|
||||
def battery_percent(self):
|
||||
"""Get batteries capacity percent."""
|
||||
if not self.initok or not self.bat.stat:
|
||||
return []
|
||||
@ -112,7 +112,7 @@ class GlancesGrabBat(object):
|
||||
bsum = 0
|
||||
for b in self.bat.stat:
|
||||
try:
|
||||
bsum = bsum + int(b.capacity)
|
||||
bsum += int(b.capacity)
|
||||
except ValueError:
|
||||
return []
|
||||
|
||||
|
@ -56,7 +56,7 @@ class Plugin(GlancesPlugin):
|
||||
# Reset the stats
|
||||
self.reset()
|
||||
|
||||
if self.get_input() == 'local':
|
||||
if self.input_method == 'local':
|
||||
# Update stats using the standard system lib
|
||||
|
||||
# The PSUtil 2.0 include psutil.cpu_count() and psutil.cpu_count(logical=False)
|
||||
@ -70,7 +70,7 @@ class Plugin(GlancesPlugin):
|
||||
except NameError:
|
||||
self.reset()
|
||||
|
||||
elif self.get_input() == 'snmp':
|
||||
elif self.input_method == 'snmp':
|
||||
# Update stats using SNMP
|
||||
# http://stackoverflow.com/questions/5662467/how-to-find-out-the-number-of-cpus-using-snmp
|
||||
pass
|
||||
|
@ -78,7 +78,7 @@ class Plugin(GlancesPlugin):
|
||||
|
||||
# Grab CPU stats using psutil's cpu_percent and cpu_times_percent
|
||||
# methods
|
||||
if self.get_input() == 'local':
|
||||
if self.input_method == 'local':
|
||||
# Get all possible values for CPU stats: user, system, idle,
|
||||
# nice (UNIX), iowait (Linux), irq (Linux, FreeBSD), steal (Linux 2.6.11+)
|
||||
# The following stats are returned by the API but not displayed in the UI:
|
||||
@ -89,14 +89,14 @@ class Plugin(GlancesPlugin):
|
||||
'irq', 'softirq', 'steal', 'guest', 'guest_nice']:
|
||||
if hasattr(cpu_times_percent, stat):
|
||||
self.stats[stat] = getattr(cpu_times_percent, stat)
|
||||
elif self.get_input() == 'snmp':
|
||||
elif self.input_method == 'snmp':
|
||||
# Update stats using SNMP
|
||||
if self.get_short_system_name() in ('windows', 'esxi'):
|
||||
if self.short_system_name in ('windows', 'esxi'):
|
||||
# Windows or VMWare ESXi
|
||||
# You can find the CPU utilization of windows system by querying the oid
|
||||
# Give also the number of core (number of element in the table)
|
||||
try:
|
||||
cpu_stats = self.set_stats_snmp(snmp_oid=snmp_oid[self.get_short_system_name()],
|
||||
cpu_stats = self.get_stats_snmp(snmp_oid=snmp_oid[self.short_system_name],
|
||||
bulk=True)
|
||||
except KeyError:
|
||||
self.reset()
|
||||
@ -117,10 +117,10 @@ class Plugin(GlancesPlugin):
|
||||
else:
|
||||
# Default behavor
|
||||
try:
|
||||
self.stats = self.set_stats_snmp(
|
||||
snmp_oid=snmp_oid[self.get_short_system_name()])
|
||||
self.stats = self.get_stats_snmp(
|
||||
snmp_oid=snmp_oid[self.short_system_name])
|
||||
except KeyError:
|
||||
self.stats = self.set_stats_snmp(
|
||||
self.stats = self.get_stats_snmp(
|
||||
snmp_oid=snmp_oid['default'])
|
||||
|
||||
if self.stats['idle'] == '':
|
||||
@ -150,9 +150,8 @@ class Plugin(GlancesPlugin):
|
||||
for key in ['user', 'system', 'iowait']:
|
||||
if key in self.stats:
|
||||
self.views[key]['decoration'] = self.get_alert_log(self.stats[key], header=key)
|
||||
self.views['total']['decoration'] = self.get_alert_log(self.stats['total'], header="system")
|
||||
# Alert only
|
||||
for key in ['steal']:
|
||||
for key in ['steal', 'total']:
|
||||
if key in self.stats:
|
||||
self.views[key]['decoration'] = self.get_alert(self.stats[key], header=key)
|
||||
# Optional
|
||||
@ -166,7 +165,7 @@ class Plugin(GlancesPlugin):
|
||||
ret = []
|
||||
|
||||
# Only process if stats exist...
|
||||
if self.stats == {}:
|
||||
if not self.stats:
|
||||
return ret
|
||||
|
||||
# Build the string message
|
||||
|
@ -66,7 +66,7 @@ class Plugin(GlancesPlugin):
|
||||
# Reset stats
|
||||
self.reset()
|
||||
|
||||
if self.get_input() == 'local':
|
||||
if self.input_method == 'local':
|
||||
# Update stats using the standard system lib
|
||||
# Grab the stat using the PsUtil disk_io_counters method
|
||||
# read_count: number of reads
|
||||
@ -96,16 +96,15 @@ class Plugin(GlancesPlugin):
|
||||
diskio_new = diskiocounters
|
||||
for disk in diskio_new:
|
||||
try:
|
||||
# Try necessary to manage dynamic disk creation/del
|
||||
diskstat = {}
|
||||
diskstat['time_since_update'] = time_since_update
|
||||
diskstat['disk_name'] = disk
|
||||
diskstat['read_bytes'] = (
|
||||
diskio_new[disk].read_bytes -
|
||||
self.diskio_old[disk].read_bytes)
|
||||
diskstat['write_bytes'] = (
|
||||
diskio_new[disk].write_bytes -
|
||||
self.diskio_old[disk].write_bytes)
|
||||
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': disk,
|
||||
'read_bytes': read_bytes,
|
||||
'write_bytes': write_bytes}
|
||||
except KeyError:
|
||||
continue
|
||||
else:
|
||||
@ -114,7 +113,7 @@ class Plugin(GlancesPlugin):
|
||||
|
||||
# Save stats to compute next bitrate
|
||||
self.diskio_old = diskio_new
|
||||
elif self.get_input() == 'snmp':
|
||||
elif self.input_method == 'snmp':
|
||||
# Update stats using SNMP
|
||||
# No standard way for the moment...
|
||||
pass
|
||||
|
@ -19,7 +19,12 @@
|
||||
|
||||
"""Docker plugin."""
|
||||
|
||||
import numbers
|
||||
import os
|
||||
import re
|
||||
|
||||
# Import Glances libs
|
||||
from glances.core.glances_timer import getTimeSinceLastUpdate
|
||||
from glances.core.glances_logging import logger
|
||||
from glances.plugins.glances_plugin import GlancesPlugin
|
||||
|
||||
@ -33,9 +38,6 @@ except ImportError as e:
|
||||
docker_tag = False
|
||||
else:
|
||||
docker_tag = True
|
||||
import os
|
||||
import re
|
||||
import numbers
|
||||
|
||||
|
||||
class Plugin(GlancesPlugin):
|
||||
@ -82,7 +84,6 @@ class Plugin(GlancesPlugin):
|
||||
# API error (Version mismatch ?)
|
||||
logger.debug("Docker API error (%s)" % e)
|
||||
# Try the connection with the server version
|
||||
import re
|
||||
version = re.search('server\:\ (.*)\)\".*\)', str(e))
|
||||
if version:
|
||||
logger.debug("Try connection with Docker API version %s" % version.group(1))
|
||||
@ -129,7 +130,7 @@ class Plugin(GlancesPlugin):
|
||||
if not docker_tag or (self.args is not None and self.args.disable_docker):
|
||||
return self.stats
|
||||
|
||||
if self.get_input() == 'local':
|
||||
if self.input_method == 'local':
|
||||
# Update stats
|
||||
# Exemple: {
|
||||
# "KernelVersion": "3.16.4-tinycore64",
|
||||
@ -150,12 +151,31 @@ class Plugin(GlancesPlugin):
|
||||
# u'Names': [u'/webstack_nginx_1'],
|
||||
# u'Id': u'b0da859e84eb4019cf1d965b15e9323006e510352c402d2f442ea632d61faaa5'}]
|
||||
self.stats['containers'] = self.docker_client.containers()
|
||||
# Get CPU and MEMORY stats for containers
|
||||
# Get stats for all containers
|
||||
for c in self.stats['containers']:
|
||||
c['cpu'] = self.get_docker_cpu(c['Id'])
|
||||
c['memory'] = self.get_docker_memory(c['Id'])
|
||||
if not hasattr(self, 'docker_stats'):
|
||||
# Create a dict with all the containers' stats instance
|
||||
self.docker_stats = {}
|
||||
|
||||
elif self.get_input() == 'snmp':
|
||||
if c['Id'] not in self.docker_stats:
|
||||
# Create the stats instance for the current container
|
||||
try:
|
||||
self.docker_stats[c['Id']] = self.docker_client.stats(c['Id'], decode=True)
|
||||
logger.debug("Create Docker stats object for container {}".format(c['Id']))
|
||||
except (AttributeError, docker.errors.InvalidVersion) as e:
|
||||
logger.error("Can not call Docker stats method {}".format(e))
|
||||
|
||||
# Get the docker stats
|
||||
try:
|
||||
all_stats = self.docker_stats[c['Id']].next()
|
||||
except:
|
||||
all_stats = {}
|
||||
|
||||
c['cpu'] = self.get_docker_cpu(c['Id'], all_stats)
|
||||
c['memory'] = self.get_docker_memory(c['Id'], all_stats)
|
||||
# c['network'] = self.get_docker_network(c['Id'], all_stats)
|
||||
|
||||
elif self.input_method == 'snmp':
|
||||
# Update stats using SNMP
|
||||
# Not available
|
||||
pass
|
||||
@ -164,14 +184,14 @@ class Plugin(GlancesPlugin):
|
||||
|
||||
return self.stats
|
||||
|
||||
def get_docker_cpu(self, id):
|
||||
def get_docker_cpu_old(self, container_id):
|
||||
"""Return the container CPU usage by reading /sys/fs/cgroup/...
|
||||
Input: id is the full container id
|
||||
Output: a dict {'total': 1.49, 'user': 0.65, 'system': 0.84}"""
|
||||
ret = {}
|
||||
# Read the stats
|
||||
try:
|
||||
with open('/sys/fs/cgroup/cpuacct/docker/' + id + '/cpuacct.stat', 'r') as f:
|
||||
with open('/sys/fs/cgroup/cpuacct/docker/' + container_id + '/cpuacct.stat', 'r') as f:
|
||||
for line in f:
|
||||
m = re.search(r"(system|user)\s+(\d+)", line)
|
||||
if m:
|
||||
@ -179,23 +199,45 @@ class Plugin(GlancesPlugin):
|
||||
except IOError as e:
|
||||
logger.error("Can not grab container CPU stat ({0})".format(e))
|
||||
return ret
|
||||
# Get the user ticks
|
||||
ticks = self.get_user_ticks()
|
||||
if isinstance(ret["system"], numbers.Number) and isinstance(ret["user"], numbers.Number):
|
||||
ret["total"] = ret["system"] + ret["user"]
|
||||
for k in ret.keys():
|
||||
ret[k] = float(ret[k]) / ticks
|
||||
# Return the stats
|
||||
return ret
|
||||
|
||||
def get_docker_memory(self, id):
|
||||
def get_docker_cpu(self, container_id, all_stats):
|
||||
"""Return the container CPU usage
|
||||
Input: id is the full container id
|
||||
all_stats is the output of the stats method of the Docker API
|
||||
Output: a dict {'total': 1.49}"""
|
||||
ret = {}
|
||||
|
||||
# Read the stats
|
||||
# try:
|
||||
# ret['total'] = all_stats['cpu_stats']['cpu_usage']['total_usage']
|
||||
# except KeyError as e:
|
||||
# # all_stats do not have CPU information
|
||||
# logger.error("Can not grab CPU usage for container {0} ({1})".format(container_id, e))
|
||||
# # Trying fallback to old grab method
|
||||
# ret = self.get_docker_cpu_old(container_id)
|
||||
|
||||
# Did not work has expected, replace by the old method...
|
||||
ret = self.get_docker_cpu_old(container_id)
|
||||
|
||||
# Get the user ticks
|
||||
ticks = self.get_user_ticks()
|
||||
for k in ret.keys():
|
||||
ret[k] = float(ret[k]) / ticks
|
||||
# Return the stats
|
||||
return ret
|
||||
|
||||
def get_docker_memory_old(self, container_id):
|
||||
"""Return the container MEMORY usage by reading /sys/fs/cgroup/...
|
||||
Input: id is the full container id
|
||||
Output: a dict {'rss': 1015808, 'cache': 356352}"""
|
||||
ret = {}
|
||||
# Read the stats
|
||||
try:
|
||||
with open('/sys/fs/cgroup/memory/docker/' + id + '/memory.stat', 'r') as f:
|
||||
with open('/sys/fs/cgroup/memory/docker/' + container_id + '/memory.stat', 'r') as f:
|
||||
for line in f:
|
||||
m = re.search(r"(rss|cache)\s+(\d+)", line)
|
||||
if m:
|
||||
@ -206,6 +248,73 @@ class Plugin(GlancesPlugin):
|
||||
# Return the stats
|
||||
return ret
|
||||
|
||||
def get_docker_memory(self, container_id, all_stats):
|
||||
"""Return the container MEMORY
|
||||
Input: id is the full container id
|
||||
all_stats is the output of the stats method of the Docker API
|
||||
Output: a dict {'rss': 1015808, 'cache': 356352, 'usage': ..., 'max_usage': ...}"""
|
||||
ret = {}
|
||||
# Read the stats
|
||||
try:
|
||||
ret['rss'] = all_stats['memory_stats']['stats']['rss']
|
||||
ret['cache'] = all_stats['memory_stats']['stats']['cache']
|
||||
ret['usage'] = all_stats['memory_stats']['usage']
|
||||
ret['max_usage'] = all_stats['memory_stats']['max_usage']
|
||||
except KeyError as e:
|
||||
# all_stats do not have MEM information
|
||||
logger.error("Can not grab MEM usage for container {0} ({1})".format(container_id, e))
|
||||
# Trying fallback to old grab method
|
||||
ret = self.get_docker_memory_old(container_id)
|
||||
# Return the stats
|
||||
return ret
|
||||
|
||||
def get_docker_network(self, container_id, all_stats):
|
||||
"""Return the container network usage using the Docker API (v1.0 or higher)
|
||||
Input: id is the full container id
|
||||
Output: a dict {'time_since_update': 3000, 'rx': 10, 'tx': 65}"""
|
||||
|
||||
# Init the returned dict
|
||||
network_new = {}
|
||||
|
||||
# Read the rx/tx stats (in bytes)
|
||||
try:
|
||||
netiocounters = all_stats["network"]
|
||||
except KeyError as e:
|
||||
# all_stats do not have NETWORK information
|
||||
logger.debug("Can not grab NET usage for container {0} ({1})".format(container_id, e))
|
||||
# No fallback available...
|
||||
return network_new
|
||||
|
||||
# Previous network interface stats are stored in the network_old variable
|
||||
if not hasattr(self, 'netiocounters_old'):
|
||||
# First call, we init the network_old var
|
||||
self.netiocounters_old = {}
|
||||
try:
|
||||
self.netiocounters_old[container_id] = netiocounters
|
||||
except (IOError, UnboundLocalError):
|
||||
pass
|
||||
|
||||
if container_id not in self.netiocounters_old:
|
||||
try:
|
||||
self.netiocounters_old[container_id] = netiocounters
|
||||
except (IOError, UnboundLocalError):
|
||||
pass
|
||||
else:
|
||||
# By storing time data we enable Rx/s and Tx/s calculations in the
|
||||
# XML/RPC API, which would otherwise be overly difficult work
|
||||
# for users of the API
|
||||
network_new['time_since_update'] = getTimeSinceLastUpdate('docker_net')
|
||||
network_new['rx'] = netiocounters["rx_bytes"] - self.netiocounters_old[container_id]["rx_bytes"]
|
||||
network_new['tx'] = netiocounters["tx_bytes"] - self.netiocounters_old[container_id]["tx_bytes"]
|
||||
network_new['cumulative_rx'] = netiocounters["rx_bytes"]
|
||||
network_new['cumulative_tx'] = netiocounters["tx_bytes"]
|
||||
|
||||
# Save stats to compute next bitrate
|
||||
self.netiocounters_old[container_id] = netiocounters
|
||||
|
||||
# Return the stats
|
||||
return network_new
|
||||
|
||||
def get_user_ticks(self):
|
||||
"""return the user ticks by reading the environment variable"""
|
||||
return os.sysconf(os.sysconf_names['SC_CLK_TCK'])
|
||||
@ -216,7 +325,7 @@ class Plugin(GlancesPlugin):
|
||||
ret = []
|
||||
|
||||
# Only process if stats exist (and non null) and display plugin enable...
|
||||
if self.stats == {} or args.disable_docker or len(self.stats['containers']) == 0:
|
||||
if not self.stats or args.disable_docker or len(self.stats['containers']) == 0:
|
||||
return ret
|
||||
|
||||
# Build the string message
|
||||
@ -239,8 +348,12 @@ class Plugin(GlancesPlugin):
|
||||
ret.append(self.curse_add_line(msg))
|
||||
msg = '{0:>6}'.format(_("CPU%"))
|
||||
ret.append(self.curse_add_line(msg))
|
||||
msg = '{0:>6}'.format(_("MEM"))
|
||||
msg = '{0:>7}'.format(_("MEM"))
|
||||
ret.append(self.curse_add_line(msg))
|
||||
# msg = '{0:>6}'.format(_("Rx/s"))
|
||||
# ret.append(self.curse_add_line(msg))
|
||||
# msg = '{0:>6}'.format(_("Tx/s"))
|
||||
# ret.append(self.curse_add_line(msg))
|
||||
msg = ' {0:8}'.format(_("Command"))
|
||||
ret.append(self.curse_add_line(msg))
|
||||
# Data
|
||||
@ -254,7 +367,7 @@ class Plugin(GlancesPlugin):
|
||||
if len(name) > 20:
|
||||
name = '_' + name[:-19]
|
||||
else:
|
||||
name[0:20]
|
||||
name = name[:20]
|
||||
msg = ' {0:20}'.format(name)
|
||||
ret.append(self.curse_add_line(msg))
|
||||
# Status
|
||||
@ -270,10 +383,18 @@ class Plugin(GlancesPlugin):
|
||||
ret.append(self.curse_add_line(msg))
|
||||
# MEM
|
||||
try:
|
||||
msg = '{0:>6}'.format(self.auto_unit(container['memory']['rss']))
|
||||
msg = '{0:>7}'.format(self.auto_unit(container['memory']['usage']))
|
||||
except KeyError:
|
||||
msg = '{0:>6}'.format('?')
|
||||
msg = '{0:>7}'.format('?')
|
||||
ret.append(self.curse_add_line(msg))
|
||||
# NET RX/TX
|
||||
# for r in ['rx', 'tx']:
|
||||
# try:
|
||||
# value = self.auto_unit(int(container['network'][r] // container['network']['time_since_update'] * 8)) + "b"
|
||||
# msg = '{0:>6}'.format(value)
|
||||
# except KeyError:
|
||||
# msg = '{0:>6}'.format('?')
|
||||
# ret.append(self.curse_add_line(msg))
|
||||
# Command
|
||||
msg = ' {0}'.format(container['Command'])
|
||||
ret.append(self.curse_add_line(msg))
|
||||
|
@ -24,7 +24,6 @@ import operator
|
||||
import psutil
|
||||
|
||||
from glances.plugins.glances_plugin import GlancesPlugin
|
||||
from glances.core.glances_logging import logger
|
||||
|
||||
# SNMP OID
|
||||
# The snmpd.conf needs to be edited.
|
||||
@ -94,7 +93,7 @@ class Plugin(GlancesPlugin):
|
||||
# Reset the list
|
||||
self.reset()
|
||||
|
||||
if self.get_input() == 'local':
|
||||
if self.input_method == 'local':
|
||||
# Update stats using the standard system lib
|
||||
|
||||
# Grab the stats using the PsUtil disk_partitions
|
||||
@ -116,10 +115,6 @@ class Plugin(GlancesPlugin):
|
||||
|
||||
# Loop over fs
|
||||
for fs in fs_stat:
|
||||
fs_current = {}
|
||||
fs_current['device_name'] = fs.device
|
||||
fs_current['fs_type'] = fs.fstype
|
||||
fs_current['mnt_point'] = fs.mountpoint
|
||||
# Grab the disk usage
|
||||
try:
|
||||
fs_usage = psutil.disk_usage(fs.mountpoint)
|
||||
@ -127,52 +122,56 @@ class Plugin(GlancesPlugin):
|
||||
# Correct issue #346
|
||||
# Disk is ejected during the command
|
||||
continue
|
||||
fs_current['size'] = fs_usage.total
|
||||
fs_current['used'] = fs_usage.used
|
||||
fs_current['free'] = fs_usage.total - fs_usage.used
|
||||
fs_current['percent'] = fs_usage.percent
|
||||
fs_current['key'] = self.get_key()
|
||||
fs_current = {
|
||||
'device_name': fs.device,
|
||||
'fs_type': fs.fstype,
|
||||
'mnt_point': fs.mountpoint,
|
||||
'size': fs_usage.total,
|
||||
'used': fs_usage.used,
|
||||
'free': fs_usage.total - fs_usage.used,
|
||||
'percent': fs_usage.percent,
|
||||
'key': self.get_key()}
|
||||
self.stats.append(fs_current)
|
||||
|
||||
elif self.get_input() == 'snmp':
|
||||
elif self.input_method == 'snmp':
|
||||
# Update stats using SNMP
|
||||
|
||||
# SNMP bulk command to get all file system in one shot
|
||||
try:
|
||||
fs_stat = self.set_stats_snmp(snmp_oid=snmp_oid[self.get_short_system_name()],
|
||||
fs_stat = self.get_stats_snmp(snmp_oid=snmp_oid[self.short_system_name],
|
||||
bulk=True)
|
||||
except KeyError:
|
||||
fs_stat = self.set_stats_snmp(snmp_oid=snmp_oid['default'],
|
||||
fs_stat = self.get_stats_snmp(snmp_oid=snmp_oid['default'],
|
||||
bulk=True)
|
||||
|
||||
# Loop over fs
|
||||
if self.get_short_system_name() in ('windows', 'esxi'):
|
||||
if self.short_system_name in ('windows', 'esxi'):
|
||||
# Windows or ESXi tips
|
||||
for fs in fs_stat:
|
||||
# Memory stats are grabed in the same OID table (ignore it)
|
||||
# Memory stats are grabbed in the same OID table (ignore it)
|
||||
if fs == 'Virtual Memory' or fs == 'Physical Memory' or fs == 'Real Memory':
|
||||
continue
|
||||
fs_current = {}
|
||||
fs_current['device_name'] = ''
|
||||
fs_current['mnt_point'] = fs.partition(' ')[0]
|
||||
fs_current['size'] = int(
|
||||
fs_stat[fs]['size']) * int(fs_stat[fs]['alloc_unit'])
|
||||
fs_current['used'] = int(
|
||||
fs_stat[fs]['used']) * int(fs_stat[fs]['alloc_unit'])
|
||||
fs_current['percent'] = float(
|
||||
fs_current['used'] * 100 / fs_current['size'])
|
||||
fs_current['key'] = self.get_key()
|
||||
size = int(fs_stat[fs]['size']) * int(fs_stat[fs]['alloc_unit'])
|
||||
used = int(fs_stat[fs]['used']) * int(fs_stat[fs]['alloc_unit'])
|
||||
percent = float(used * 100 / size)
|
||||
fs_current = {
|
||||
'device_name': '',
|
||||
'mnt_point': fs.partition(' ')[0],
|
||||
'size': size,
|
||||
'used': used,
|
||||
'percent': percent,
|
||||
'key': self.get_key()}
|
||||
self.stats.append(fs_current)
|
||||
else:
|
||||
# Default behavor
|
||||
# Default behavior
|
||||
for fs in fs_stat:
|
||||
fs_current = {}
|
||||
fs_current['device_name'] = fs_stat[fs]['device_name']
|
||||
fs_current['mnt_point'] = fs
|
||||
fs_current['size'] = int(fs_stat[fs]['size']) * 1024
|
||||
fs_current['used'] = int(fs_stat[fs]['used']) * 1024
|
||||
fs_current['percent'] = float(fs_stat[fs]['percent'])
|
||||
fs_current['key'] = self.get_key()
|
||||
fs_current = {
|
||||
'device_name': fs_stat[fs]['device_name'],
|
||||
'mnt_point': fs,
|
||||
'size': int(fs_stat[fs]['size']) * 1024,
|
||||
'used': int(fs_stat[fs]['used']) * 1024,
|
||||
'percent': float(fs_stat[fs]['percent']),
|
||||
'key': self.get_key()}
|
||||
self.stats.append(fs_current)
|
||||
|
||||
# Update the history list
|
||||
@ -192,7 +191,7 @@ class Plugin(GlancesPlugin):
|
||||
# Alert
|
||||
for i in self.stats:
|
||||
self.views[i[self.get_key()]]['used']['decoration'] = self.get_alert(
|
||||
i['used'], max=i['size'], header=i['mnt_point'])
|
||||
i['used'], maximum=i['size'], header=i['mnt_point'])
|
||||
|
||||
def msg_curse(self, args=None, max_width=None):
|
||||
"""Return the dict to display in the curse interface."""
|
||||
|
@ -25,6 +25,7 @@ import socket
|
||||
|
||||
# Import Glances libs
|
||||
from glances.plugins.glances_plugin import GlancesPlugin
|
||||
from glances.core.glances_logging import logger
|
||||
|
||||
|
||||
class Plugin(GlancesPlugin):
|
||||
@ -39,7 +40,7 @@ class Plugin(GlancesPlugin):
|
||||
GlancesPlugin.__init__(self, args=args)
|
||||
|
||||
# Init the sensor class
|
||||
self.glancesgrabhddtemp = GlancesGrabHDDTemp()
|
||||
self.glancesgrabhddtemp = GlancesGrabHDDTemp(args=args)
|
||||
|
||||
# We do not want to display the stat in a dedicated area
|
||||
# The HDD temp is displayed within the sensors plugin
|
||||
@ -57,7 +58,7 @@ class Plugin(GlancesPlugin):
|
||||
# Reset stats
|
||||
self.reset()
|
||||
|
||||
if self.get_input() == 'local':
|
||||
if self.input_method == 'local':
|
||||
# Update stats using the standard system lib
|
||||
self.stats = self.glancesgrabhddtemp.get()
|
||||
|
||||
@ -73,8 +74,9 @@ class GlancesGrabHDDTemp(object):
|
||||
|
||||
"""Get hddtemp stats using a socket connection."""
|
||||
|
||||
def __init__(self, host='127.0.0.1', port=7634):
|
||||
def __init__(self, host='127.0.0.1', port=7634, args=None):
|
||||
"""Init hddtemp stats."""
|
||||
self.args = args
|
||||
self.host = host
|
||||
self.port = port
|
||||
self.cache = ""
|
||||
@ -89,6 +91,10 @@ class GlancesGrabHDDTemp(object):
|
||||
# Reset the list
|
||||
self.reset()
|
||||
|
||||
# Only update if --disable-hddtemp is not set
|
||||
if self.args is None or self.args.disable_hddtemp:
|
||||
return
|
||||
|
||||
# Fetch the data
|
||||
data = self.fetch()
|
||||
|
||||
@ -125,7 +131,10 @@ class GlancesGrabHDDTemp(object):
|
||||
sck.connect((self.host, self.port))
|
||||
data = sck.recv(4096)
|
||||
sck.close()
|
||||
except socket.error:
|
||||
except socket.error as e:
|
||||
logger.warning("Can not connect to an HDDtemp server ({0}:{1} => {2})".format(self.host, self.port, e))
|
||||
logger.debug("Disable the HDDtemp module. Use the --disable-hddtemp to hide the previous message.")
|
||||
self.args.disable_hddtemp = True
|
||||
data = ""
|
||||
|
||||
return data
|
||||
|
@ -61,7 +61,7 @@ class Plugin(GlancesPlugin):
|
||||
# Reset stats
|
||||
self.reset()
|
||||
|
||||
if self.get_input() == 'local' and netifaces_tag:
|
||||
if self.input_method == 'local' and netifaces_tag:
|
||||
# Update stats using the netifaces lib
|
||||
try:
|
||||
default_gw = netifaces.gateways()['default'][netifaces.AF_INET]
|
||||
@ -76,7 +76,7 @@ class Plugin(GlancesPlugin):
|
||||
except KeyError as e:
|
||||
logger.debug("Can not grab IP information (%s)".format(e))
|
||||
|
||||
elif self.get_input() == 'snmp':
|
||||
elif self.input_method == 'snmp':
|
||||
# Not implemented yet
|
||||
pass
|
||||
|
||||
@ -106,9 +106,11 @@ class Plugin(GlancesPlugin):
|
||||
return ret
|
||||
|
||||
# Build the string message
|
||||
msg = _(' - IP')
|
||||
msg = _(' - ')
|
||||
ret.append(self.curse_add_line(msg))
|
||||
msg = _('IP ')
|
||||
ret.append(self.curse_add_line(msg, 'TITLE'))
|
||||
msg = ' {0:}/{1}'.format(self.stats['address'], self.stats['mask_cidr'])
|
||||
msg = '{0:}/{1}'.format(self.stats['address'], self.stats['mask_cidr'])
|
||||
ret.append(self.curse_add_line(msg))
|
||||
|
||||
return ret
|
||||
@ -117,4 +119,4 @@ class Plugin(GlancesPlugin):
|
||||
def ip_to_cidr(ip):
|
||||
# Convert IP address to CIDR
|
||||
# Exemple: '255.255.255.0' will return 24
|
||||
return sum(map(lambda x: int(x) << 8, ip.split('.'))) / 8128
|
||||
return sum(map(lambda x: int(x) << 8, ip.split('.'))) // 8128
|
||||
|
@ -76,7 +76,7 @@ class Plugin(GlancesPlugin):
|
||||
# Reset stats
|
||||
self.reset()
|
||||
|
||||
if self.get_input() == 'local':
|
||||
if self.input_method == 'local':
|
||||
# Update stats using the standard system lib
|
||||
|
||||
# Get the load using the os standard lib
|
||||
@ -89,9 +89,9 @@ class Plugin(GlancesPlugin):
|
||||
'min5': load[1],
|
||||
'min15': load[2],
|
||||
'cpucore': self.nb_log_core}
|
||||
elif self.get_input() == 'snmp':
|
||||
elif self.input_method == 'snmp':
|
||||
# Update stats using SNMP
|
||||
self.stats = self.set_stats_snmp(snmp_oid=snmp_oid)
|
||||
self.stats = self.get_stats_snmp(snmp_oid=snmp_oid)
|
||||
|
||||
if self.stats['min1'] == '':
|
||||
self.reset()
|
||||
@ -124,9 +124,9 @@ class Plugin(GlancesPlugin):
|
||||
# Add specifics informations
|
||||
try:
|
||||
# Alert and log
|
||||
self.views['min15']['decoration'] = self.get_alert_log(self.stats['min15'], max=100 * self.stats['cpucore'])
|
||||
self.views['min15']['decoration'] = self.get_alert_log(self.stats['min15'], maximum=100 * self.stats['cpucore'])
|
||||
# Alert only
|
||||
self.views['min5']['decoration'] = self.get_alert(self.stats['min5'], max=100 * self.stats['cpucore'])
|
||||
self.views['min5']['decoration'] = self.get_alert(self.stats['min5'], maximum=100 * self.stats['cpucore'])
|
||||
except KeyError:
|
||||
# try/except mandatory for Windows compatibility (no load stats)
|
||||
pass
|
||||
@ -137,7 +137,7 @@ class Plugin(GlancesPlugin):
|
||||
ret = []
|
||||
|
||||
# Only process if stats exist...
|
||||
if self.stats == {}:
|
||||
if not self.stats:
|
||||
return ret
|
||||
|
||||
# Build the string message
|
||||
|
@ -78,7 +78,7 @@ class Plugin(GlancesPlugin):
|
||||
# Reset stats
|
||||
self.reset()
|
||||
|
||||
if self.get_input() == 'local':
|
||||
if self.input_method == 'local':
|
||||
# Update stats using the standard system lib
|
||||
# Grab MEM using the PSUtil virtual_memory method
|
||||
vm_stats = psutil.virtual_memory()
|
||||
@ -112,12 +112,12 @@ class Plugin(GlancesPlugin):
|
||||
self.stats['free'] += self.stats['cached']
|
||||
# used=total-free
|
||||
self.stats['used'] = self.stats['total'] - self.stats['free']
|
||||
elif self.get_input() == 'snmp':
|
||||
elif self.input_method == 'snmp':
|
||||
# Update stats using SNMP
|
||||
if self.get_short_system_name() in ('windows', 'esxi'):
|
||||
if self.short_system_name in ('windows', 'esxi'):
|
||||
# Mem stats for Windows|Vmware Esxi are stored in the FS table
|
||||
try:
|
||||
fs_stat = self.set_stats_snmp(snmp_oid=snmp_oid[self.get_short_system_name()],
|
||||
fs_stat = self.get_stats_snmp(snmp_oid=snmp_oid[self.short_system_name],
|
||||
bulk=True)
|
||||
except KeyError:
|
||||
self.reset()
|
||||
@ -133,7 +133,7 @@ class Plugin(GlancesPlugin):
|
||||
break
|
||||
else:
|
||||
# Default behavor for others OS
|
||||
self.stats = self.set_stats_snmp(snmp_oid=snmp_oid['default'])
|
||||
self.stats = self.get_stats_snmp(snmp_oid=snmp_oid['default'])
|
||||
|
||||
if self.stats['total'] == '':
|
||||
self.reset()
|
||||
@ -167,7 +167,7 @@ class Plugin(GlancesPlugin):
|
||||
|
||||
# Add specifics informations
|
||||
# Alert and log
|
||||
self.views['used']['decoration'] = self.get_alert_log(self.stats['used'], max=self.stats['total'])
|
||||
self.views['used']['decoration'] = self.get_alert_log(self.stats['used'], maximum=self.stats['total'])
|
||||
# Optional
|
||||
for key in ['active', 'inactive', 'buffers', 'cached']:
|
||||
if key in self.stats:
|
||||
@ -179,7 +179,7 @@ class Plugin(GlancesPlugin):
|
||||
ret = []
|
||||
|
||||
# Only process if stats exist...
|
||||
if self.stats == {}:
|
||||
if not self.stats:
|
||||
return ret
|
||||
|
||||
# Build the string message
|
||||
|
@ -67,7 +67,7 @@ class Plugin(GlancesPlugin):
|
||||
# Reset stats
|
||||
self.reset()
|
||||
|
||||
if self.get_input() == 'local':
|
||||
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()
|
||||
@ -84,12 +84,12 @@ class Plugin(GlancesPlugin):
|
||||
'sin', 'sout']:
|
||||
if hasattr(sm_stats, swap):
|
||||
self.stats[swap] = getattr(sm_stats, swap)
|
||||
elif self.get_input() == 'snmp':
|
||||
elif self.input_method == 'snmp':
|
||||
# Update stats using SNMP
|
||||
if self.get_short_system_name() == 'windows':
|
||||
if self.short_system_name == 'windows':
|
||||
# Mem stats for Windows OS are stored in the FS table
|
||||
try:
|
||||
fs_stat = self.set_stats_snmp(snmp_oid=snmp_oid[self.get_short_system_name()],
|
||||
fs_stat = self.get_stats_snmp(snmp_oid=snmp_oid[self.short_system_name],
|
||||
bulk=True)
|
||||
except KeyError:
|
||||
self.reset()
|
||||
@ -109,7 +109,7 @@ class Plugin(GlancesPlugin):
|
||||
'total'] - self.stats['used']
|
||||
break
|
||||
else:
|
||||
self.stats = self.set_stats_snmp(snmp_oid=snmp_oid['default'])
|
||||
self.stats = self.get_stats_snmp(snmp_oid=snmp_oid['default'])
|
||||
|
||||
if self.stats['total'] == '':
|
||||
self.reset()
|
||||
@ -142,7 +142,7 @@ class Plugin(GlancesPlugin):
|
||||
|
||||
# Add specifics informations
|
||||
# Alert and log
|
||||
self.views['used']['decoration'] = self.get_alert_log(self.stats['used'], max=self.stats['total'])
|
||||
self.views['used']['decoration'] = self.get_alert_log(self.stats['used'], maximum=self.stats['total'])
|
||||
|
||||
def msg_curse(self, args=None):
|
||||
"""Return the dict to display in the curse interface."""
|
||||
@ -150,7 +150,7 @@ class Plugin(GlancesPlugin):
|
||||
ret = []
|
||||
|
||||
# Only process if stats exist...
|
||||
if self.stats == {}:
|
||||
if not self.stats:
|
||||
return ret
|
||||
|
||||
# Build the string message
|
||||
|
@ -47,7 +47,7 @@ class Plugin(GlancesPlugin):
|
||||
|
||||
def update(self):
|
||||
"""Update the monitored list."""
|
||||
if self.get_input() == 'local':
|
||||
if self.input_method == 'local':
|
||||
# Monitor list only available in a full Glances environment
|
||||
# Check if the glances_monitor instance is init
|
||||
if self.glances_monitors is None:
|
||||
|
@ -75,7 +75,7 @@ class Plugin(GlancesPlugin):
|
||||
# Reset stats
|
||||
self.reset()
|
||||
|
||||
if self.get_input() == 'local':
|
||||
if self.input_method == 'local':
|
||||
# Update stats using the standard system lib
|
||||
|
||||
# Grab network interface stat using the PsUtil net_io_counter method
|
||||
@ -101,19 +101,21 @@ class Plugin(GlancesPlugin):
|
||||
network_new = netiocounters
|
||||
for net in network_new:
|
||||
try:
|
||||
# Try necessary to manage dynamic network interface
|
||||
netstat = {}
|
||||
netstat['interface_name'] = net
|
||||
netstat['time_since_update'] = time_since_update
|
||||
netstat['cumulative_rx'] = network_new[net].bytes_recv
|
||||
netstat['rx'] = (network_new[net].bytes_recv -
|
||||
self.network_old[net].bytes_recv)
|
||||
netstat['cumulative_tx'] = network_new[net].bytes_sent
|
||||
netstat['tx'] = (network_new[net].bytes_sent -
|
||||
self.network_old[net].bytes_sent)
|
||||
netstat['cumulative_cx'] = (netstat['cumulative_rx'] +
|
||||
netstat['cumulative_tx'])
|
||||
netstat['cx'] = netstat['rx'] + netstat['tx']
|
||||
cumulative_rx = network_new[net].bytes_recv
|
||||
cumulative_tx = network_new[net].bytes_sent
|
||||
cumulative_cx = cumulative_rx + cumulative_tx
|
||||
rx = cumulative_rx - self.network_old[net].bytes_recv
|
||||
tx = cumulative_tx - self.network_old[net].bytes_sent
|
||||
cx = rx + tx
|
||||
netstat = {
|
||||
'interface_name': net,
|
||||
'time_since_update': time_since_update,
|
||||
'cumulative_rx': cumulative_rx,
|
||||
'rx': rx,
|
||||
'cumulative_tx': cumulative_tx,
|
||||
'tx': tx,
|
||||
'cumulative_cx': cumulative_cx,
|
||||
'cx': cx}
|
||||
except KeyError:
|
||||
continue
|
||||
else:
|
||||
@ -123,15 +125,15 @@ class Plugin(GlancesPlugin):
|
||||
# Save stats to compute next bitrate
|
||||
self.network_old = network_new
|
||||
|
||||
elif self.get_input() == 'snmp':
|
||||
elif self.input_method == 'snmp':
|
||||
# Update stats using SNMP
|
||||
|
||||
# SNMP bulk command to get all network interface in one shot
|
||||
try:
|
||||
netiocounters = self.set_stats_snmp(snmp_oid=snmp_oid[self.get_short_system_name()],
|
||||
netiocounters = self.get_stats_snmp(snmp_oid=snmp_oid[self.short_system_name],
|
||||
bulk=True)
|
||||
except KeyError:
|
||||
netiocounters = self.set_stats_snmp(snmp_oid=snmp_oid['default'],
|
||||
netiocounters = self.get_stats_snmp(snmp_oid=snmp_oid['default'],
|
||||
bulk=True)
|
||||
|
||||
# Previous network interface stats are stored in the network_old variable
|
||||
@ -150,27 +152,30 @@ class Plugin(GlancesPlugin):
|
||||
|
||||
for net in network_new:
|
||||
try:
|
||||
# Try necessary to manage dynamic network interface
|
||||
netstat = {}
|
||||
# Windows: a tips is needed to convert HEX to TXT
|
||||
# http://blogs.technet.com/b/networking/archive/2009/12/18/how-to-query-the-list-of-network-interfaces-using-snmp-via-the-ifdescr-counter.aspx
|
||||
if self.get_short_system_name() == 'windows':
|
||||
if self.short_system_name == 'windows':
|
||||
try:
|
||||
netstat['interface_name'] = str(base64.b16decode(net[2:-2].upper()))
|
||||
interface_name = str(base64.b16decode(net[2:-2].upper()))
|
||||
except TypeError:
|
||||
netstat['interface_name'] = net
|
||||
interface_name = net
|
||||
else:
|
||||
netstat['interface_name'] = net
|
||||
netstat['time_since_update'] = time_since_update
|
||||
netstat['cumulative_rx'] = float(network_new[net]['cumulative_rx'])
|
||||
netstat['rx'] = (float(network_new[net]['cumulative_rx']) -
|
||||
float(self.network_old[net]['cumulative_rx']))
|
||||
netstat['cumulative_tx'] = float(network_new[net]['cumulative_tx'])
|
||||
netstat['tx'] = (float(network_new[net]['cumulative_tx']) -
|
||||
float(self.network_old[net]['cumulative_tx']))
|
||||
netstat['cumulative_cx'] = (netstat['cumulative_rx'] +
|
||||
netstat['cumulative_tx'])
|
||||
netstat['cx'] = netstat['rx'] + netstat['tx']
|
||||
interface_name = net
|
||||
cumulative_rx = float(network_new[net]['cumulative_rx'])
|
||||
cumulative_tx = float(network_new[net]['cumulative_tx'])
|
||||
cumulative_cx = cumulative_rx + cumulative_tx
|
||||
rx = cumulative_rx - float(self.network_old[net]['cumulative_rx'])
|
||||
tx = cumulative_tx - float(self.network_old[net]['cumulative_tx'])
|
||||
cx = rx + tx
|
||||
netstat = {
|
||||
'interface_name': interface_name,
|
||||
'time_since_update': time_since_update,
|
||||
'cumulative_rx': cumulative_rx,
|
||||
'rx': rx,
|
||||
'cumulative_tx': cumulative_tx,
|
||||
'tx': tx,
|
||||
'cumulative_cx': cumulative_cx,
|
||||
'cx': cx}
|
||||
except KeyError:
|
||||
continue
|
||||
else:
|
||||
|
@ -39,7 +39,7 @@ class Plugin(GlancesPlugin):
|
||||
self.display_curse = True
|
||||
|
||||
# Set the message position
|
||||
self.set_align('bottom')
|
||||
self.align = 'bottom'
|
||||
|
||||
def update(self):
|
||||
"""Update current date/time."""
|
||||
|
@ -53,7 +53,7 @@ class Plugin(GlancesPlugin):
|
||||
|
||||
# Grab per-CPU stats using psutil's cpu_percent(percpu=True) and
|
||||
# cpu_times_percent(percpu=True) methods
|
||||
if self.get_input() == 'local':
|
||||
if self.input_method == 'local':
|
||||
percpu_percent = psutil.cpu_percent(interval=0.0, percpu=True)
|
||||
percpu_times_percent = psutil.cpu_times_percent(interval=0.0, percpu=True)
|
||||
for cputimes in percpu_times_percent:
|
||||
|
@ -49,11 +49,11 @@ class GlancesPlugin(object):
|
||||
self.args = args
|
||||
|
||||
# Init the default alignement (for curses)
|
||||
self.set_align('left')
|
||||
self._align = 'left'
|
||||
|
||||
# Init the input method
|
||||
self.input_method = 'local'
|
||||
self.short_system_name = None
|
||||
self._input_method = 'local'
|
||||
self._short_system_name = None
|
||||
|
||||
# Init the stats list
|
||||
self.stats = None
|
||||
@ -63,7 +63,7 @@ class GlancesPlugin(object):
|
||||
self.stats_history = self.init_stats_history()
|
||||
|
||||
# Init the limits dictionnary
|
||||
self.limits = dict()
|
||||
self._limits = dict()
|
||||
|
||||
# Init the actions
|
||||
self.actions = GlancesActions()
|
||||
@ -107,11 +107,12 @@ class GlancesPlugin(object):
|
||||
logger.debug("Reset history for plugin {0} (items: {0})".format(
|
||||
self.plugin_name, reset_list))
|
||||
self.stats_history = {}
|
||||
return self.stats_history
|
||||
|
||||
def update_stats_history(self, item_name=''):
|
||||
"""Update stats history"""
|
||||
if self.stats != [] and self.args is not None and self.args.enable_history and self.get_items_history_list() is not None:
|
||||
if (self.stats and self.args is not None and
|
||||
self.args.enable_history and
|
||||
self.get_items_history_list() is not None):
|
||||
self.add_item_history('date', datetime.now())
|
||||
for i in self.get_items_history_list():
|
||||
if type(self.stats) is list:
|
||||
@ -125,7 +126,6 @@ class GlancesPlugin(object):
|
||||
# Stats is not a list
|
||||
# Add the item to the history directly
|
||||
self.add_item_history(i['name'], self.stats[i['name']])
|
||||
return self.stats_history
|
||||
|
||||
def get_stats_history(self):
|
||||
"""Return the stats history"""
|
||||
@ -135,37 +135,42 @@ class GlancesPlugin(object):
|
||||
"""Return the items history list"""
|
||||
return self.items_history_list
|
||||
|
||||
def set_input(self, input_method, short_system_name=None):
|
||||
@property
|
||||
def input_method(self):
|
||||
"""Get the input method."""
|
||||
return self._input_method
|
||||
|
||||
@input_method.setter
|
||||
def input_method(self, input_method):
|
||||
"""Set the input method.
|
||||
|
||||
* local: system local grab (psutil or direct access)
|
||||
* snmp: Client server mode via SNMP
|
||||
* glances: Client server mode via Glances API
|
||||
|
||||
For SNMP, short_system_name is detected short OS name
|
||||
"""
|
||||
self.input_method = input_method
|
||||
self.short_system_name = short_system_name
|
||||
return self.input_method
|
||||
self._input_method = input_method
|
||||
|
||||
def get_input(self):
|
||||
"""Get the input method."""
|
||||
return self.input_method
|
||||
@property
|
||||
def short_system_name(self):
|
||||
"""Get the short detected OS name (SNMP)."""
|
||||
return self._short_system_name
|
||||
|
||||
def get_short_system_name(self):
|
||||
"""Get the short detected OS name"""
|
||||
return self.short_system_name
|
||||
@short_system_name.setter
|
||||
def short_system_name(self, short_name):
|
||||
"""Set the short detected OS name (SNMP)."""
|
||||
self._short_system_name = short_name
|
||||
|
||||
def set_stats(self, input_stats):
|
||||
"""Set the stats to input_stats."""
|
||||
self.stats = input_stats
|
||||
return self.stats
|
||||
|
||||
def set_stats_snmp(self, bulk=False, snmp_oid={}):
|
||||
def get_stats_snmp(self, bulk=False, snmp_oid=None):
|
||||
"""Update stats using SNMP.
|
||||
|
||||
If bulk=True, use a bulk request instead of a get request.
|
||||
"""
|
||||
snmp_oid = snmp_oid or {}
|
||||
|
||||
from glances.core.glances_snmp import GlancesSNMPClient
|
||||
|
||||
# Init the SNMP request
|
||||
@ -201,7 +206,7 @@ class GlancesPlugin(object):
|
||||
item_key = item[oid]
|
||||
else:
|
||||
item_stats[key] = item[oid]
|
||||
if item_stats != {}:
|
||||
if item_stats:
|
||||
ret[item_key] = item_stats
|
||||
index += 1
|
||||
else:
|
||||
@ -299,7 +304,6 @@ class GlancesPlugin(object):
|
||||
def set_views(self, input_views):
|
||||
"""Set the views to input_views."""
|
||||
self.views = input_views
|
||||
return self.views
|
||||
|
||||
def get_views(self, item=None, key=None, option=None):
|
||||
"""Return the views object.
|
||||
@ -326,27 +330,26 @@ class GlancesPlugin(object):
|
||||
"""Load the limits from the configuration file."""
|
||||
if (hasattr(config, 'has_section') and
|
||||
config.has_section(self.plugin_name)):
|
||||
for s, v in config.items(self.plugin_name):
|
||||
for level, v in config.items(self.plugin_name):
|
||||
# Read limits
|
||||
limit = '_'.join([self.plugin_name, level])
|
||||
try:
|
||||
self.limits[
|
||||
self.plugin_name + '_' + s] = config.get_option(self.plugin_name, s)
|
||||
self._limits[limit] = config.get_option(self.plugin_name, level)
|
||||
except ValueError:
|
||||
self.limits[
|
||||
self.plugin_name + '_' + s] = config.get_raw_option(self.plugin_name, s).split(",")
|
||||
logger.debug("Load limit: {0} = {1}".format(self.plugin_name + '_' + s,
|
||||
self.limits[self.plugin_name + '_' + s]))
|
||||
self._limits[limit] = config.get_raw_option(self.plugin_name, level).split(",")
|
||||
logger.debug("Load limit: {0} = {1}".format(limit, self._limits[limit]))
|
||||
|
||||
def set_limits(self, input_limits):
|
||||
"""Set the limits to input_limits."""
|
||||
self.limits = input_limits
|
||||
return self.limits
|
||||
|
||||
def get_limits(self):
|
||||
@property
|
||||
def limits(self):
|
||||
"""Return the limits object."""
|
||||
return self.limits
|
||||
return self._limits
|
||||
|
||||
def get_alert(self, current=0, min=0, max=100, header="", log=False):
|
||||
@limits.setter
|
||||
def limits(self, input_limits):
|
||||
"""Set the limits to input_limits."""
|
||||
self._limits = input_limits
|
||||
|
||||
def get_alert(self, current=0, minimum=0, maximum=100, header="", log=False):
|
||||
"""Return the alert status relative to a current value.
|
||||
|
||||
Use this function for minor stats.
|
||||
@ -365,7 +368,7 @@ class GlancesPlugin(object):
|
||||
"""
|
||||
# Compute the %
|
||||
try:
|
||||
value = (current * 100) / max
|
||||
value = (current * 100) / maximum
|
||||
except ZeroDivisionError:
|
||||
return 'DEFAULT'
|
||||
except TypeError:
|
||||
@ -386,7 +389,7 @@ class GlancesPlugin(object):
|
||||
ret = 'WARNING'
|
||||
elif value > self.__get_limit('careful', stat_name=stat_name):
|
||||
ret = 'CAREFUL'
|
||||
elif current < min:
|
||||
elif current < minimum:
|
||||
ret = 'CAREFUL'
|
||||
except KeyError:
|
||||
return 'DEFAULT'
|
||||
@ -428,20 +431,20 @@ class GlancesPlugin(object):
|
||||
# Default is ok
|
||||
return ret + log_str
|
||||
|
||||
def get_alert_log(self, current=0, min=0, max=100, header=""):
|
||||
def get_alert_log(self, current=0, minimum=0, maximum=100, header=""):
|
||||
"""Get the alert log."""
|
||||
return self.get_alert(current, min, max, header, log=True)
|
||||
return self.get_alert(current, minimum, maximum, header, log=True)
|
||||
|
||||
def __get_limit(self, criticity, stat_name=""):
|
||||
"""Return the limit value for the alert"""
|
||||
# Get the limit for stat + header
|
||||
# Exemple: network_wlan0_rx_careful
|
||||
try:
|
||||
limit = self.limits[stat_name + '_' + criticity]
|
||||
limit = self._limits[stat_name + '_' + criticity]
|
||||
except KeyError:
|
||||
# Try fallback to plugin default limit
|
||||
# Exemple: network_careful
|
||||
limit = self.limits[self.plugin_name + '_' + criticity]
|
||||
limit = self._limits[self.plugin_name + '_' + criticity]
|
||||
|
||||
# Return the limit
|
||||
return limit
|
||||
@ -451,11 +454,11 @@ class GlancesPlugin(object):
|
||||
# Get the action for stat + header
|
||||
# Exemple: network_wlan0_rx_careful_action
|
||||
try:
|
||||
ret = self.limits[stat_name + '_' + criticity + '_action']
|
||||
ret = self._limits[stat_name + '_' + criticity + '_action']
|
||||
except KeyError:
|
||||
# Try fallback to plugin default limit
|
||||
# Exemple: network_careful_action
|
||||
ret = self.limits[self.plugin_name + '_' + criticity + '_action']
|
||||
ret = self._limits[self.plugin_name + '_' + criticity + '_action']
|
||||
|
||||
# Return the action list
|
||||
return ret
|
||||
@ -465,12 +468,12 @@ class GlancesPlugin(object):
|
||||
# Get the log tag for stat + header
|
||||
# Exemple: network_wlan0_rx_log
|
||||
try:
|
||||
log_tag = self.limits[stat_name + '_log']
|
||||
log_tag = self._limits[stat_name + '_log']
|
||||
except KeyError:
|
||||
# Try fallback to plugin default log
|
||||
# Exemple: network_log
|
||||
try:
|
||||
log_tag = self.limits[self.plugin_name + '_log']
|
||||
log_tag = self._limits[self.plugin_name + '_log']
|
||||
except KeyError:
|
||||
# By defaukt, log are disabled
|
||||
return default_action
|
||||
@ -484,12 +487,12 @@ class GlancesPlugin(object):
|
||||
plugin_name = self.plugin_name
|
||||
if header == "":
|
||||
try:
|
||||
return self.limits[plugin_name + '_' + value]
|
||||
return self._limits[plugin_name + '_' + value]
|
||||
except KeyError:
|
||||
return []
|
||||
else:
|
||||
try:
|
||||
return self.limits[plugin_name + '_' + header + '_' + value]
|
||||
return self._limits[plugin_name + '_' + header + '_' + value]
|
||||
except KeyError:
|
||||
return []
|
||||
|
||||
@ -500,7 +503,7 @@ class GlancesPlugin(object):
|
||||
def has_alias(self, header):
|
||||
"""Return the alias name for the relative header or None if nonexist"""
|
||||
try:
|
||||
return self.limits[self.plugin_name + '_' + header + '_' + 'alias'][0]
|
||||
return self._limits[self.plugin_name + '_' + header + '_' + 'alias'][0]
|
||||
except (KeyError, IndexError):
|
||||
return None
|
||||
|
||||
@ -522,7 +525,7 @@ class GlancesPlugin(object):
|
||||
if hasattr(self, 'display_curse'):
|
||||
display_curse = self.display_curse
|
||||
if hasattr(self, 'align'):
|
||||
align_curse = self.align
|
||||
align_curse = self._align
|
||||
|
||||
if max_width is not None:
|
||||
ret = {'display': display_curse,
|
||||
@ -568,16 +571,18 @@ class GlancesPlugin(object):
|
||||
"""Go to a new line."""
|
||||
return self.curse_add_line('\n')
|
||||
|
||||
def set_align(self, align='left'):
|
||||
"""Set the Curse align"""
|
||||
if align in ('left', 'right', 'bottom'):
|
||||
self.align = align
|
||||
else:
|
||||
self.align = 'left'
|
||||
@property
|
||||
def align(self):
|
||||
"""Get the curse align."""
|
||||
return self._align
|
||||
|
||||
def get_align(self):
|
||||
"""Get the Curse align"""
|
||||
return self.align
|
||||
@align.setter
|
||||
def align(self, value):
|
||||
"""Set the curse align.
|
||||
|
||||
value: left, right, bottom.
|
||||
"""
|
||||
self._align = value
|
||||
|
||||
def auto_unit(self, number, low_precision=False):
|
||||
"""Make a nice human-readable string out of number.
|
||||
|
@ -52,14 +52,14 @@ class Plugin(GlancesPlugin):
|
||||
# Reset stats
|
||||
self.reset()
|
||||
|
||||
if self.get_input() == 'local':
|
||||
if self.input_method == 'local':
|
||||
# Update stats using the standard system lib
|
||||
# Here, update is call for processcount AND processlist
|
||||
glances_processes.update()
|
||||
|
||||
# Return the processes count
|
||||
self.stats = glances_processes.getcount()
|
||||
elif self.get_input() == 'snmp':
|
||||
elif self.input_method == 'snmp':
|
||||
# Update stats using SNMP
|
||||
# !!! TODO
|
||||
pass
|
||||
@ -77,14 +77,14 @@ class Plugin(GlancesPlugin):
|
||||
ret.append(self.curse_add_line(msg))
|
||||
return ret
|
||||
|
||||
if self.stats == {}:
|
||||
if not self.stats:
|
||||
return ret
|
||||
|
||||
# Display the filter (if it exists)
|
||||
if glances_processes.get_process_filter() is not None:
|
||||
if glances_processes.process_filter is not None:
|
||||
msg = _("Processes filter:")
|
||||
ret.append(self.curse_add_line(msg, "TITLE"))
|
||||
msg = _(" {0} ").format(glances_processes.get_process_filter())
|
||||
msg = _(" {0} ").format(glances_processes.process_filter)
|
||||
ret.append(self.curse_add_line(msg, "FILTER"))
|
||||
msg = _("(press ENTER to edit)")
|
||||
ret.append(self.curse_add_line(msg))
|
||||
@ -117,13 +117,13 @@ class Plugin(GlancesPlugin):
|
||||
ret.append(self.curse_add_line(msg))
|
||||
|
||||
# Display sort information
|
||||
if glances_processes.getmanualsortkey() is None:
|
||||
if glances_processes.auto_sort:
|
||||
msg = _("sorted automatically")
|
||||
ret.append(self.curse_add_line(msg))
|
||||
msg = _(" by {0}").format(glances_processes.getautosortkey())
|
||||
msg = _(" by {0}").format(glances_processes.sort_key)
|
||||
ret.append(self.curse_add_line(msg))
|
||||
else:
|
||||
msg = _("sorted by {0}").format(glances_processes.getmanualsortkey())
|
||||
msg = _("sorted by {0}").format(glances_processes.sort_key)
|
||||
ret.append(self.curse_add_line(msg))
|
||||
ret[-1]["msg"] += ", %s view" % ("tree" if glances_processes.is_tree_enabled() else "flat")
|
||||
|
||||
|
@ -59,7 +59,7 @@ class Plugin(GlancesPlugin):
|
||||
# Reset stats
|
||||
self.reset()
|
||||
|
||||
if self.get_input() == 'local':
|
||||
if self.input_method == 'local':
|
||||
# Update stats using the standard system lib
|
||||
# Note: Update is done in the processcount plugin
|
||||
# Just return the processes list
|
||||
@ -67,7 +67,7 @@ class Plugin(GlancesPlugin):
|
||||
self.stats = glances_processes.gettree()
|
||||
else:
|
||||
self.stats = glances_processes.getlist()
|
||||
elif self.get_input() == 'snmp':
|
||||
elif self.input_method == 'snmp':
|
||||
# No SNMP grab for processes
|
||||
pass
|
||||
|
||||
@ -154,8 +154,7 @@ class Plugin(GlancesPlugin):
|
||||
|
||||
def get_process_curses_data(self, p, first, args):
|
||||
""" Get curses data to display for a process. """
|
||||
ret = []
|
||||
ret.append(self.curse_new_line())
|
||||
ret = [self.curse_new_line()]
|
||||
# CPU
|
||||
if 'cpu_percent' in p and p['cpu_percent'] is not None and p['cpu_percent'] != '':
|
||||
msg = '{0:>6.1f}'.format(p['cpu_percent'])
|
||||
@ -365,7 +364,7 @@ class Plugin(GlancesPlugin):
|
||||
return ret
|
||||
|
||||
# Compute the sort key
|
||||
process_sort_key = glances_processes.getsortkey()
|
||||
process_sort_key = glances_processes.sort_key
|
||||
sort_style = 'SORT'
|
||||
|
||||
# Header
|
||||
@ -401,7 +400,7 @@ class Plugin(GlancesPlugin):
|
||||
ret.extend(self.get_process_tree_curses_data(self.sortstats(process_sort_key),
|
||||
args,
|
||||
first_level=True,
|
||||
max_node_count=glances_processes.get_max_processes()))
|
||||
max_node_count=glances_processes.max_processes))
|
||||
else:
|
||||
# Loop over processes (sorted by the sort key previously compute)
|
||||
first = True
|
||||
|
@ -45,7 +45,7 @@ class Plugin(GlancesPlugin):
|
||||
self.reset()
|
||||
|
||||
# Return PsUtil version as a tuple
|
||||
if self.get_input() == 'local':
|
||||
if self.input_method == 'local':
|
||||
# PsUtil version only available in local
|
||||
try:
|
||||
self.stats = tuple([int(num) for num in __psutil_version.split('.')])
|
||||
|
@ -24,7 +24,7 @@ import psutil
|
||||
from glances.plugins.glances_plugin import GlancesPlugin
|
||||
from glances.core.glances_cpu_percent import cpu_percent
|
||||
from glances.outputs.glances_bars import Bar
|
||||
from glances.core.glances_logging import logger
|
||||
#from glances.core.glances_logging import logger
|
||||
|
||||
|
||||
class Plugin(GlancesPlugin):
|
||||
@ -55,13 +55,13 @@ class Plugin(GlancesPlugin):
|
||||
self.reset()
|
||||
|
||||
# Grab quicklook stats: CPU, MEM and SWAP
|
||||
if self.get_input() == 'local':
|
||||
if self.input_method == 'local':
|
||||
# Get the latest CPU percent value
|
||||
self.stats['cpu'] = cpu_percent.get()
|
||||
# Use the PsUtil lib for the memory (virtual and swap)
|
||||
self.stats['mem'] = psutil.virtual_memory().percent
|
||||
self.stats['swap'] = psutil.swap_memory().percent
|
||||
elif self.get_input() == 'snmp':
|
||||
elif self.input_method == 'snmp':
|
||||
# Not available
|
||||
pass
|
||||
|
||||
@ -87,7 +87,7 @@ class Plugin(GlancesPlugin):
|
||||
ret = []
|
||||
|
||||
# Only process if stats exist...
|
||||
if self.stats == {} or args.disable_quicklook:
|
||||
if not self.stats or args.disable_quicklook:
|
||||
return ret
|
||||
|
||||
# Define the bar
|
||||
@ -95,7 +95,7 @@ class Plugin(GlancesPlugin):
|
||||
|
||||
# Build the string message
|
||||
for key in ['cpu', 'mem', 'swap']:
|
||||
bar.set_percent(self.stats[key])
|
||||
bar.percent = self.stats[key]
|
||||
msg = '{0:>4} '.format(key.upper())
|
||||
ret.append(self.curse_add_line(msg))
|
||||
msg = '{0}'.format(bar)
|
||||
|
@ -28,7 +28,6 @@ try:
|
||||
from pymdstat import MdStat
|
||||
except ImportError:
|
||||
logger.debug("pymdstat library not found. Glances cannot grab RAID info.")
|
||||
pass
|
||||
|
||||
|
||||
class Plugin(GlancesPlugin):
|
||||
@ -58,7 +57,7 @@ class Plugin(GlancesPlugin):
|
||||
# Reset stats
|
||||
self.reset()
|
||||
|
||||
if self.get_input() == 'local':
|
||||
if self.input_method == 'local':
|
||||
# Update stats using the PyMDstat lib (https://github.com/nicolargo/pymdstat)
|
||||
try:
|
||||
mds = MdStat()
|
||||
@ -67,7 +66,7 @@ class Plugin(GlancesPlugin):
|
||||
logger.debug("Can not grab RAID stats (%s)" % e)
|
||||
return self.stats
|
||||
|
||||
elif self.get_input() == 'snmp':
|
||||
elif self.input_method == 'snmp':
|
||||
# Update stats using SNMP
|
||||
# No standard way for the moment...
|
||||
pass
|
||||
|
@ -83,7 +83,7 @@ class Plugin(GlancesPlugin):
|
||||
# Reset the stats
|
||||
self.reset()
|
||||
|
||||
if self.get_input() == 'local':
|
||||
if self.input_method == 'local':
|
||||
# Update stats using the dedicated lib
|
||||
self.stats = []
|
||||
# Get the temperature
|
||||
@ -123,7 +123,7 @@ class Plugin(GlancesPlugin):
|
||||
# Append Batteries %
|
||||
self.stats.extend(batpercent)
|
||||
|
||||
elif self.get_input() == 'snmp':
|
||||
elif self.input_method == 'snmp':
|
||||
# Update stats using SNMP
|
||||
# No standard:
|
||||
# http://www.net-snmp.org/wiki/index.php/Net-SNMP_and_lm-sensors_on_Ubuntu_10.04
|
||||
@ -156,7 +156,7 @@ class Plugin(GlancesPlugin):
|
||||
# Add specifics informations
|
||||
# Alert
|
||||
for i in self.stats:
|
||||
if i['value'] == []:
|
||||
if not i['value']:
|
||||
continue
|
||||
if i['type'] == 'battery':
|
||||
self.views[i[self.get_key()]]['value']['decoration'] = self.get_alert(100 - i['value'], header=i['type'])
|
||||
@ -169,7 +169,7 @@ class Plugin(GlancesPlugin):
|
||||
ret = []
|
||||
|
||||
# Only process if stats exist and display plugin enable...
|
||||
if not self.stats or args.disable_sensors or self.stats == []:
|
||||
if not self.stats or args.disable_sensors:
|
||||
return ret
|
||||
|
||||
# Build the string message
|
||||
@ -178,7 +178,7 @@ class Plugin(GlancesPlugin):
|
||||
ret.append(self.curse_add_line(msg, "TITLE"))
|
||||
|
||||
for i in self.stats:
|
||||
if i['value'] is not None and i['value'] != []:
|
||||
if i['value']:
|
||||
# New line
|
||||
ret.append(self.curse_new_line())
|
||||
# Alias for the lable name ?
|
||||
@ -187,8 +187,8 @@ class Plugin(GlancesPlugin):
|
||||
label = i['label']
|
||||
try:
|
||||
msg = "{0:12} {1:3}".format(label[:11], i['unit'])
|
||||
except KeyError:
|
||||
msg = '{0:16}'.format(label[:15])
|
||||
except (KeyError, UnicodeEncodeError):
|
||||
msg = "{0:16}".format(label[:15])
|
||||
ret.append(self.curse_add_line(msg))
|
||||
msg = '{0:>7}'.format(i['value'])
|
||||
ret.append(self.curse_add_line(
|
||||
@ -234,23 +234,23 @@ class GlancesGrabSensors(object):
|
||||
elif feature.name.startswith(b'fan'):
|
||||
# Fan speed sensor
|
||||
sensors_current['unit'] = SENSOR_FAN_UNIT
|
||||
if sensors_current != {}:
|
||||
if sensors_current:
|
||||
sensors_current['label'] = feature.label
|
||||
sensors_current['value'] = int(feature.get_value())
|
||||
self.sensors_list.append(sensors_current)
|
||||
|
||||
return self.sensors_list
|
||||
|
||||
def get(self, type='temperature_core'):
|
||||
def get(self, sensor_type='temperature_core'):
|
||||
"""Get sensors list."""
|
||||
self.__update__()
|
||||
if type == 'temperature_core':
|
||||
if sensor_type == 'temperature_core':
|
||||
ret = [s for s in self.sensors_list if s['unit'] == SENSOR_TEMP_UNIT]
|
||||
elif type == 'fan_speed':
|
||||
elif sensor_type == 'fan_speed':
|
||||
ret = [s for s in self.sensors_list if s['unit'] == SENSOR_FAN_UNIT]
|
||||
else:
|
||||
# Unknown type
|
||||
logger.debug("Unknown sensor type %s" % type)
|
||||
logger.debug("Unknown sensor type %s" % sensor_type)
|
||||
ret = []
|
||||
return ret
|
||||
|
||||
|
@ -103,7 +103,7 @@ class Plugin(GlancesPlugin):
|
||||
# Reset stats
|
||||
self.reset()
|
||||
|
||||
if self.get_input() == 'local':
|
||||
if self.input_method == 'local':
|
||||
# Update stats using the standard system lib
|
||||
self.stats['os_name'] = platform.system()
|
||||
self.stats['hostname'] = platform.node()
|
||||
@ -136,17 +136,17 @@ class Plugin(GlancesPlugin):
|
||||
self.stats['os_name'], self.stats['os_version'])
|
||||
self.stats['hr_name'] += ' ({0})'.format(self.stats['platform'])
|
||||
|
||||
elif self.get_input() == 'snmp':
|
||||
elif self.input_method == 'snmp':
|
||||
# Update stats using SNMP
|
||||
try:
|
||||
self.stats = self.set_stats_snmp(
|
||||
snmp_oid=snmp_oid[self.get_short_system_name()])
|
||||
self.stats = self.get_stats_snmp(
|
||||
snmp_oid=snmp_oid[self.short_system_name])
|
||||
except KeyError:
|
||||
self.stats = self.set_stats_snmp(snmp_oid=snmp_oid['default'])
|
||||
self.stats = self.get_stats_snmp(snmp_oid=snmp_oid['default'])
|
||||
# Default behavor: display all the information
|
||||
self.stats['os_name'] = self.stats['system_name']
|
||||
# Windows OS tips
|
||||
if self.get_short_system_name() == 'windows':
|
||||
if self.short_system_name == 'windows':
|
||||
try:
|
||||
iteritems = snmp_to_human['windows'].iteritems()
|
||||
except AttributeError:
|
||||
|
@ -47,7 +47,7 @@ class Plugin(GlancesPlugin):
|
||||
self.display_curse = True
|
||||
|
||||
# Set the message position
|
||||
self.set_align('right')
|
||||
self.align = 'right'
|
||||
|
||||
# Init the stats
|
||||
self.reset()
|
||||
@ -61,16 +61,15 @@ class Plugin(GlancesPlugin):
|
||||
# Reset stats
|
||||
self.reset()
|
||||
|
||||
if self.get_input() == 'local':
|
||||
if self.input_method == 'local':
|
||||
# Update stats using the standard system lib
|
||||
uptime = datetime.now() - \
|
||||
datetime.fromtimestamp(psutil.boot_time())
|
||||
uptime = datetime.now() - datetime.fromtimestamp(psutil.boot_time())
|
||||
|
||||
# Convert uptime to string (because datetime is not JSONifi)
|
||||
self.stats = str(uptime).split('.')[0]
|
||||
elif self.get_input() == 'snmp':
|
||||
elif self.input_method == 'snmp':
|
||||
# Update stats using SNMP
|
||||
uptime = self.set_stats_snmp(snmp_oid=snmp_oid)['_uptime']
|
||||
uptime = self.get_stats_snmp(snmp_oid=snmp_oid)['_uptime']
|
||||
try:
|
||||
# In hundredths of seconds
|
||||
self.stats = str(timedelta(seconds=int(uptime) / 100))
|
||||
@ -82,11 +81,4 @@ class Plugin(GlancesPlugin):
|
||||
|
||||
def msg_curse(self, args=None):
|
||||
"""Return the string to display in the curse interface."""
|
||||
# Init the return message
|
||||
ret = []
|
||||
|
||||
# Add the line with decoration
|
||||
ret.append(self.curse_add_line(_("Uptime: {0}").format(self.stats)))
|
||||
|
||||
# Return the message with decoration
|
||||
return ret
|
||||
return [self.curse_add_line(_("Uptime: {0}").format(self.stats))]
|
||||
|
@ -49,6 +49,10 @@ disable network module
|
||||
.B \-\-disable-sensors
|
||||
disable sensors module
|
||||
.TP
|
||||
.B \-\-disable-hddtemp
|
||||
disable HDDTemp module
|
||||
.TP
|
||||
.TP
|
||||
.B \-\-disable-left-sidebar
|
||||
disable network, disk IO, FS and sensors modules
|
||||
.TP
|
||||
@ -121,6 +125,12 @@ set refresh time in seconds [default: 3 sec]
|
||||
.B \-w, \-\-webserver
|
||||
run Glances in Web server mode
|
||||
.TP
|
||||
.B \-q, \-\-quiet
|
||||
run Glances in quiet mode (nothing is displayed)
|
||||
.TP
|
||||
.B -\f PROCESS_FILTER, \-\-process\-filter PROCESS_FILTER
|
||||
set the process filter patern (regular expression)
|
||||
.TP
|
||||
.B \-1, \-\-percpu
|
||||
start Glances in per CPU mode
|
||||
.TP
|
||||
@ -210,9 +220,31 @@ Show/hide processes list (for low CPU consumption)
|
||||
Switch between global CPU and per-CPU stats
|
||||
.SH EXAMPLES
|
||||
.TP
|
||||
Refresh information every 5 seconds:
|
||||
.B glances
|
||||
\-t 5
|
||||
Monitor local machine (standalone mode):
|
||||
.B $ glances
|
||||
.PP
|
||||
Monitor local machine with the Web interface (Web UI):
|
||||
.B $ glances -w
|
||||
.PP
|
||||
Glances web server started on http://0.0.0.0:61208/
|
||||
.PP
|
||||
Monitor local machine and export stats to a CSV file (standalone mode):
|
||||
.B $ glances --export-csv
|
||||
.PP
|
||||
Monitor local machine and export stats to a InfluxDB server with 5s refresh time (standalone mode):
|
||||
.B $ glances -t 5 --export-influxdb
|
||||
.PP
|
||||
Start a Glances server (server mode):
|
||||
.B $ glances -s
|
||||
.PP
|
||||
Connect Glances to a Glances server (client mode):
|
||||
.B $ glances -c <ip_server>
|
||||
.PP
|
||||
Connect Glances to a Glances server and export stats to a StatsD server (client mode):
|
||||
.B $ glances -c <ip_server> --export-statsd
|
||||
.PP
|
||||
Start the client browser (browser mode):
|
||||
.B $ glances --browser
|
||||
.PP
|
||||
.SH EXIT STATUS
|
||||
Glances returns a zero exit status if it succeeds to print/grab information.
|
||||
|
@ -1 +1 @@
|
||||
psutil==2.2.0
|
||||
psutil==2.2.1
|
||||
|
10
setup.py
10
setup.py
@ -8,6 +8,9 @@ from setuptools import setup
|
||||
|
||||
is_chroot = os.stat('/').st_ino != 2
|
||||
|
||||
if sys.version_info < (2, 6) or (3, 0) <= sys.version_info < (3, 3):
|
||||
print('Glances requires at least Python 2.6 or 3.3 to run.')
|
||||
sys.exit(1)
|
||||
|
||||
def get_data_files():
|
||||
data_files = [
|
||||
@ -31,7 +34,6 @@ def get_data_files():
|
||||
conf_path = os.path.join(os.environ.get('APPDATA'), 'glances')
|
||||
else: # Unix-like + per-user install
|
||||
conf_path = os.path.join('etc', 'glances')
|
||||
|
||||
data_files.append((conf_path, ['conf/glances.conf']))
|
||||
|
||||
for mo in glob.glob('i18n/*/LC_MESSAGES/*.mo'):
|
||||
@ -45,8 +47,8 @@ def get_requires():
|
||||
requires = ['psutil>=2.0.0']
|
||||
if sys.platform.startswith('win'):
|
||||
requires += ['colorconsole']
|
||||
if sys.version_info < (2, 7):
|
||||
requires += ['argparse']
|
||||
if sys.version_info == (2, 6):
|
||||
requires += ['argparse', 'logutils']
|
||||
|
||||
return requires
|
||||
|
||||
@ -71,7 +73,7 @@ setup(
|
||||
'BROWSER': ['zeroconf>=0.16', 'netifaces'],
|
||||
'RAID': ['pymdstat'],
|
||||
'DOCKER': ['docker-py'],
|
||||
'EXPORT': ['influxdb', 'statsd'],
|
||||
'EXPORT': ['influxdb>=1.0.0', 'statsd'],
|
||||
'ACTION': ['pystache']
|
||||
},
|
||||
packages=['glances'],
|
||||
|
@ -1,7 +1,7 @@
|
||||
# Required metadata
|
||||
sonar.projectKey=glances
|
||||
sonar.projectName=Glances
|
||||
sonar.projectVersion=2.3_beta
|
||||
sonar.projectVersion=2.4_beta
|
||||
|
||||
# Path to the parent source code directory.
|
||||
# Path is relative to the sonar-project.properties file. Replace "\" by "/" on Windows.
|
||||
@ -17,4 +17,4 @@ sonar.language=py
|
||||
sonar.sourceEncoding=UTF-8
|
||||
|
||||
# Additional parameters
|
||||
#sonar.my.property=value
|
||||
#sonar.my.property=value
|
||||
|
@ -91,7 +91,7 @@ class TestGlances(unittest.TestCase):
|
||||
args = shlex.split(cmdline)
|
||||
pid = subprocess.Popen(args)
|
||||
print("Please wait...")
|
||||
time.sleep(1)
|
||||
time.sleep(3)
|
||||
|
||||
self.assertTrue(pid is not None)
|
||||
|
||||
|
@ -78,14 +78,14 @@ class TestGlances(unittest.TestCase):
|
||||
print('INFO: [TEST_000] Test the stats update function')
|
||||
try:
|
||||
stats.update()
|
||||
except:
|
||||
print('ERROR: Stats update failed')
|
||||
except Exception as e:
|
||||
print('ERROR: Stats update failed ({})'.format(e))
|
||||
self.assertTrue(False)
|
||||
time.sleep(1)
|
||||
try:
|
||||
stats.update()
|
||||
except:
|
||||
print('ERROR: Stats update failed')
|
||||
except Exception as e:
|
||||
print('ERROR: Stats update failed ({})'.format(e))
|
||||
self.assertTrue(False)
|
||||
|
||||
self.assertTrue(True)
|
||||
|
Loading…
Reference in New Issue
Block a user