Remove graph export from Glances #1206

This commit is contained in:
nicolargo 2017-12-29 19:10:25 +01:00
parent 4f7f6be666
commit 1738af11d2
17 changed files with 9 additions and 262 deletions

2
NEWS
View File

@ -14,6 +14,7 @@ Enhancements and new features:
* Make plugins disable and export CLI option dynamical #1173
* Add a light mode for the console UI #1165
* Refactor InfluxDB (API is now stable) #1166
* Remove graph export from Glances #1206
Bugs corrected:
@ -34,6 +35,7 @@ Backward-incompatible changes:
* Minimum supported Docker API version is now 1.21 (Docker plugins)
* Support for InfluxDB < 0.9 is deprecated (InfluxDB exporter)
* Remove graph export from Glances
* --disable-<plugin> no longer available (use --disable-plugin <plugin>)
* --export-<exporter> no longer available (use --export <exporter>)

View File

@ -65,7 +65,6 @@ Optional dependencies:
- ``hddtemp`` (for HDD temperature monitoring support) [Linux-only]
- ``influxdb`` (for the InfluxDB export module)
- ``kafka-python`` (for the Kafka export module)
- ``matplotlib`` (for graphical/chart support)
- ``netifaces`` (for the IP plugin)
- ``nvidia-ml-py3`` (for the GPU plugin)
- ``pika`` (for the RabbitMQ/ActiveMQ export module)

View File

@ -84,7 +84,7 @@ Command-Line Options
.. option:: --enable-history
enable the history mode (matplotlib lib needed)
enable the history mode
.. option:: --disable-bold

View File

@ -1,6 +1,6 @@
.\" Man page generated from reStructuredText.
.
.TH "GLANCES" "1" "Dec 28, 2017" "3.0_DEV" "Glances"
.TH "GLANCES" "1" "Dec 29, 2017" "3.0_DEV" "Glances"
.SH NAME
glances \- An eye on your system
.
@ -144,7 +144,7 @@ start Glances in mean GPU mode
.INDENT 0.0
.TP
.B \-\-enable\-history
enable the history mode (matplotlib lib needed)
enable the history mode
.UNINDENT
.INDENT 0.0
.TP

View File

@ -1,182 +0,0 @@
# -*- coding: utf-8 -*-
#
# This file is part of Glances.
#
# Copyright (C) 2017 Nicolargo <nicolas@nicolargo.com>
#
# 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 <http://www.gnu.org/licenses/>.
"""Graph generation class."""
import os
from glances.compat import iterkeys
from glances.logger import logger
try:
from matplotlib import __version__ as matplotlib_version
import matplotlib.pyplot as plt
except ImportError:
matplotlib_check = False
logger.warning('Cannot load Matplotlib library. Please install it using "pip install matplotlib"')
else:
matplotlib_check = True
logger.info('Load Matplotlib version %s' % matplotlib_version)
class GlancesGraph(object):
"""Thanks to this class, Glances can export history to graphs."""
def __init__(self, output_folder):
self.output_folder = output_folder
def get_output_folder(self):
"""Return the output folder where the graph are generated."""
return self.output_folder
def graph_enabled(self):
"""Return True if Glances can generate history graphs."""
return matplotlib_check
def reset(self, stats):
"""Reset all the history."""
if not self.graph_enabled():
return False
for p in stats.getPluginsList():
h = stats.get_plugin(p).get_stats_history()
if h is not None:
stats.get_plugin(p).reset_stats_history()
return True
def get_graph_color(self, item):
"""Get the item's color."""
try:
ret = item['color']
except KeyError:
return '#FFFFFF'
else:
return ret
def get_graph_legend(self, item):
"""Get the item's legend."""
return item['description']
def get_graph_yunit(self, item, pre_label=''):
"""Get the item's Y unit."""
try:
unit = " (%s)" % item['y_unit']
except KeyError:
unit = ''
if pre_label == '':
label = ''
else:
label = pre_label.split('_')[0]
return "%s%s" % (label, unit)
def generate_graph(self, stats):
"""Generate graphs from plugins history.
Return the number of output files generated by the function.
"""
if not self.graph_enabled():
return 0
index_all = 0
for p in stats.getPluginsList():
# History
h = stats.get_plugin(p).get_export_history()
# Current plugin item history list
ih = stats.get_plugin(p).get_items_history_list()
# Check if we must process history
if h is None or ih is None:
# History (h) not available for plugin (p)
continue
# Init graph
plt.clf()
index_graph = 0
handles = []
labels = []
for i in ih:
if i['name'] in iterkeys(h):
# The key exist
# Add the curves in the current chart
logger.debug("Generate graph: %s %s" % (p, i['name']))
index_graph += 1
# Labels
handles.append(plt.Rectangle((0, 0), 1, 1, fc=self.get_graph_color(i), ec=self.get_graph_color(i), linewidth=2))
labels.append(self.get_graph_legend(i))
# Legend
plt.ylabel(self.get_graph_yunit(i, pre_label=''))
# Curves
plt.grid(True)
# Points are stored as tuple (date, value)
x, y = zip(*h[i['name']])
plt.plot_date(x, y,
fmt='', drawstyle='default', linestyle='-',
color=self.get_graph_color(i),
xdate=True, ydate=False)
if index_graph == 1:
# Title only on top of the first graph
plt.title(p.capitalize())
else:
# The key did not exist
# Find if anothers key ends with the key
# Ex: key='tx' => 'ethernet_tx'
# Add one curve per chart
stats_history_filtered = sorted([key for key in iterkeys(h) if key.endswith('_' + i['name'])])
logger.debug("Generate graphs: %s %s" %
(p, stats_history_filtered))
if len(stats_history_filtered) > 0:
# Create 'n' graph
# Each graph iter through the stats
plt.clf()
index_item = 0
for k in stats_history_filtered:
index_item += 1
plt.subplot(
len(stats_history_filtered), 1, index_item)
# Legend
plt.ylabel(self.get_graph_yunit(i, pre_label=k))
# Curves
plt.grid(True)
# Points are stored as tuple (date, value)
x, y = zip(*h[k])
plt.plot_date(x, y,
fmt='', drawstyle='default', linestyle='-',
color=self.get_graph_color(i),
xdate=True, ydate=False)
if index_item == 1:
# Title only on top of the first graph
plt.title(p.capitalize() + ' ' + i['name'])
# Save the graph to output file
fig = plt.gcf()
fig.set_size_inches(20, 5 * index_item)
plt.xlabel('Date')
plt.savefig(
os.path.join(self.output_folder, 'glances_%s_%s.png' % (p, i['name'])), dpi=72)
index_all += 1
if index_graph > 0:
# Save the graph to output file
fig = plt.gcf()
fig.set_size_inches(20, 10)
plt.legend(handles, labels, loc=1, prop={'size': 9})
plt.xlabel('Date')
plt.savefig(os.path.join(self.output_folder, 'glances_%s.png' % p), dpi=72)
index_all += 1
plt.close()
return index_all

View File

@ -20,9 +20,7 @@
"""Glances main class."""
import argparse
import os
import sys
import tempfile
from glances import __version__, psutil_version
from glances.compat import input
@ -160,11 +158,6 @@ Examples of use:
# Export modules feature
parser.add_argument('--export', dest='export',
help='enable export module (comma separed list)')
# To be removed on https://github.com/nicolargo/glances/issues/1206
# parser.add_argument('--export-graph', action='store_true', default=None,
# dest='export_graph', help='export stats to graphs')
# parser.add_argument('--path-graph', default=tempfile.gettempdir(),
# dest='path_graph', help='set the export path for graphs (default is {})'.format(tempfile.gettempdir()))
parser.add_argument('--export-csv-file',
default='./glances.csv',
dest='export_csv_file',
@ -382,19 +375,6 @@ Examples of use:
"Process filter is only available in standalone mode")
sys.exit(2)
# Check graph output path
# To be removed on https://github.com/nicolargo/glances/issues/1206
# if args.export_graph and args.path_graph is not None:
# if not os.access(args.path_graph, os.W_OK):
# logger.critical("Graphs output path {} doesn't exist or is not writable".format(args.path_graph))
# sys.exit(2)
# logger.debug(
# "Graphs output path is set to {}".format(args.path_graph))
# For export graph, history is mandatory
# if args.export_graph and args.disable_history:
# logger.critical("Can not export graph if history is disabled")
# sys.exit(2)
# Disable HDDTemp if sensors are disabled
if getattr(args, 'disable_sensors', False):
disable(args, 'hddtemp')

View File

@ -373,13 +373,6 @@ class _GlancesCurses(object):
# 'f' > Show/hide fs / folder stats
self.args.disable_fs = not self.args.disable_fs
self.args.disable_folders = not self.args.disable_folders
# To be removed on https://github.com/nicolargo/glances/issues/1206
# elif self.pressedkey == ord('g'):
# # 'g' > Generate graph from history
# self.graph_tag = not self.graph_tag
# elif self.pressedkey == ord('r'):
# # 'r' > Reset graph history
# self.reset_history_tag = not self.reset_history_tag
elif self.pressedkey == ord('w'):
# 'w' > Delete finished warning logs
glances_logs.clean()
@ -587,30 +580,6 @@ class _GlancesCurses(object):
# ====================================
self.__display_right(__stat_display)
# History option
# Generate history graph
# To be removed on https://github.com/nicolargo/glances/issues/1206
# if self.graph_tag and self.args.export_graph:
# self.display_popup(
# 'Generate graphs history in {}\nPlease wait...'.format(
# self.glances_graph.get_output_folder()))
# self.display_popup(
# 'Generate graphs history in {}\nDone: {} graphs generated'.format(
# self.glances_graph.get_output_folder(),
# self.glances_graph.generate_graph(stats)))
# elif self.reset_history_tag and self.args.export_graph:
# self.display_popup('Reset graph history')
# self.glances_graph.reset(stats)
# elif (self.graph_tag or self.reset_history_tag) and not self.args.export_graph:
# try:
# self.glances_graph.graph_enabled()
# except Exception:
# self.display_popup('Graph disabled\nEnable it using --export-graph')
# else:
# self.display_popup('Graph disabled')
# self.graph_tag = False
self.reset_history_tag = False
# Display edit filter popup
# Only in standalone mode (cs_status is None)
if self.edit_filter and cs_status is None:

View File

@ -43,16 +43,13 @@ snmp_oid = {'default': {'user': '1.3.6.1.4.1.2021.11.9.0',
# Define the history items list
# - 'name' define the stat identifier
# - 'color' define the graph color in #RGB format
# - 'y_unit' define the Y label
# All items in this list will be historised if the --enable-history tag is set
items_history_list = [{'name': 'user',
'description': 'User CPU usage',
'color': '#00FF00',
'y_unit': '%'},
{'name': 'system',
'description': 'System CPU usage',
'color': '#FF0000',
'y_unit': '%'}]

View File

@ -29,14 +29,11 @@ import psutil
# Define the history items list
# All items in this list will be historised if the --enable-history tag is set
# 'color' define the graph color in #RGB format
items_history_list = [{'name': 'read_bytes',
'description': 'Bytes read per second',
'color': '#00FF00',
'y_unit': 'B/s'},
{'name': 'write_bytes',
'description': 'Bytes write per second',
'color': '#FF0000',
'y_unit': 'B/s'}]

View File

@ -59,10 +59,9 @@ snmp_oid['esxi'] = snmp_oid['windows']
# Define the history items list
# All items in this list will be historised if the --enable-history tag is set
# 'color' define the graph color in #RGB format
items_history_list = [{'name': 'percent',
'description': 'File system usage in percent',
'color': '#00FF00'}]
'y_unit': '%'}]
class Plugin(GlancesPlugin):

View File

@ -35,16 +35,12 @@ snmp_oid = {'min1': '1.3.6.1.4.1.2021.10.1.3.1',
# Define the history items list
# All items in this list will be historised if the --enable-history tag is set
# 'color' define the graph color in #RGB format
items_history_list = [{'name': 'min1',
'description': '1 minute load',
'color': '#0000FF'},
'description': '1 minute load'},
{'name': 'min5',
'description': '5 minutes load',
'color': '#0000AA'},
'description': '5 minutes load'},
{'name': 'min15',
'description': '15 minutes load',
'color': '#000044'}]
'description': '15 minutes load'}]
class Plugin(GlancesPlugin):

View File

@ -48,10 +48,8 @@ snmp_oid = {'default': {'total': '1.3.6.1.4.1.2021.4.5.0',
# Define the history items list
# All items in this list will be historised if the --enable-history tag is set
# 'color' define the graph color in #RGB format
items_history_list = [{'name': 'percent',
'description': 'RAM memory usage',
'color': '#00FF00',
'y_unit': '%'}]

View File

@ -36,10 +36,8 @@ snmp_oid = {'default': {'total': '1.3.6.1.4.1.2021.4.3.0',
# Define the history items list
# All items in this list will be historised if the --enable-history tag is set
# 'color' define the graph color in #RGB format
items_history_list = [{'name': 'percent',
'description': 'Swap memory usage',
'color': '#00FF00',
'y_unit': '%'}]

View File

@ -36,14 +36,11 @@ snmp_oid = {'default': {'interface_name': '1.3.6.1.2.1.2.2.1.2',
# Define the history items list
# All items in this list will be historised if the --enable-history tag is set
# 'color' define the graph color in #RGB format
items_history_list = [{'name': 'rx',
'description': 'Download rate per second',
'color': '#00FF00',
'y_unit': 'bit/s'},
{'name': 'tx',
'description': 'Upload rate per second',
'color': '#FF0000',
'y_unit': 'bit/s'}]

View File

@ -23,7 +23,6 @@ from glances.processes import glances_processes
from glances.plugins.glances_plugin import GlancesPlugin
# Note: history items list is not compliant with process count
# if a filter is applyed, the graph will show the filtered processes count
class Plugin(GlancesPlugin):

View File

@ -6,7 +6,6 @@ docker>=2.0.0
elasticsearch
influxdb
kafka-python
matplotlib
netifaces
nvidia-ml-py3
pika

View File

@ -82,7 +82,6 @@ setup(
'browser': ['zeroconf>=0.17'],
'cloud': ['requests'],
'cpuinfo': ['py-cpuinfo'],
'chart': ['matplotlib'],
'docker': ['docker>=2.0.0'],
'export': ['bernhard', 'cassandra-driver', 'couchdb', 'elasticsearch',
'influxdb>=1.0.0', 'kafka-python', 'pika', 'potsdb',