Merge branch 'issue1077' into develop

This commit is contained in:
nicolargo 2017-04-03 10:20:11 +02:00
commit 9b71b377d8
12 changed files with 67 additions and 10 deletions

1
NEWS
View File

@ -8,6 +8,7 @@ Version 2.9.2
Enhancements and new features: Enhancements and new features:
* Use -> and <- arrows keys to switch between processing sort (issue #1075) * Use -> and <- arrows keys to switch between processing sort (issue #1075)
* Add trends in the Curses interface (issue #1077)
Bugs corrected: Bugs corrected:

BIN
docs/_static/trend.png vendored Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 22 KiB

View File

@ -69,3 +69,9 @@ CPU (user/system) Status
.. note:: .. note::
Limit values can be overwritten in the configuration file under Limit values can be overwritten in the configuration file under
the ``[cpu]`` and/or ``[percpu]`` sections. the ``[cpu]`` and/or ``[percpu]`` sections.
.. note::
A trend character could be displayed just after the title.
* '-': value is more or less equal to the mean of the lasts N values
* '/': value is higher than the mean of the lasts N values
* '/': value is lower than the mean of the lasts N values

View File

@ -28,3 +28,9 @@ RAM/Swap Status
.. note:: .. note::
Limit values can be overwritten in the configuration file under Limit values can be overwritten in the configuration file under
the ``[memory]`` and/or ``[memswap]`` sections. the ``[memory]`` and/or ``[memswap]`` sections.
.. note::
A trend character could be displayed just after the title.
* '-': value is more or less equal to the mean of the lasts N values
* '/': value is higher than the mean of the lasts N values
* '/': value is lower than the mean of the lasts N values

View File

@ -1,6 +1,6 @@
.\" Man page generated from reStructuredText. .\" Man page generated from reStructuredText.
. .
.TH "GLANCES" "1" "Mar 29, 2017" "2.9.1" "Glances" .TH "GLANCES" "1" "Apr 03, 2017" "2.9.2_DEVELOP" "Glances"
.SH NAME .SH NAME
glances \- An eye on your system glances \- An eye on your system
. .

View File

@ -126,6 +126,10 @@ class GlancesAttribute(object):
""" """
return self._history[-pos] 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): def history_json(self, nb=0):
"""Return the history of last nb items (0 for all) In ISO JSON format""" """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:]] return [(i[0].isoformat(), i[1]) for i in self._history[-nb:]]

View File

@ -35,6 +35,7 @@ if PY3:
from xmlrpc.server import SimpleXMLRPCRequestHandler, SimpleXMLRPCServer from xmlrpc.server import SimpleXMLRPCRequestHandler, SimpleXMLRPCServer
from urllib.request import urlopen from urllib.request import urlopen
from urllib.error import HTTPError, URLError from urllib.error import HTTPError, URLError
from statistics import mean
input = input input = input
range = range range = range
@ -103,6 +104,9 @@ else:
viewvalues = operator.methodcaller('viewvalues') viewvalues = operator.methodcaller('viewvalues')
viewitems = operator.methodcaller('viewitems') viewitems = operator.methodcaller('viewitems')
def mean(numbers):
return float(sum(numbers)) / max(len(numbers), 1)
def to_ascii(s): def to_ascii(s):
"""Convert the unicode 's' to a ASCII string """Convert the unicode 's' to a ASCII string
Usefull to remove accent (diacritics)""" Usefull to remove accent (diacritics)"""

View File

@ -49,9 +49,9 @@ class GlancesHistory(object):
for a in self.stats_history: for a in self.stats_history:
self.stats_history[a].history_reset() self.stats_history[a].history_reset()
def get(self): def get(self, nb=0):
"""Get the history as a dict of list""" """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): def get_json(self, nb=0):
"""Get the history as a dict of list (with list JSON compliant)""" """Get the history as a dict of list (with list JSON compliant)"""

View File

@ -229,8 +229,16 @@ class Plugin(GlancesPlugin):
idle_tag = 'user' not in self.stats idle_tag = 'user' not in self.stats
# Header # Header
msg = '{:8}'.format('CPU') msg = '{}'.format('CPU')
ret.append(self.curse_add_line(msg, "TITLE")) ret.append(self.curse_add_line(msg, "TITLE"))
trend_user = self.get_trend('user')
trend_system = self.get_trend('system')
if trend_user is None or trend_user is None:
trend_cpu = None
else:
trend_cpu = trend_user + trend_system
msg = ' {:4}'.format(self.trend_msg(trend_cpu))
ret.append(self.curse_add_line(msg))
# Total CPU usage # Total CPU usage
msg = '{:5.1f}%'.format(self.stats['total']) msg = '{:5.1f}%'.format(self.stats['total'])
if idle_tag: if idle_tag:

View File

@ -183,8 +183,10 @@ class Plugin(GlancesPlugin):
# Build the string message # Build the string message
# Header # Header
msg = '{:5} '.format('MEM') msg = '{}'.format('MEM')
ret.append(self.curse_add_line(msg, "TITLE")) ret.append(self.curse_add_line(msg, "TITLE"))
msg = ' {:2}'.format(self.trend_msg(self.get_trend('percent')))
ret.append(self.curse_add_line(msg))
# Percent memory usage # Percent memory usage
msg = '{:>7.1%}'.format(self.stats['percent'] / 100) msg = '{:>7.1%}'.format(self.stats['percent'] / 100)
ret.append(self.curse_add_line(msg)) ret.append(self.curse_add_line(msg))

View File

@ -154,8 +154,10 @@ class Plugin(GlancesPlugin):
# Build the string message # Build the string message
# Header # Header
msg = '{:7} '.format('SWAP') msg = '{}'.format('SWAP')
ret.append(self.curse_add_line(msg, "TITLE")) ret.append(self.curse_add_line(msg, "TITLE"))
msg = ' {:3}'.format(self.trend_msg(self.get_trend('percent')))
ret.append(self.curse_add_line(msg))
# Percent memory usage # Percent memory usage
msg = '{:>6.1%}'.format(self.stats['percent'] / 100) msg = '{:>6.1%}'.format(self.stats['percent'] / 100)
ret.append(self.curse_add_line(msg)) ret.append(self.curse_add_line(msg))

View File

@ -27,7 +27,7 @@ import re
import json import json
from operator import itemgetter from operator import itemgetter
from glances.compat import iterkeys, itervalues, listkeys, map from glances.compat import iterkeys, itervalues, listkeys, map, mean
from glances.actions import GlancesActions from glances.actions import GlancesActions
from glances.history import GlancesHistory from glances.history import GlancesHistory
from glances.logger import logger from glances.logger import logger
@ -156,12 +156,13 @@ class GlancesPlugin(object):
"""Return the items history list.""" """Return the items history list."""
return self.items_history_list return self.items_history_list
def get_raw_history(self, item=None): def get_raw_history(self, item=None, nb=0):
"""Return """Return
- the stats history (dict of list) if item is None - the stats history (dict of list) if item is None
- the stats history for the given item (list) instead - the stats history for the given item (list) instead
- None if item did not exist in the history""" - None if item did not exist in the history
s = self.stats_history.get() Limit to lasts nb items (all if nb=0)"""
s = self.stats_history.get(nb=nb)
if item is None: if item is None:
return s return s
else: else:
@ -215,6 +216,17 @@ class GlancesPlugin(object):
else: else:
return None return None
def get_trend(self, item, nb=6):
"""Get the trend regarding to the last nb values
The trend is the diff between the mean of the last nb values
and the current one.
"""
raw_history = self.get_raw_history(item=item, nb=nb)
if raw_history is None or len(raw_history) < nb:
return None
last_nb = [v[1] for v in raw_history]
return last_nb[-1] - mean(last_nb[:-1])
@property @property
def input_method(self): def input_method(self):
"""Get the input method.""" """Get the input method."""
@ -798,6 +810,18 @@ class GlancesPlugin(object):
value, decimal=decimal_precision, symbol=symbol) value, decimal=decimal_precision, symbol=symbol)
return '{!s}'.format(number) return '{!s}'.format(number)
def trend_msg(self, trend, significant=1):
"""Return the trend message
Do not take into account if trend < significant"""
ret = '-'
if trend is None:
ret = ' '
elif trend > significant:
ret = '/'
elif trend < -significant:
ret = '\\'
return ret
def _check_decorator(fct): def _check_decorator(fct):
"""Check if the plugin is enabled.""" """Check if the plugin is enabled."""
def wrapper(self, *args, **kw): def wrapper(self, *args, **kw):