Test Failed
Push — master ( 4c6c3d...040528 )
by Nicolas
04:27
created

glances/exports/glances_csv.py (5 issues)

Labels
Severity
1
# -*- coding: utf-8 -*-
0 ignored issues
show
There seems to be a cyclic import (glances -> glances.main).

Cyclic imports may cause partly loaded modules to be returned. This might lead to unexpected runtime behavior which is hard to debug.

Loading history...
There seems to be a cyclic import (glances -> glances.client).

Cyclic imports may cause partly loaded modules to be returned. This might lead to unexpected runtime behavior which is hard to debug.

Loading history...
There seems to be a cyclic import (glances -> glances.client_browser -> glances.client).

Cyclic imports may cause partly loaded modules to be returned. This might lead to unexpected runtime behavior which is hard to debug.

Loading history...
There seems to be a cyclic import (glances -> glances.standalone -> glances.outdated).

Cyclic imports may cause partly loaded modules to be returned. This might lead to unexpected runtime behavior which is hard to debug.

Loading history...
There seems to be a cyclic import (glances -> glances.server).

Cyclic imports may cause partly loaded modules to be returned. This might lead to unexpected runtime behavior which is hard to debug.

Loading history...
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
"""CSV interface class."""
21
22
import os.path
23
import csv
24
import sys
25
import time
26
27
from glances.compat import PY3, iterkeys, itervalues
28
from glances.logger import logger
29
from glances.exports.glances_export import GlancesExport
30
31
32
class Export(GlancesExport):
33
34
    """This class manages the CSV export module."""
35
36
    def __init__(self, config=None, args=None):
37
        """Init the CSV export IF."""
38
        super(Export, self).__init__(config=config, args=args)
39
40
        # CSV file name
41
        self.csv_filename = args.export_csv_file
42
43
        # Set the CSV output file
44
        # (see https://github.com/nicolargo/glances/issues/1525)
45
        if not os.path.isfile(self.csv_filename) or args.export_csv_overwrite:
46
            # File did not exist, create it
47
            file_mode = 'w'
48
            self.old_header = None
49
        else:
50
            # A CSV file already exit, append new data
51
            file_mode = 'a'
52
            # Header will be check later
53
            # Get the existing one
54
            try:
55
                self.csv_file = open_csv_file(self.csv_filename, 'r')
56
                reader = csv.reader(self.csv_file)
57
            except IOError as e:
58
                logger.critical("Cannot open existing CSV file: {}".format(e))
59
                sys.exit(2)
60
            self.old_header = next(reader, None)
61
            self.csv_file.close()
62
63
        try:
64
            self.csv_file = open_csv_file(self.csv_filename, file_mode)
65
            self.writer = csv.writer(self.csv_file)
66
        except IOError as e:
67
            logger.critical("Cannot create the CSV file: {}".format(e))
68
            sys.exit(2)
69
70
        logger.info("Stats exported to CSV file: {}".format(self.csv_filename))
71
72
        self.export_enable = True
73
74
        self.first_line = True
75
76
    def exit(self):
77
        """Close the CSV file."""
78
        logger.debug("Finalise export interface %s" % self.export_name)
79
        self.csv_file.close()
80
81
    def update(self, stats):
82
        """Update stats in the CSV output file."""
83
        # Get the stats
84
        all_stats = stats.getAllExportsAsDict(plugin_list=self.plugins_to_export())
85
86
        # Init data with timestamp (issue#708)
87
        if self.first_line:
88
            csv_header = ['timestamp']
89
        csv_data = [time.strftime('%Y-%m-%d %H:%M:%S')]
90
91
        # Loop over plugins to export
92
        for plugin in self.plugins_to_export():
93
            if isinstance(all_stats[plugin], list):
94
                for stat in all_stats[plugin]:
95
                    # First line: header
96
                    if self.first_line:
97
                        csv_header += ('{}_{}_{}'.format(
98
                            plugin, self.get_item_key(stat), item) for item in stat)
99
                    # Others lines: stats
100
                    csv_data += itervalues(stat)
101
            elif isinstance(all_stats[plugin], dict):
102
                # First line: header
103
                if self.first_line:
104
                    fieldnames = iterkeys(all_stats[plugin])
105
                    csv_header += ('{}_{}'.format(plugin, fieldname)
106
                                   for fieldname in fieldnames)
107
                # Others lines: stats
108
                csv_data += itervalues(all_stats[plugin])
109
110
        # Export to CSV
111
        # Manage header
112
        if self.first_line:
113
            if self.old_header is None:
114
                # New file, write the header on top on the CSV file
115
                self.writer.writerow(csv_header)
116
            # File already exist, check if header are compatible
117
            if self.old_header != csv_header:
118
                # Header are differents, log an error and do not write data
119
                logger.error("Cannot append data to existing CSV file. Headers are differents.")
120
                logger.debug("Old header: {}".format(self.old_header))
121
                logger.debug("New header: {}".format(csv_header))
122
            else:
123
                # Header are equals, ready to write data
124
                self.old_header = None
125
            # Only do this once
126
            self.first_line = False
127
        # Manage data
128
        if self.old_header is None:
129
            self.writer.writerow(csv_data)
130
            self.csv_file.flush()
131
132
133
def open_csv_file(file_name, file_mode):
134
    if PY3:
135
        csv_file = open(file_name, file_mode, newline='')
136
    else:
137
        csv_file = open(file_name, file_mode + 'b')
138
    return csv_file
139