Test Failed
Push — develop ( d7cf39...faa4bd )
by Nicolas
04:34 queued 10s
created

glances/exports/glances_graph.py (3 issues)

1
# -*- coding: utf-8 -*-
2
#
3
# This file is part of Glances.
4
#
5
# Copyright (C) 2019 Nicolargo <[email protected]>
6
#
7
# Glances is free software; you can redistribute it and/or modify
8
# it under the terms of the GNU Lesser General Public License as published by
9
# the Free Software Foundation, either version 3 of the License, or
10
# (at your option) any later version.
11
#
12
# Glances is distributed in the hope that it will be useful,
13
# but WITHOUT ANY WARRANTY; without even the implied warranty of
14
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15
# GNU Lesser General Public License for more details.
16
#
17
# You should have received a copy of the GNU Lesser General Public License
18
# along with this program. If not, see <http://www.gnu.org/licenses/>.
19
20
"""Graph exporter interface class."""
21
22
from pygal import DateTimeLine
0 ignored issues
show
Unable to import 'pygal'
Loading history...
23
import pygal.style
0 ignored issues
show
Unable to import 'pygal.style'
Loading history...
24
import sys
25
import os
26
import tempfile
27
import errno
28
29
from glances.logger import logger
30
from glances.timer import Timer
31
from glances.compat import iteritems, time_serie_subsample
32
from glances.exports.glances_export import GlancesExport
33
34
35
class Export(GlancesExport):
36
37
    """This class manages the Graph export module."""
38
39
    def __init__(self, config=None, args=None):
40
        """Init the export IF."""
41
        super(Export, self).__init__(config=config, args=args)
42
43
        # Load the Graph configuration file section (is exists)
44
        self.export_enable = self.load_conf('graph',
45
                                            options=['path',
46
                                                     'generate_every',
47
                                                     'width',
48
                                                     'height',
49
                                                     'style'])
50
51
        # Manage options (command line arguments overwrite configuration file)
52
        self.path = args.export_graph_path or self.path
53
        self.generate_every = int(getattr(self, 'generate_every', 0))
54
        self.width = int(getattr(self, 'width', 800))
55
        self.height = int(getattr(self, 'height', 600))
56
        self.style = getattr(pygal.style,
57
                             getattr(self, 'style', 'DarkStyle'),
58
                             pygal.style.DarkStyle)
59
60
        # Create export folder
61
        try:
62
            os.makedirs(self.path)
63
        except OSError as e:
64
            if e.errno != errno.EEXIST:
65
                logger.critical("Cannot create the Graph output folder {} ({})".format(self.path, e))
66
                sys.exit(2)
67
68
        # Check if output folder is writeable
69
        try:
70
            tempfile.TemporaryFile(dir=self.path)
71
        except OSError as e:
72
            logger.critical("Graph output folder {} is not writeable".format(self.path))
73
            sys.exit(2)
74
75
        logger.info("Graphs will be created in the {} folder".format(self.path))
76
        logger.info("Graphs will be created  when 'g' key is pressed (in the CLI interface)")
77
        if self.generate_every != 0:
78
            logger.info("Graphs will be created automatically every {} seconds".format(self.generate_every))
79
            # Start the timer
80
            self._timer = Timer(self.generate_every)
81
        else:
82
            self._timer = None
83
84
    def exit(self):
85
        """Close the files."""
86
        logger.debug("Finalise export interface %s" % self.export_name)
87
88
    def update(self, stats):
89
        """Generate Graph file in the output folder."""
90
91
        if self.generate_every != 0 and self._timer.finished():
92
            self.args.generate_graph = True
93
            self._timer.reset()
94
95
        if not self.args.generate_graph:
96
            return
97
98
        plugins = stats.getPluginsList()
99
        for plugin_name in plugins:
100
            plugin = stats._plugins[plugin_name]
0 ignored issues
show
Coding Style Best Practice introduced by
It seems like _plugins was declared protected and should not be accessed from this context.

Prefixing a member variable _ is usually regarded as the equivalent of declaring it with protected visibility that exists in other languages. Consequentially, such a member should only be accessed from the same class or a child class:

class MyParent:
    def __init__(self):
        self._x = 1;
        self.y = 2;

class MyChild(MyParent):
    def some_method(self):
        return self._x    # Ok, since accessed from a child class

class AnotherClass:
    def some_method(self, instance_of_my_child):
        return instance_of_my_child._x   # Would be flagged as AnotherClass is not
                                         # a child class of MyParent
Loading history...
101
            if plugin_name in self.plugins_to_export():
102
                self.export(plugin_name, plugin.get_export_history())
103
104
        logger.info("Graphs created in the folder {}".format(self.path))
105
        self.args.generate_graph = False
106
107
    def export(self, title, data):
108
        """Generate graph from the data.
109
110
        Example for the mem plugin:
111
        {'percent': [
112
            (datetime.datetime(2018, 3, 24, 16, 27, 47, 282070), 51.8),
113
            (datetime.datetime(2018, 3, 24, 16, 27, 47, 540999), 51.9),
114
            (datetime.datetime(2018, 3, 24, 16, 27, 50, 653390), 52.0),
115
            (datetime.datetime(2018, 3, 24, 16, 27, 53, 749702), 52.0),
116
            (datetime.datetime(2018, 3, 24, 16, 27, 56, 825660), 52.0),
117
            ...
118
            ]
119
        }
120
121
        Return:
122
        * True if the graph have been generated
123
        * False if the graph have not been generated
124
        """
125
        if data == {}:
126
            return False
127
128
        chart = DateTimeLine(title=title.capitalize(),
129
                             width=self.width,
130
                             height=self.height,
131
                             style=self.style,
132
                             show_dots=False,
133
                             legend_at_bottom=True,
134
                             x_label_rotation=20,
135
                             x_value_formatter=lambda dt: dt.strftime('%Y/%m/%d %H:%M:%S'))
136
        for k, v in iteritems(time_serie_subsample(data, self.width)):
137
            chart.add(k, v)
138
        chart.render_to_file(os.path.join(self.path,
139
                                          title + '.svg'))
140
        return True
141