diff --git a/glances/outputs/glances_bars.py b/glances/outputs/glances_bars.py index c5c94aba..d3a7bf03 100644 --- a/glances/outputs/glances_bars.py +++ b/glances/outputs/glances_bars.py @@ -62,10 +62,6 @@ class Bar(object): if self.__with_text: return self.__size - 6 - # @size.setter - # def size(self, value): - # self.__size = value - @property def percent(self): return self.__percent diff --git a/glances/outputs/glances_sparklines.py b/glances/outputs/glances_sparklines.py new file mode 100644 index 00000000..c69bddff --- /dev/null +++ b/glances/outputs/glances_sparklines.py @@ -0,0 +1,85 @@ +# -*- coding: utf-8 -*- +# +# This file is part of Glances. +# +# Copyright (C) 2019 Nicolargo +# +# Glances is free software; you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# Glances is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public License +# along with this program. If not, see . + +"""Manage sparklines for Glances output.""" + +from __future__ import division +from math import modf +from glances.logger import logger + +sparklines_module = True +try: + from sparklines import sparklines +except ImportError as e: + logger.debug("Sparklines module not found ({})".format(e)) + sparklines_module = False + + +class Sparkline(object): + + r"""Manage sparklines (see https://pypi.org/project/sparklines/).""" + + def __init__(self, size, pre_char='[', post_char=']', empty_char=' ', with_text=True): + # If the sparklines python module available ? + self.__available = sparklines_module + # Sparkline size + self.__size = size + # Sparkline current percents list + self.__percent = [] + # Char used for the decoration + self.__pre_char = pre_char + self.__post_char = post_char + self.__empty_char = empty_char + self.__with_text = with_text + + @property + def available(self): + return self.__available + + @property + def size(self, with_decoration=False): + # Return the sparkine size, with or without decoration + if with_decoration: + return self.__size + if self.__with_text: + return self.__size - 6 + + @property + def percents(self): + return self.__percent + + @percents.setter + def percents(self, value): + self.__percent = value + + @property + def pre_char(self): + return self.__pre_char + + @property + def post_char(self): + return self.__post_char + + def get(self): + """Return the sparkline.""" + return sparklines(self.percents)[0].encode('utf8') + + def __str__(self): + """Return the sparkline.""" + return self.get() diff --git a/glances/plugins/glances_quicklook.py b/glances/plugins/glances_quicklook.py index 1c222634..680f0fef 100644 --- a/glances/plugins/glances_quicklook.py +++ b/glances/plugins/glances_quicklook.py @@ -19,9 +19,11 @@ """Quicklook plugin.""" +from glances.compat import nativestr from glances.cpu_percent import cpu_percent from glances.logger import logger from glances.outputs.glances_bars import Bar +from glances.outputs.glances_sparklines import Sparkline from glances.plugins.glances_plugin import GlancesPlugin import psutil @@ -36,6 +38,19 @@ else: cpuinfo_tag = True +# Define the history items list +# All items in this list will be historised if the --enable-history tag is set +items_history_list = [{'name': 'cpu', + 'description': 'CPU percent usage', + 'y_unit': '%'}, + {'name': 'mem', + 'description': 'MEM percent usage', + 'y_unit': '%'}, + {'name': 'swap', + 'description': 'SWAP percent usage', + 'y_unit': '%'}] + + class Plugin(GlancesPlugin): """Glances quicklook plugin. @@ -44,8 +59,8 @@ class Plugin(GlancesPlugin): def __init__(self, args=None): """Init the quicklook plugin.""" - super(Plugin, self).__init__(args=args) - + super(Plugin, self).__init__(args=args, + items_history_list=items_history_list) # We want to display the stat in the curse interface self.display_curse = True @@ -105,8 +120,13 @@ class Plugin(GlancesPlugin): if not self.stats or self.is_disable(): return ret - # Define the bar - bar = Bar(max_width) + # Define the data (Sparkline or Bar) + # Sparkline is the default behavor (see https://github.com/nicolargo/glances/issues/1446) + data = Sparkline(max_width) + sparkline_tag = data.available + if not sparkline_tag: + # Fallback to bar if Sparkline module is not installed + data = Bar(max_width) # Build the string message if 'cpu_name' in self.stats and 'cpu_hz_current' in self.stats and 'cpu_hz' in self.stats: @@ -128,9 +148,15 @@ class Plugin(GlancesPlugin): ret.extend(self._msg_create_line(msg, bar, key)) ret.append(self.curse_new_line()) else: - bar.percent = self.stats[key] + if sparkline_tag: + # Sparkline display an history + logger.info('Size: {}'.format(data.size)) + data.percents = [i[1] for i in self.get_raw_history(item=key, nb=max_width - 6)] + else: + # Bar only the last value + data.percent = self.stats[key] msg = '{:4} '.format(key.upper()) - ret.extend(self._msg_create_line(msg, bar, key)) + ret.extend(self._msg_create_line(msg, data, key)) ret.append(self.curse_new_line()) # Remove the last new line @@ -139,14 +165,14 @@ class Plugin(GlancesPlugin): # Return the message with decoration return ret - def _msg_create_line(self, msg, bar, key): + def _msg_create_line(self, msg, data, key): """Create a new line to the Quickview.""" ret = [] ret.append(self.curse_add_line(msg)) - ret.append(self.curse_add_line(bar.pre_char, decoration='BOLD')) - ret.append(self.curse_add_line(str(bar), self.get_views(key=key, option='decoration'))) - ret.append(self.curse_add_line(bar.post_char, decoration='BOLD')) + ret.append(self.curse_add_line(data.pre_char, decoration='BOLD')) + ret.append(self.curse_add_line(str(data), self.get_views(key=key, option='decoration'))) + ret.append(self.curse_add_line(data.post_char, decoration='BOLD')) ret.append(self.curse_add_line(' ')) return ret