From 3b11856926d9d512ba749033e67c326fb619fa3a Mon Sep 17 00:00:00 2001 From: nicolargo Date: Sun, 24 Nov 2019 17:40:02 +0100 Subject: Feature request: HDD S.M.A.R.T. reports #1288 (only terminal UI) --- conf/glances.conf | 17 ++++++++-- docs/aoa/amps.rst | 2 +- docs/aoa/disk.rst | 31 ------------------ docs/aoa/diskio.rst | 31 ++++++++++++++++++ docs/aoa/index.rst | 8 +++-- docs/aoa/irq.rst | 2 +- docs/aoa/quicklook.rst | 2 ++ docs/aoa/wifi.rst | 2 +- glances/compat.py | 25 +++++++++++++++ glances/outputs/glances_curses.py | 20 ++++++------ glances/plugins/glances_raid.py | 2 +- glances/plugins/glances_smart.py | 67 ++++++++++++++++++++++----------------- unitest.py | 2 +- 13 files changed, 130 insertions(+), 81 deletions(-) delete mode 100644 docs/aoa/disk.rst create mode 100644 docs/aoa/diskio.rst diff --git a/conf/glances.conf b/conf/glances.conf index a69a1192..5a177068 100644 --- a/conf/glances.conf +++ b/conf/glances.conf @@ -186,7 +186,13 @@ critical=90 # Allow additional file system types (comma-separated FS type) #allow=zfs +[irq] +# Documentation: https://glances.readthedocs.io/en/stable/aoa/irq.html +# This plugin is disabled by default +disable=True + [folders] +# Documentation: https://glances.readthedocs.io/en/stable/aoa/folders.html disable=False # Define a folder list to monitor # The list is composed of items (list_#nb <= 10) @@ -207,10 +213,15 @@ disable=False #folder_3_path=/nonexisting #folder_4_path=/root -[irq] +[raid] +# Documentation: https://glances.readthedocs.io/en/stable/aoa/raid.html # This plugin is disabled by default -# Documentation: https://glances.readthedocs.io/en/stable/aoa/irq.html -disable=False +disable=True + +[smart] +# Documentation: https://glances.readthedocs.io/en/stable/aoa/smart.html +# This plugin is disabled by default +disable=True [hddtemp] disable=False diff --git a/docs/aoa/amps.rst b/docs/aoa/amps.rst index 85518f86..e32d6192 100644 --- a/docs/aoa/amps.rst +++ b/docs/aoa/amps.rst @@ -6,7 +6,7 @@ Applications Monitoring Process Thanks to Glances and its AMP module, you can add specific monitoring to running processes. AMPs are defined in the Glances [configuration file](http://glances.readthedocs.io/en/stable/config.html). -You can disable AMP using the ``--disable-amps`` option or pressing the +You can disable AMP using the ``--disable-plugin amps`` option or pressing the ``A`` key. Simple AMP diff --git a/docs/aoa/disk.rst b/docs/aoa/disk.rst deleted file mode 100644 index f6d03ffe..00000000 --- a/docs/aoa/disk.rst +++ /dev/null @@ -1,31 +0,0 @@ -.. _disk: - -Disk I/O -======== - -.. image:: ../_static/diskio.png - -Glances displays the disk I/O throughput. The unit is adapted -dynamically. - -You can display: - -- bytes per second (default behavor / Bytes/s, KBytes/s, MBytes/s, etc) -- requests per second (using --diskio-iops option or *B* hotkey) - -There is no alert on this information. - -It's possible to define: - -- a list of disks to hide -- aliases for disk name - -under the ``[diskio]`` section in the configuration file. - -For example, if you want to hide the loopback disks (loop0, loop1, ...) -and the specific ``sda5`` partition: - -.. code-block:: ini - - [diskio] - hide=sda5,loop.* diff --git a/docs/aoa/diskio.rst b/docs/aoa/diskio.rst new file mode 100644 index 00000000..f6d03ffe --- /dev/null +++ b/docs/aoa/diskio.rst @@ -0,0 +1,31 @@ +.. _disk: + +Disk I/O +======== + +.. image:: ../_static/diskio.png + +Glances displays the disk I/O throughput. The unit is adapted +dynamically. + +You can display: + +- bytes per second (default behavor / Bytes/s, KBytes/s, MBytes/s, etc) +- requests per second (using --diskio-iops option or *B* hotkey) + +There is no alert on this information. + +It's possible to define: + +- a list of disks to hide +- aliases for disk name + +under the ``[diskio]`` section in the configuration file. + +For example, if you want to hide the loopback disks (loop0, loop1, ...) +and the specific ``sda5`` partition: + +.. code-block:: ini + + [diskio] + hide=sda5,loop.* diff --git a/docs/aoa/index.rst b/docs/aoa/index.rst index 93d7db44..571e9410 100644 --- a/docs/aoa/index.rst +++ b/docs/aoa/index.rst @@ -24,16 +24,18 @@ Legend: quicklook cpu gpu - load memory + load network connections wifi ports - disk + diskio fs - folders irq + folders + raid + smart sensors ps monitor diff --git a/docs/aoa/irq.rst b/docs/aoa/irq.rst index 9a9a55a7..6fbc868f 100644 --- a/docs/aoa/irq.rst +++ b/docs/aoa/irq.rst @@ -5,7 +5,7 @@ IRQ *Availability: Linux* -This plugin is disable by default, please use the --enable-irq option +This plugin is disable by default, please use the --enable irq option to enable it. .. image:: ../_static/irq.png diff --git a/docs/aoa/quicklook.rst b/docs/aoa/quicklook.rst index 69e47427..a7cad3ee 100644 --- a/docs/aoa/quicklook.rst +++ b/docs/aoa/quicklook.rst @@ -6,6 +6,8 @@ Quick Look The ``quicklook`` plugin is only displayed on wide screen and proposes a bar view for CPU and memory (virtual and swap). +In the terminal interface, click on ``3`` to enable/disable it. + .. image:: ../_static/quicklook.png If the per CPU mode is on (by clicking the ``1`` key): diff --git a/docs/aoa/wifi.rst b/docs/aoa/wifi.rst index 9e44d062..deb71fbc 100644 --- a/docs/aoa/wifi.rst +++ b/docs/aoa/wifi.rst @@ -32,5 +32,5 @@ hide the loopback interface (lo) and all the virtual docker interfaces: warning=-75 critical=-85 -You can disable this plugin using the ``--disable-wifi`` option or by +You can disable this plugin using the ``--disable-plugin wifi`` option or by hitting the ``W`` key from the user interface. diff --git a/glances/compat.py b/glances/compat.py index cac531f1..e16e8286 100644 --- a/glances/compat.py +++ b/glances/compat.py @@ -28,6 +28,7 @@ import sys import unicodedata import types import subprocess +import os from glances.logger import logger @@ -239,3 +240,27 @@ def time_serie_subsample(data, sampling): def to_fahrenheit(celsius): """Convert Celsius to Fahrenheit.""" return celsius * 1.8 + 32 + + +def is_admin(): + """ + https://stackoverflow.com/a/19719292 + @return: True if the current user is an 'Admin' whatever that + means (root on Unix), otherwise False. + Warning: The inner function fails unless you have Windows XP SP2 or + higher. The failure causes a traceback to be printed and this + function to return False. + """ + + if os.name == 'nt': + import ctypes + import traceback + # WARNING: requires Windows XP SP2 or higher! + try: + return ctypes.windll.shell32.IsUserAnAdmin() + except Exception as e: + traceback.print_exc() + return False + else: + # Check for root on Posix + return os.getuid() == 0 diff --git a/glances/outputs/glances_curses.py b/glances/outputs/glances_curses.py index ec1afdf4..a1e00d2d 100644 --- a/glances/outputs/glances_curses.py +++ b/glances/outputs/glances_curses.py @@ -55,38 +55,38 @@ class _GlancesCurses(object): '3': {'switch': 'disable_quicklook'}, '6': {'switch': 'meangpu'}, '/': {'switch': 'process_short_name'}, + 'a': {'sort_key': 'auto'}, 'A': {'switch': 'disable_amps'}, 'b': {'switch': 'byte'}, 'B': {'switch': 'diskio_iops'}, + 'c': {'sort_key': 'cpu_percent'}, 'C': {'switch': 'disable_cloud'}, - 'D': {'switch': 'disable_docker'}, 'd': {'switch': 'disable_diskio'}, + 'D': {'switch': 'disable_docker'}, 'F': {'switch': 'fs_free_space'}, 'g': {'switch': 'generate_graph'}, 'G': {'switch': 'disable_gpu'}, 'h': {'switch': 'help_tag'}, + 'i': {'sort_key': 'io_counters'}, 'I': {'switch': 'disable_ip'}, 'k': {'switch': 'disable_connections'}, 'l': {'switch': 'disable_alert'}, + 'm': {'sort_key': 'memory_percent'}, 'M': {'switch': 'reset_minmax_tag'}, 'n': {'switch': 'disable_network'}, 'N': {'switch': 'disable_now'}, + 'p': {'sort_key': 'name'}, 'P': {'switch': 'disable_ports'}, 'Q': {'switch': 'enable_irq'}, + 'r': {'switch': 'disable_smart'}, 'R': {'switch': 'disable_raid'}, 's': {'switch': 'disable_sensors'}, 'S': {'switch': 'sparkline'}, + 't': {'sort_key': 'cpu_times'}, 'T': {'switch': 'network_sum'}, + 'u': {'sort_key': 'username'}, 'U': {'switch': 'network_cumul'}, 'W': {'switch': 'disable_wifi'}, - # Processes sort hotkeys - 'a': {'sort_key': 'auto'}, - 'c': {'sort_key': 'cpu_percent'}, - 'i': {'sort_key': 'io_counters'}, - 'm': {'sort_key': 'memory_percent'}, - 'p': {'sort_key': 'name'}, - 't': {'sort_key': 'cpu_times'}, - 'u': {'sort_key': 'username'}, } _sort_loop = ['cpu_percent', 'memory_percent', 'username', @@ -98,7 +98,7 @@ class _GlancesCurses(object): # Define left sidebar _left_sidebar = ['network', 'connections', 'wifi', 'ports', 'diskio', 'fs', - 'irq', 'folders', 'raid', 'sensors', 'now'] + 'irq', 'folders', 'raid', 'smart', 'sensors', 'now'] _left_sidebar_min_width = 23 _left_sidebar_max_width = 34 diff --git a/glances/plugins/glances_raid.py b/glances/plugins/glances_raid.py index 7e5275b2..795812e7 100644 --- a/glances/plugins/glances_raid.py +++ b/glances/plugins/glances_raid.py @@ -83,7 +83,7 @@ class Plugin(GlancesPlugin): ret = [] # Only process if stats exist... - if not self.stats: + if not self.stats or self.is_disable(): return ret # Max size for the interface name diff --git a/glances/plugins/glances_smart.py b/glances/plugins/glances_smart.py index f0291cad..445942cb 100644 --- a/glances/plugins/glances_smart.py +++ b/glances/plugins/glances_smart.py @@ -47,7 +47,7 @@ If smartmontools is not installed, we should catch the error upstream in plugin from glances.plugins.glances_plugin import GlancesPlugin from glances.logger import logger from glances.main import disable -import os +from glances.compat import is_admin # Import plugin specific dependency try: @@ -58,35 +58,10 @@ except ImportError as e: else: import_error_tag = False -DEVKEY = "DeviceName" - - -def is_admin(): - """ - https://stackoverflow.com/a/19719292 - @return: True if the current user is an 'Admin' whatever that - means (root on Unix), otherwise False. - Warning: The inner function fails unless you have Windows XP SP2 or - higher. The failure causes a traceback to be printed and this - function to return False. - """ - - if os.name == 'nt': - import ctypes - import traceback - # WARNING: requires Windows XP SP2 or higher! - try: - return ctypes.windll.shell32.IsUserAnAdmin() - except: - traceback.print_exc() - return False - else: - # Check for root on Posix - return os.getuid() == 0 - def convert_attribute_to_dict(attr): return { + 'name': attr.name, 'num': attr.num, 'flags': attr.flags, 'raw': attr.raw, @@ -114,6 +89,7 @@ def get_smart_data(): "raw": "..", etc, } + ... } ] """ @@ -123,7 +99,7 @@ def get_smart_data(): for dev in devlist.devices: stats.append({ - DEVKEY: str(dev) + 'DeviceName': '{} {}'.format(dev.name, dev.model), }) for attribute in dev.attributes: if attribute is None: @@ -187,4 +163,37 @@ class Plugin(GlancesPlugin): def get_key(self): """Return the key of the list.""" - return DEVKEY + return 'DeviceName' + + def msg_curse(self, args=None, max_width=None): + """Return the dict to display in the curse interface.""" + # Init the return message + ret = [] + + # Only process if stats exist... + if not self.stats or self.is_disable(): + return ret + + # Max size for the interface name + name_max_width = max_width - 6 + + # Header + msg = '{:{width}}'.format('SMART disks', + width=name_max_width) + ret.append(self.curse_add_line(msg, "TITLE")) + # Data + for device_stat in self.stats: + # New line + ret.append(self.curse_new_line()) + msg = '{:{width}}'.format(device_stat['DeviceName'][:max_width], + width=max_width) + ret.append(self.curse_add_line(msg)) + for smart_stat in sorted([i for i in device_stat.keys() if i != 'DeviceName'], key=int): + ret.append(self.curse_new_line()) + msg = ' {:{width}}'.format(device_stat[smart_stat]['name'][:name_max_width-1].replace('_', ' '), + width=name_max_width-1) + ret.append(self.curse_add_line(msg)) + msg = '{:>8}'.format(device_stat[smart_stat]['raw']) + ret.append(self.curse_add_line(msg)) + + return ret diff --git a/unitest.py b/unitest.py index 142997c0..1b15cd1c 100755 --- a/unitest.py +++ b/unitest.py @@ -257,7 +257,7 @@ class TestGlances(unittest.TestCase): def test_016_hddsmart(self): """Check hard disk SMART data plugin.""" try: - from glances.plugins.glances_smart import is_admin + from glances.compat import is_admin except ImportError: print("INFO: [TEST_016] pySMART not found, not running SMART plugin test") return -- cgit v1.2.3