From 1738af11d2818b3df9f8d00be5110e40f7149144 Mon Sep 17 00:00:00 2001 From: nicolargo Date: Fri, 29 Dec 2017 19:10:25 +0100 Subject: [PATCH] Remove graph export from Glances #1206 --- NEWS | 2 + README.rst | 1 - docs/cmds.rst | 2 +- docs/man/glances.1 | 4 +- glances/exports/graph.py | 182 ------------------------ glances/main.py | 20 --- glances/outputs/glances_curses.py | 31 ---- glances/plugins/glances_cpu.py | 3 - glances/plugins/glances_diskio.py | 3 - glances/plugins/glances_fs.py | 3 +- glances/plugins/glances_load.py | 10 +- glances/plugins/glances_mem.py | 2 - glances/plugins/glances_memswap.py | 2 - glances/plugins/glances_network.py | 3 - glances/plugins/glances_processcount.py | 1 - optional-requirements.txt | 1 - setup.py | 1 - 17 files changed, 9 insertions(+), 262 deletions(-) delete mode 100644 glances/exports/graph.py diff --git a/NEWS b/NEWS index ea511557..e240fca0 100644 --- a/NEWS +++ b/NEWS @@ -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- no longer available (use --disable-plugin ) * --export- no longer available (use --export ) diff --git a/README.rst b/README.rst index f7f04dfe..4e28aaf4 100644 --- a/README.rst +++ b/README.rst @@ -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) diff --git a/docs/cmds.rst b/docs/cmds.rst index 9af00844..9dc46690 100644 --- a/docs/cmds.rst +++ b/docs/cmds.rst @@ -84,7 +84,7 @@ Command-Line Options .. option:: --enable-history - enable the history mode (matplotlib lib needed) + enable the history mode .. option:: --disable-bold diff --git a/docs/man/glances.1 b/docs/man/glances.1 index 5f5be268..f2bec9c7 100644 --- a/docs/man/glances.1 +++ b/docs/man/glances.1 @@ -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 diff --git a/glances/exports/graph.py b/glances/exports/graph.py deleted file mode 100644 index b6e31ddf..00000000 --- a/glances/exports/graph.py +++ /dev/null @@ -1,182 +0,0 @@ -# -*- coding: utf-8 -*- -# -# This file is part of Glances. -# -# Copyright (C) 2017 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 . - -"""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 diff --git a/glances/main.py b/glances/main.py index 46462649..f814aac5 100644 --- a/glances/main.py +++ b/glances/main.py @@ -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') diff --git a/glances/outputs/glances_curses.py b/glances/outputs/glances_curses.py index 1eef2043..f4615775 100644 --- a/glances/outputs/glances_curses.py +++ b/glances/outputs/glances_curses.py @@ -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: diff --git a/glances/plugins/glances_cpu.py b/glances/plugins/glances_cpu.py index 8e0e2386..f06e6fa8 100644 --- a/glances/plugins/glances_cpu.py +++ b/glances/plugins/glances_cpu.py @@ -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': '%'}] diff --git a/glances/plugins/glances_diskio.py b/glances/plugins/glances_diskio.py index 7b8049e8..195e30ad 100644 --- a/glances/plugins/glances_diskio.py +++ b/glances/plugins/glances_diskio.py @@ -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'}] diff --git a/glances/plugins/glances_fs.py b/glances/plugins/glances_fs.py index 94c7f533..df572c10 100644 --- a/glances/plugins/glances_fs.py +++ b/glances/plugins/glances_fs.py @@ -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): diff --git a/glances/plugins/glances_load.py b/glances/plugins/glances_load.py index f4f78bfb..93cc8156 100644 --- a/glances/plugins/glances_load.py +++ b/glances/plugins/glances_load.py @@ -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): diff --git a/glances/plugins/glances_mem.py b/glances/plugins/glances_mem.py index f092bbd9..63bee0fa 100644 --- a/glances/plugins/glances_mem.py +++ b/glances/plugins/glances_mem.py @@ -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': '%'}] diff --git a/glances/plugins/glances_memswap.py b/glances/plugins/glances_memswap.py index 0aeed61f..60c0dd95 100644 --- a/glances/plugins/glances_memswap.py +++ b/glances/plugins/glances_memswap.py @@ -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': '%'}] diff --git a/glances/plugins/glances_network.py b/glances/plugins/glances_network.py index a526bafd..92e01ca1 100644 --- a/glances/plugins/glances_network.py +++ b/glances/plugins/glances_network.py @@ -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'}] diff --git a/glances/plugins/glances_processcount.py b/glances/plugins/glances_processcount.py index d4f9ac56..bf65cda4 100644 --- a/glances/plugins/glances_processcount.py +++ b/glances/plugins/glances_processcount.py @@ -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): diff --git a/optional-requirements.txt b/optional-requirements.txt index 93f199ca..c1ad0f73 100644 --- a/optional-requirements.txt +++ b/optional-requirements.txt @@ -6,7 +6,6 @@ docker>=2.0.0 elasticsearch influxdb kafka-python -matplotlib netifaces nvidia-ml-py3 pika diff --git a/setup.py b/setup.py index f423d48d..08a831a4 100755 --- a/setup.py +++ b/setup.py @@ -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', -- GitLab