mirror of
https://github.com/nicolargo/glances.git
synced 2024-12-25 18:23:41 +03:00
Remove graph export from Glances #1206
This commit is contained in:
parent
4f7f6be666
commit
1738af11d2
2
NEWS
2
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-<plugin> no longer available (use --disable-plugin <plugin>)
|
||||
* --export-<exporter> no longer available (use --export <exporter>)
|
||||
|
||||
|
@ -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)
|
||||
|
@ -84,7 +84,7 @@ Command-Line Options
|
||||
|
||||
.. option:: --enable-history
|
||||
|
||||
enable the history mode (matplotlib lib needed)
|
||||
enable the history mode
|
||||
|
||||
.. option:: --disable-bold
|
||||
|
||||
|
@ -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
|
||||
|
@ -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
|
@ -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')
|
||||
|
@ -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:
|
||||
|
@ -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': '%'}]
|
||||
|
||||
|
||||
|
@ -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'}]
|
||||
|
||||
|
||||
|
@ -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):
|
||||
|
@ -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):
|
||||
|
@ -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': '%'}]
|
||||
|
||||
|
||||
|
@ -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': '%'}]
|
||||
|
||||
|
||||
|
@ -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'}]
|
||||
|
||||
|
||||
|
@ -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):
|
||||
|
@ -6,7 +6,6 @@ docker>=2.0.0
|
||||
elasticsearch
|
||||
influxdb
|
||||
kafka-python
|
||||
matplotlib
|
||||
netifaces
|
||||
nvidia-ml-py3
|
||||
pika
|
||||
|
1
setup.py
1
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',
|
||||
|
Loading…
Reference in New Issue
Block a user