From 0be5c24ae900fda9461bdf4d0cc9b68c4010a85e Mon Sep 17 00:00:00 2001 From: nicolargo Date: Sun, 11 Aug 2019 20:11:13 +0200 Subject: [PATCH] Make CSV export append instead of replace #1525 --- docs/gw/csv.rst | 14 +++++++-- glances/exports/glances_csv.py | 54 +++++++++++++++++++++++++++++----- glances/main.py | 2 ++ 3 files changed, 61 insertions(+), 9 deletions(-) diff --git a/docs/gw/csv.rst b/docs/gw/csv.rst index 3e766e0a..4c477be2 100644 --- a/docs/gw/csv.rst +++ b/docs/gw/csv.rst @@ -11,5 +11,15 @@ It's possible to export stats to a CSV file. CSV file description: -- Stats description (first line) -- Stats (other lines) +- first line: Stats description (header) +- others lines: Stats (data) + +By default, data will be append any existing CSV file. + +If the header did not match with a previous one, an error is logged. + +The --export-csv-overwrite tag should be used if you want to delete the existing CSV file when Glances starts. + +It is possible to remove some exported data using the --disable-plugin tag: + + $ glances --export csv --export-csv-file /tmp/glances.csv --disable-plugin load,swap diff --git a/glances/exports/glances_csv.py b/glances/exports/glances_csv.py index 7c680306..4e198809 100644 --- a/glances/exports/glances_csv.py +++ b/glances/exports/glances_csv.py @@ -19,6 +19,7 @@ """CSV interface class.""" +import os.path import csv import sys import time @@ -40,11 +41,27 @@ class Export(GlancesExport): self.csv_filename = args.export_csv_file # Set the CSV output file + # (see https://github.com/nicolargo/glances/issues/1525) + if not os.path.isfile(self.csv_filename) or args.export_csv_overwrite: + # File did not exist, create it + file_mode = 'w' + self.old_header = None + else: + # A CSV file already exit, append new data + file_mode = 'a' + # Header will be check later + # Get the existing one + try: + self.csv_file = open_csv_file(self.csv_filename, 'r') + reader = csv.reader(self.csv_file) + except IOError as e: + logger.critical("Cannot open existing CSV file: {}".format(e)) + sys.exit(2) + self.old_header = next(reader, None) + self.csv_file.close() + try: - if PY3: - self.csv_file = open(self.csv_filename, 'w', newline='') - else: - self.csv_file = open(self.csv_filename, 'wb') + self.csv_file = open_csv_file(self.csv_filename, file_mode) self.writer = csv.writer(self.csv_file) except IOError as e: logger.critical("Cannot create the CSV file: {}".format(e)) @@ -91,8 +108,31 @@ class Export(GlancesExport): csv_data += itervalues(all_stats[plugin]) # Export to CSV + # Manage header if self.first_line: - self.writer.writerow(csv_header) + if self.old_header is None: + # New file, write the header on top on the CSV file + self.writer.writerow(csv_header) + # File already exist, check if header are compatible + if self.old_header != csv_header: + # Header are differents, log an error and do not write data + logger.error("Cannot append data to existing CSV file. Headers are differents.") + logger.debug("Old header: {}".format(self.old_header)) + logger.debug("New header: {}".format(csv_header)) + else: + # Header are equals, ready to write data + self.old_header = None + # Only do this once self.first_line = False - self.writer.writerow(csv_data) - self.csv_file.flush() + # Manage data + if self.old_header is None: + self.writer.writerow(csv_data) + self.csv_file.flush() + + +def open_csv_file(file_name, file_mode): + if PY3: + csv_file = open(file_name, file_mode, newline='') + else: + csv_file = open(file_name, file_mode + 'b') + return csv_file diff --git a/glances/main.py b/glances/main.py index ad55b82a..24efe84a 100644 --- a/glances/main.py +++ b/glances/main.py @@ -169,6 +169,8 @@ Examples of use: default='./glances.csv', dest='export_csv_file', help='file path for CSV exporter') + parser.add_argument('--export-csv-overwrite', action='store_true', default=False, + dest='export_csv_overwrite', help='overwrite existing CSV file') parser.add_argument('--export-json-file', default='./glances.json', dest='export_json_file', -- GitLab