glances.exports.glances_csv.Export.update()   C
last analyzed

Complexity

Conditions 9

Size

Total Lines 40
Code Lines 22

Duplication

Lines 0
Ratio 0 %

Importance

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