Issues (46)

glances/exports/glances_csv.py (3 issues)

1
# -*- coding: utf-8 -*-
2
#
3
# This file is part of Glances.
4
#
5
# SPDX-FileCopyrightText: 2022 Nicolas Hennion <[email protected]>
6
#
7
# SPDX-License-Identifier: LGPL-3.0-only
8
#
9
10
"""CSV interface class."""
11
12
import os.path
13
import csv
14
import sys
15
import time
16
17
from glances.compat import PY3, iterkeys, itervalues
18
from glances.logger import logger
19
from glances.exports.glances_export import GlancesExport
20
21
22
class Export(GlancesExport):
23
24
    """This class manages the CSV export module."""
25
26
    def __init__(self, config=None, args=None):
27
        """Init the CSV export IF."""
28
        super(Export, self).__init__(config=config, args=args)
29
30
        # CSV file name
31
        self.csv_filename = args.export_csv_file
32
33
        # Set the CSV output file
34
        # (see https://github.com/nicolargo/glances/issues/1525)
35
        if not os.path.isfile(self.csv_filename) or args.export_csv_overwrite:
36
            # File did not exist, create it
37
            file_mode = 'w'
38
            self.old_header = None
39
        else:
40
            # A CSV file already exit, append new data
41
            file_mode = 'a'
42
            # Header will be checked later
43
            # Get the existing one
44
            try:
45
                self.csv_file = open_csv_file(self.csv_filename, 'r')
46
                reader = csv.reader(self.csv_file)
47
            except IOError as e:
48
                logger.critical("Cannot open existing CSV file: {}".format(e))
49
                sys.exit(2)
50
            self.old_header = next(reader, None)
0 ignored issues
show
The variable reader does not seem to be defined for all execution paths.
Loading history...
51
            self.csv_file.close()
52
53
        try:
54
            self.csv_file = open_csv_file(self.csv_filename, file_mode)
55
            self.writer = csv.writer(self.csv_file)
56
        except IOError as e:
57
            logger.critical("Cannot create the CSV file: {}".format(e))
58
            sys.exit(2)
59
60
        logger.info("Stats exported to CSV file: {}".format(self.csv_filename))
61
62
        self.export_enable = True
63
64
        self.first_line = True
65
66
    def exit(self):
67
        """Close the CSV file."""
68
        logger.debug("Finalise export interface %s" % self.export_name)
69
        self.csv_file.close()
70
71
    def update(self, stats):
72
        """Update stats in the CSV output file."""
73
        # Get the stats
74
        all_stats = stats.getAllExportsAsDict(plugin_list=self.plugins_to_export(stats))
75
76
        # Init data with timestamp (issue#708)
77
        if self.first_line:
78
            csv_header = ['timestamp']
79
        csv_data = [time.strftime('%Y-%m-%d %H:%M:%S')]
80
81
        # Loop over plugins to export
82
        for plugin in self.plugins_to_export(stats):
83
            if isinstance(all_stats[plugin], list):
84
                for stat in sorted(all_stats[plugin], key=lambda x: x['key']):
85
                    # First line: header
86
                    if self.first_line:
87
                        csv_header += ['{}_{}_{}'.format(plugin, self.get_item_key(stat), item) for item in stat]
0 ignored issues
show
The variable csv_header does not seem to be defined in case self.first_line on line 77 is False. Are you sure this can never be the case?
Loading history...
88
                    # Others lines: stats
89
                    csv_data += itervalues(stat)
90
            elif isinstance(all_stats[plugin], dict):
91
                # First line: header
92
                if self.first_line:
93
                    fieldnames = iterkeys(all_stats[plugin])
94
                    csv_header += ('{}_{}'.format(plugin, fieldname) for fieldname in fieldnames)
0 ignored issues
show
The variable fieldname does not seem to be defined for all execution paths.
Loading history...
95
                # Others lines: stats
96
                csv_data += itervalues(all_stats[plugin])
97
98
        # Export to CSV
99
        # Manage header
100
        if self.first_line:
101
            if self.old_header is None:
102
                # New file, write the header on top on the CSV file
103
                self.writer.writerow(csv_header)
104
            # File already exist, check if header are compatible
105
            if self.old_header != csv_header and self.old_header is not None:
106
                # Header are different, log an error and do not write data
107
                logger.error("Cannot append data to existing CSV file. Headers are different.")
108
                logger.debug("Old header: {}".format(self.old_header))
109
                logger.debug("New header: {}".format(csv_header))
110
            else:
111
                # Header are equals, ready to write data
112
                self.old_header = None
113
            # Only do this once
114
            self.first_line = False
115
        # Manage data
116
        if self.old_header is None:
117
            self.writer.writerow(csv_data)
118
            self.csv_file.flush()
119
120
121
def open_csv_file(file_name, file_mode):
122
    if PY3:
123
        csv_file = open(file_name, file_mode, newline='')
124
    else:
125
        csv_file = open(file_name, file_mode + 'b')
126
    return csv_file
127