diff options
44 files changed, 801 insertions, 160 deletions
@@ -2,6 +2,33 @@ Glances Version 2 ============================================================================== +Version 2.10 +============ + +Enhancements and new features: + + * New plugin to scan remote Web sites (URL) (issue #981) + * Add trends in the Curses interface (issue #1077) + * Add new repeat function to the action (issue #952) + * Use -> and <- arrows keys to switch between processing sort (issue #1075) + * Refactor __init__ and main scripts (issue #1050) + * [WebUI] Improve WebUI for Windows 10 (issue #1052) + +Bugs corrected: + + * StatsD export prefix option is ignored (issue #1074) + * Some FS and LAN metrics fail to export correctly to StatsD (issue #1068) + * Problem with non breaking space in file system name (issue #1065) + * TypeError: string indices must be integers (Network plugin) (issue #1054) + * No Offline status for timeouted ports? (issue #1084) + * When exporting, uptime values loop after 1 day (issue #1092) + +Installation: + + * Create a package.sh script to generate .DEB, .RPM and others... (issue #722) + ==> https://github.com/nicolargo/glancesautopkg + * OSX: can't python setup.py install due to python 3.5 constraint (issue #1064) + Version 2.9.1 ============= @@ -9,7 +36,7 @@ Bugs corrected: * Glances PerCPU issues with Curses UI on Android (issue #1071) * Remove extra } in format string (issue #1073) - + Version 2.9.0 ============= @@ -265,6 +265,7 @@ Start Termux on your device and enter: $ apt update $ apt upgrade $ apt install clang python python-dev + $ pip install bottle $ pip install glances And start Glances: @@ -273,6 +274,9 @@ And start Glances: $ glances +You can also run Glances in server mode (-s or -w) in order to remotely +monitor your Android device. + Source ------ @@ -374,7 +378,6 @@ LGPLv3. See ``COPYING`` for more details. .. _psutil: https://github.com/giampaolo/psutil .. _glancesautoinstall: https://github.com/nicolargo/glancesautoinstall .. _@nicolargo: https://twitter.com/nicolargo -.. _@glances_system: https://twitter.com/glances_system .. _Python: https://www.python.org/getit/ .. _Termux: https://play.google.com/store/apps/details?id=com.termux .. _readthedocs: https://glances.readthedocs.io/ diff --git a/conf/glances.conf b/conf/glances.conf index 013b8067..a7dc1cb4 100644 --- a/conf/glances.conf +++ b/conf/glances.conf @@ -87,6 +87,7 @@ mem_critical=90 # Define RAM thresholds in % # Default values if not defined: 50/70/90 careful=50 +#careful_action_repeat=echo {{percent}} >> /tmp/memory.alert warning=70 critical=90 @@ -141,9 +142,10 @@ careful=-65 warning=-75 critical=-85 -#[diskio] +[diskio] # Define the list of hidden disks (comma-separated regexp) #hide=sda2,sda5,loop.* +hide=loop.* # Alias for sda1 #sda1_alias=IntDisk @@ -217,12 +219,14 @@ refresh=30 timeout=3 # If port_default_gateway is True, add the default gateway on top of the scan list port_default_gateway=True +# # Define the scan list (1 < x < 255) # port_x_host (name or IP) is mandatory # port_x_port (TCP port number) is optional (if not set, use ICMP) # port_x_description is optional (if not set, define to host:port) # port_x_timeout is optional and overwrite the default timeout value # port_x_rtt_warning is optional and defines the warning threshold in ms +# #port_1_host=192.168.0.1 #port_1_port=80 #port_1_description=Home Box @@ -232,10 +236,25 @@ port_default_gateway=True #port_3_host=www.google.com #port_3_description=Internet ICMP #port_3_rtt_warning=1000 -#port_4_host=www.google.com #port_4_description=Internet Web +#port_4_host=www.google.com #port_4_port=80 #port_4_rtt_warning=1000 +# +# Define Web (URL) monitoring list (1 < x < 255) +# web_x_url is the URL to monitor (example: http://my.site.com/folder) +# web_x_description is optional (if not set, define to URL) +# web_x_timeout is optional and overwrite the default timeout value +# web_x_rtt_warning is optional and defines the warning respond time in ms (approximatively) +# +#web_1_url=https://blog.nicolargo.com +#web_1_description=My Blog +#web_1_rtt_warning=3000 +#web_2_url=https://github.com +#web_3_url=http://www.google.fr +#web_3_description=Google Fr +#web_4_url=https://blog.nicolargo.com/nonexist +#web_4_description=Intranet [docker] # Thresholds for CPU and MEM (in %) diff --git a/docs/_static/cpu-wide.png b/docs/_static/cpu-wide.png Binary files differindex 1046b7d8..53c2a95b 100644 --- a/docs/_static/cpu-wide.png +++ b/docs/_static/cpu-wide.png diff --git a/docs/_static/cpu.png b/docs/_static/cpu.png Binary files differindex 7fa618a1..d034c180 100644 --- a/docs/_static/cpu.png +++ b/docs/_static/cpu.png diff --git a/docs/_static/mem-wide.png b/docs/_static/mem-wide.png Binary files differindex 838b959d..60a6bece 100644 --- a/docs/_static/mem-wide.png +++ b/docs/_static/mem-wide.png diff --git a/docs/_static/mem.png b/docs/_static/mem.png Binary files differindex aaf90ac4..df79d0da 100644 --- a/docs/_static/mem.png +++ b/docs/_static/mem.png diff --git a/docs/_static/ports.png b/docs/_static/ports.png Binary files differindex 03edf63d..f65c8453 100644 --- a/docs/_static/ports.png +++ b/docs/_static/ports.png diff --git a/docs/_static/trend.png b/docs/_static/trend.png Binary files differnew file mode 100644 index 00000000..7cf0cff4 --- /dev/null +++ b/docs/_static/trend.png diff --git a/docs/aoa/actions.rst b/docs/aoa/actions.rst index 5ce40bcd..b83f1737 100644 --- a/docs/aoa/actions.rst +++ b/docs/aoa/actions.rst @@ -31,4 +31,14 @@ reached: https://github.com/nicolargo/glances/wiki/The-Glances-2.x-API-How-to for the stats list. +It is also possible to repeat action until the end of the alert. +Keep in mind that the command line is executed every refresh time so +use with caution: + +.. code-block:: ini + + [load] + critical=5.0 + critical_action_repeat=/home/myhome/bin/bipper.sh + .. _{{mustache}}: https://mustache.github.io/ diff --git a/docs/aoa/cpu.rst b/docs/aoa/cpu.rst index ead6a0df..d112d795 100644 --- a/docs/aoa/cpu.rst +++ b/docs/aoa/cpu.rst @@ -3,8 +3,10 @@ CPU === -The CPU stats are shown as a percentage or value and for the configured -refresh time. The total CPU usage is displayed on the first line. +The CPU stats are shown as a percentage or values and for the configured +refresh time. + +The total CPU usage is displayed on the first line. .. image:: ../_static/cpu.png @@ -13,6 +15,17 @@ displayed. .. image:: ../_static/cpu-wide.png +A character is also displayed just after the CPU header and shows the +trend value: + +======== ============================================================== +Trend Status +======== ============================================================== +``-`` CPU value is equal to the mean of the six latests refreshes +``\`` CPU value is lower than the mean of the six latests refreshes +``/`` CPU value is higher than the mean of the six latests refreshes +======== ============================================================== + CPU stats description: - **user**: percent time spent in user space. User CPU time is the time diff --git a/docs/aoa/memory.rst b/docs/aoa/memory.rst index 0cd6afc8..05b3df87 100644 --- a/docs/aoa/memory.rst +++ b/docs/aoa/memory.rst @@ -12,6 +12,17 @@ the ``RAM``: .. image:: ../_static/mem-wide.png +A character is also displayed just after the MEM header and shows the +trend value: + +======== ============================================================== +Trend Status +======== ============================================================== +``-`` MEM value is equal to the mean of the six latests refreshes +``\`` MEM value is lower than the mean of the six latests refreshes +``/`` MEM value is higher than the mean of the six latests refreshes +======== ============================================================== + Alerts are only set for used memory and used swap. Legend: diff --git a/docs/aoa/ports.rst b/docs/aoa/ports.rst index 4534dfa9..54353891 100644 --- a/docs/aoa/ports.rst +++ b/docs/aoa/ports.rst @@ -7,9 +7,9 @@ Ports .. image:: ../_static/ports.png -This plugin aims at providing a list of hosts/port to scan. +This plugin aims at providing a list of hosts/port and URL to scan. -You can define ``ICMP`` or ``TCP`` ports scan. +You can define ``ICMP`` or ``TCP`` ports scans and URL (head only) check. The list should be defined in the ``[ports]`` section of the Glances configuration file. @@ -24,12 +24,14 @@ configuration file. timeout=3 # If port_default_gateway is True, add the default gateway on top of the scan list port_default_gateway=True + # # Define the scan list (1 < x < 255) # port_x_host (name or IP) is mandatory # port_x_port (TCP port number) is optional (if not set, use ICMP) # port_x_description is optional (if not set, define to host:port) # port_x_timeout is optional and overwrite the default timeout value # port_x_rtt_warning is optional and defines the warning threshold in ms + # port_1_host=192.168.0.1 port_1_port=80 port_1_description=Home Box @@ -43,3 +45,16 @@ configuration file. port_4_description=Internet Web port_4_port=80 port_4_rtt_warning=1000 + # + # Define Web (URL) monitoring list (1 < x < 255) + # web_x_url is the URL to monitor (example: http://my.site.com/folder) + # web_x_description is optional (if not set, define to URL) + # web_x_timeout is optional and overwrite the default timeout value + # web_x_rtt_warning is optional and defines the warning respond time in ms (approximatively) + # + web_1_url=https://blog.nicolargo.com + web_1_description=My Blog + web_1_rtt_warning=3000 + web_2_url=https://github.com + web_3_url=http://www.google.fr + web_3_description=Google Fr diff --git a/docs/man/glances.1 b/docs/man/glances.1 index 1f0b9fb2..8e4bf72f 100644 --- a/docs/man/glances.1 +++ b/docs/man/glances.1 @@ -1,6 +1,6 @@ .\" Man page generated from reStructuredText. . -.TH "GLANCES" "1" "Mar 29, 2017" "2.9.1" "Glances" +.TH "GLANCES" "1" "May 26, 2017" "2.10" "Glances" .SH NAME glances \- An eye on your system . diff --git a/glances/__init__.py b/glances/__init__.py index 8a1d1c79..85942d5f 100644 --- a/glances/__init__.py +++ b/glances/__init__.py @@ -27,7 +27,7 @@ import signal import sys # Global name -__version__ = '2.9.1' +__version__ = '2.10' __author__ = 'Nicolas Hennion <nicolas@nicolargo.com>' __license__ = 'LGPLv3' diff --git a/glances/actions.py b/glances/actions.py index e50376d0..89c9e326 100644 --- a/glances/actions.py +++ b/glances/actions.py @@ -63,21 +63,24 @@ class GlancesActions(object): """Set the stat_name to criticity.""" self.status[stat_name] = criticity - def run(self, stat_name, criticity, commands, mustache_dict=None): + def run(self, stat_name, criticity, commands, repeat, mustache_dict=None): """Run the commands (in background). - stats_name: plugin_name (+ header) - criticity: criticity of the trigger - commands: a list of command line with optional {{mustache}} + - If True, then repeat the action - mustache_dict: Plugin stats (can be use within {{mustache}}) Return True if the commands have been ran. """ - if self.get(stat_name) == criticity or not self.start_timer.finished(): + if (self.get(stat_name) == criticity and not repeat) or \ + not self.start_timer.finished(): # Action already executed => Exit return False - logger.debug("Run action {} for {} ({}) with stats {}".format( + logger.debug("{} action {} for {} ({}) with stats {}".format( + "Repeat" if repeat else "Run", commands, stat_name, criticity, mustache_dict)) # Run all actions in background diff --git a/glances/attribute.py b/glances/attribute.py index 5f008650..41b9c8b0 100644 --- a/glances/attribute.py +++ b/glances/attribute.py @@ -126,6 +126,10 @@ class GlancesAttribute(object): """ return self._history[-pos] + def history_raw(self, nb=0): + """Return the history of last nb items (0 for all) In ISO JSON format""" + return self._history[-nb:] + def history_json(self, nb=0): """Return the history of last nb items (0 for all) In ISO JSON format""" return [(i[0].isoformat(), i[1]) for i in self._history[-nb:]] diff --git a/glances/compat.py b/glances/compat.py index bfec1433..f11ce3ca 100644 --- a/glances/compat.py +++ b/glances/compat.py @@ -28,6 +28,13 @@ import types PY3 = sys.version_info[0] == 3 +try: + from statistics import mean +except ImportError: + # Statistics is only available for Python 3.4 or higher + def mean(numbers): + return float(sum(numbers)) / max(len(numbers), 1) + if PY3: import queue from configparser import ConfigParser, NoOptionError, NoSectionError @@ -35,6 +42,7 @@ if PY3: from xmlrpc.server import SimpleXMLRPCRequestHandler, SimpleXMLRPCServer from urllib.request import urlopen from urllib.error import HTTPError, URLError + from urllib.parse import urlparse input = input range = range @@ -90,6 +98,7 @@ else: from SimpleXMLRPCServer import SimpleXMLRPCRequestHandler, SimpleXMLRPCServer from xmlrpclib import Fault, ProtocolError, ServerProxy, Transport, Server from urllib2 import urlopen, HTTPError, URLError + from urlparse import urlparse input = raw_input range = xrange diff --git a/glances/exports/glances_export.py b/glances/exports/glances_export.py index e47f773b..b402ea2e 100644 --- a/glances/exports/glances_export.py +++ b/glances/exports/glances_export.py @@ -122,9 +122,9 @@ class GlancesExport(object): def parse_tags(self, tags): """Parse tags into a dict. - tags: a comma separated list of 'key:value' pairs. + input tags: a comma separated list of 'key:value' pairs. Example: foo:bar,spam:eggs - dtags: a dict of tags. + output dtags: a dict of tags. Example: {'foo': 'bar', 'spam': 'eggs'} """ dtags = {} @@ -158,7 +158,9 @@ class GlancesExport(object): if isinstance(all_stats[plugin], dict): all_stats[plugin].update(all_limits[plugin]) elif isinstance(all_stats[plugin], list): - all_stats[plugin] += all_limits[plugin] + # TypeError: string indices must be integers (Network plugin) #1054 + for i in all_stats[plugin]: + i.update(all_limits[plugin]) else: continue export_names, export_values = self.__build_export(all_stats[plugin]) diff --git a/glances/exports/glances_statsd.py b/glances/exports/glances_statsd.py index db7628a0..4ab88e9c 100644 --- a/glances/exports/glances_statsd.py +++ b/glances/exports/glances_statsd.py @@ -57,7 +57,7 @@ class Export(GlancesExport): # Init the Statsd client self.client = self.init() - def init(self, prefix='glances'): + def init(self): """Init the connection to the Statsd server.""" if not self.export_enable: return None @@ -66,7 +66,7 @@ class Export(GlancesExport): self.port)) return StatsClient(self.host, int(self.port), - prefix=prefix) + prefix=self.prefix) def export(self, name, columns, points): """Export the stats to the Statsd server.""" @@ -76,7 +76,19 @@ class Export(GlancesExport): stat_name = '{}.{}'.format(name, columns[i]) stat_value = points[i] try: - self.client.gauge(stat_name, stat_value) + self.client.gauge(normalize(stat_name), + stat_value) except Exception as e: logger.error("Can not export stats to Statsd (%s)" % e) logger.debug("Export {} stats to Statsd".format(name)) + + +def normalize(name): + """Normalize name for the Statsd convention""" + + # Name should not contain some specials chars (issue #1068) + ret = name.replace(':', '') + ret = ret.replace('%', '') + ret = ret.replace(' ', '_') + + return ret diff --git a/glances/history.py b/glances/history.py index ff222328..433f15df 100644 --- a/glances/history.py +++ b/glances/history.py @@ -49,9 +49,9 @@ class GlancesHistory(object): for a in self.stats_history: self.stats_history[a].history_reset() - def get(self): + def get(self, nb=0): """Get the history as a dict of list""" - return {i: self.stats_history[i].history for i in self.stats_history} + return {i: self.stats_history[i].history_raw(nb=nb) for i in self.stats_history} def get_json(self, nb=0): """Get the history as a dict of list (with list JSON compliant)""" diff --git a/glances/outputs/glances_curses.py b/glances/outputs/glances_curses.py index 3234775a..5416e5be 100644 --- a/glances/outputs/glances_curses.py +++ b/glances/outputs/glances_curses.py @@ -82,9 +82,11 @@ class _GlancesCurses(object): 'm': {'auto_sort': False, 'sort_key': 'memory_percent'}, 'p': {'auto_sort': False, 'sort_key': 'name'}, 't': {'auto_sort': False, 'sort_key': 'cpu_times'}, - 'u': {'auto_sort': False, 'sort_key': 'username'} + 'u': {'auto_sort': False, 'sort_key': 'username'}, } + _sort_loop = ['cpu_percent', 'memory_percent', 'username', 'cpu_times', 'io_counters', 'name'] + def __init__(self, config=None, args=None): # Init self.config = config @@ -130,7 +132,7 @@ class _GlancesCurses(object): self.args.reset_minmax_tag = False # Catch key pressed with non blocking mode - self.no_flash_cursor() + self.term_window.keypad(1) self.term_window.nodelay(1) self.pressedkey = -1 @@ -284,12 +286,6 @@ class _GlancesCurses(object): 'PASSWORD': curses.A_PROTECT } - def flash_cursor(self): - self.term_window.keypad(1) - - def no_flash_cursor(self): - self.term_window.keypad(0) - def set_cursor(self, value): """Configure the curse cursor apparence. @@ -395,10 +391,27 @@ class _GlancesCurses(object): glances_processes.disable() else: glances_processes.enable() + elif self.pressedkey == curses.KEY_LEFT: + # "<" (left arrow) navigation through process sort + setattr(glances_processes, 'auto_sort', False) + next_sort = (self.loop_position() - 1) % len(self._sort_loop) + glances_processes.sort_key = self._sort_loop[next_sort] + elif self.pressedkey == curses.KEY_RIGHT: + # ">" (right arrow) navigation through process sort + setattr(glances_processes, 'auto_sort', False) + next_sort = (self.loop_position() + 1) % len(self._sort_loop) + glances_processes.sort_key = self._sort_loop[next_sort] # Return the key code return self.pressedkey + def loop_position(self): + """Return the current sort in the loop""" + for i, v in enumerate(self._sort_loop): + if v == glances_processes.sort_key: + return i + return 0 + def disable_top(self): """Disable the top panel""" for p in ['quicklook', 'cpu', 'gpu', 'mem', 'memswap', 'load']: @@ -816,11 +829,11 @@ class _GlancesCurses(object): subpop.refresh() # Create the textbox inside the subwindows self.set_cursor(2) - self.flash_cursor() + self.term_window.keypad(1) textbox = GlancesTextbox(subpop, insert_mode=False) textbox.edit() self.set_cursor(0) - self.no_flash_cursor() + self.term_window.keypad(0) if textbox.gather() != '': logger.debug( "User enters the following string: %s" % textbox.gather()) diff --git a/glances/outputs/static/html/plugins/cpu.html b/glances/outputs/static/html/plugins/cpu.html index 82315ff9..53175592 100644 --- a/glances/outputs/static/html/plugins/cpu.html +++ b/glances/outputs/static/html/plugins/cpu.html @@ -25,7 +25,7 @@ </div> <div class="hidden-xs hidden-sm col-md-12 col-lg-8"> <div class="table"> - <div class="table-row"> + <div class="tab |