summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authornicolargo <nicolas@nicolargo.com>2017-04-03 10:20:11 +0200
committernicolargo <nicolas@nicolargo.com>2017-04-03 10:20:11 +0200
commit9b71b377d8fe8e0f1ff8f7c7f07d9361e489dd90 (patch)
tree32285eba372c2c3eca06f04282b6af7f1ebdcf89
parent130cd2961a5a83c2f8735dc637a5a2d37b25c4a5 (diff)
parent6058ee2fca05469d3a6fe4abe3b0e5dfb681a89c (diff)
Merge branch 'issue1077' into develop
-rw-r--r--NEWS1
-rw-r--r--docs/_static/trend.pngbin0 -> 23021 bytes
-rw-r--r--docs/aoa/cpu.rst6
-rw-r--r--docs/aoa/memory.rst6
-rw-r--r--docs/man/glances.12
-rw-r--r--glances/attribute.py4
-rw-r--r--glances/compat.py4
-rw-r--r--glances/history.py4
-rw-r--r--glances/plugins/glances_cpu.py10
-rw-r--r--glances/plugins/glances_mem.py4
-rw-r--r--glances/plugins/glances_memswap.py4
-rw-r--r--glances/plugins/glances_plugin.py32
12 files changed, 67 insertions, 10 deletions
diff --git a/NEWS b/NEWS
index 693b0c0b..da750506 100644
--- a/NEWS
+++ b/NEWS
@@ -8,6 +8,7 @@ Version 2.9.2
Enhancements and new features:
* Use -> and <- arrows keys to switch between processing sort (issue #1075)
+ * Add trends in the Curses interface (issue #1077)
Bugs corrected:
diff --git a/docs/_static/trend.png b/docs/_static/trend.png
new file mode 100644
index 00000000..7cf0cff4
--- /dev/null
+++ b/docs/_static/trend.png
Binary files differ
diff --git a/docs/aoa/cpu.rst b/docs/aoa/cpu.rst
index ead6a0df..8f531bb7 100644
--- a/docs/aoa/cpu.rst
+++ b/docs/aoa/cpu.rst
@@ -69,3 +69,9 @@ CPU (user/system) Status
.. note::
Limit values can be overwritten in the configuration file under
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
diff --git a/docs/aoa/memory.rst b/docs/aoa/memory.rst
index 0cd6afc8..37795cb5 100644
--- a/docs/aoa/memory.rst
+++ b/docs/aoa/memory.rst
@@ -28,3 +28,9 @@ RAM/Swap Status
.. note::
Limit values can be overwritten in the configuration file under
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
diff --git a/docs/man/glances.1 b/docs/man/glances.1
index 1f0b9fb2..404327e1 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" "Apr 03, 2017" "2.9.2_DEVELOP" "Glances"
.SH NAME
glances \- An eye on your system
.
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..ad28709c 100644
--- a/glances/compat.py
+++ b/glances/compat.py
@@ -35,6 +35,7 @@ if PY3:
from xmlrpc.server import SimpleXMLRPCRequestHandler, SimpleXMLRPCServer
from urllib.request import urlopen
from urllib.error import HTTPError, URLError
+ from statistics import mean
input = input
range = range
@@ -103,6 +104,9 @@ else:
viewvalues = operator.methodcaller('viewvalues')
viewitems = operator.methodcaller('viewitems')
+ def mean(numbers):
+ return float(sum(numbers)) / max(len(numbers), 1)
+
def to_ascii(s):
"""Convert the unicode 's' to a ASCII string
Usefull to remove accent (diacritics)"""
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/plugins/glances_cpu.py b/glances/plugins/glances_cpu.py
index 6dee43c0..c9ce5501 100644
--- a/glances/plugins/glances_cpu.py
+++ b/glances/plugins/glances_cpu.py
@@ -229,8 +229,16 @@ class Plugin(GlancesPlugin):
idle_tag = 'user' not in self.stats
# Header
- msg = '{:8}'.format('CPU')
+ msg = '{}'.format('CPU')
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
msg = '{:5.1f}%'.format(self.stats['total'])
if idle_tag:
diff --git a/glances/plugins/glances_mem.py b/glances/plugins/glances_mem.py
index 3cbfc2a4..eaebfa97 100644
--- a/glances/plugins/glances_mem.py
+++ b/glances/plugins/glances_mem.py
@@ -183,8 +183,10 @@ class Plugin(GlancesPlugin):
# Build the string message
# Header
- msg = '{:5} '.format('MEM')
+ msg = '{}'.format('MEM')
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
msg = '{:>7.1%}'.format(self.stats['percent'] / 100)
ret.append(self.curse_add_line(msg))
diff --git a/glances/plugins/glances_memswap.py b/glances/plugins/glances_memswap.py
index eedd0eaa..ec8f7bee 100644
--- a/glances/plugins/glances_memswap.py
+++ b/glances/plugins/glances_memswap.py
@@ -154,8 +154,10 @@ class Plugin(GlancesPlugin):
# Build the string message
# Header
- msg = '{:7} '.format('SWAP')
+ msg = '{}'.format('SWAP')
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
msg = '{:>6.1%}'.format(self.stats['percent'] / 100)
ret.append(self.curse_add_line(msg))
diff --git a/glances/plugins/glances_plugin.py b/glances/plugins/glances_plugin.py
index 48cc7cd3..f0dd1cac 100644
--- a/glances/plugins/glances_plugin.py
+++ b/glances/plugins/glances_plugin.py
@@ -27,7 +27,7 @@ import re
import json
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.history import GlancesHistory
from glances.logger import logger
@@ -156,12 +156,13 @@ class GlancesPlugin(object):
"""Return the 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
- the stats history (dict of list) if item is None
- the stats history for the given item (list) instead
- - None if item did not exist in the history"""
- s = self.stats_history.get()
+ - None if item did not exist in the history
+ Limit to lasts nb items (all if nb=0)"""
+ s = self.stats_history.get(nb=nb)
if item is None:
return s
else:
@@ -215,6 +216,17 @@ class GlancesPlugin(object):
else:
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
def input_method(self):
"""Get the input method."""
@@ -798,6 +810,18 @@ class GlancesPlugin(object):
value, decimal=decimal_precision, symbol=symbol)
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):
"""Check if the plugin is enabled."""
def wrapper(self, *args, **kw):