Last active
February 4, 2019 02:08
-
-
Save wecsam/ffecb8066819f77ca0e789a2c39dc65e to your computer and use it in GitHub Desktop.
This tool moves all but the last N log entries from the specified file to another file.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env python3 | |
import argparse, collections, os.path, sys | |
def move_lines(fin, fout, lines_to_leave, preserve_first_line): | |
# For CSV files, preserve the first line, which is the header row. | |
if preserve_first_line: | |
first_line = next(fin) | |
else: | |
first_line = "" | |
# If the output file is new, write the first line into it. | |
if fout.tell() == 0: | |
fout.write(first_line) | |
# Maintain a circular buffer for the last N entries from the original log. | |
buffer = collections.deque() | |
# Fill the buffer with N lines. | |
for line, _ in zip(fin, range(lines_to_leave)): | |
buffer.append(line) | |
# Continue to fill the buffer, but write the oldest line to the archive in | |
# each iteration of the loop. | |
for line in fin: | |
buffer.append(line) | |
fout.write(buffer.popleft()) | |
# The buffer now contains the last N entries from the original log. | |
# Write those back into the original log. | |
fin.seek(0) | |
fin.truncate() | |
fin.write(first_line) | |
for line in buffer: | |
fin.write(line) | |
def main(argv): | |
# Parse the command-line arguments. | |
arg_parser = argparse.ArgumentParser( | |
description= | |
"This tool moves all but the last N log entries from the " | |
"specified file to another file with \" - Archive\" appended to " | |
"the name (unless the output path is overridden). If the " | |
"extension is .CSV, then the header row is preserved in the " | |
"original and copied to the archive." | |
) | |
arg_parser.add_argument("file", help="The log file") | |
arg_parser.add_argument( | |
"-n", | |
"--lines-to-leave", | |
metavar="N", | |
type=int, | |
default=1000, | |
help="The number of lines to leave in the original log file" | |
) | |
arg_parser.add_argument( | |
"-o", | |
"--out-file", | |
help="Specify this argument to override the output path." | |
) | |
parsed_args = arg_parser.parse_args(argv[1:]) | |
if parsed_args.lines_to_leave < 0: | |
arg_parser.error("The number of lines must not be negative.") | |
# Add " - Archive" to the end of the filename unless the output path was | |
# specified, in which case just use the specified output path. | |
path_without_extension, extension = os.path.splitext(parsed_args.file) | |
if parsed_args.out_file is None: | |
path_in = path_without_extension + extension | |
path_out = path_without_extension + " - Archive" + extension | |
else: | |
path_in = parsed_args.file | |
path_out = parsed_args.out_file | |
print("Source:", path_in) | |
print("Destination:", path_out) | |
# Check whether this is a CSV file. | |
is_csv = extension.upper() == ".CSV" | |
print("This", "is" if is_csv else "is not", "a CSV file.") | |
# Try to open the two files. | |
try: | |
fin = open(path_in, "r+", encoding="UTF-8") | |
except OSError as e: | |
arg_parser.error("Could not open original log file: " + str(e)) | |
try: | |
fout = open(path_out, "a", encoding="UTF-8") | |
except OSError as e: | |
arg_parser.error("Could not open archive file: " + str(e)) | |
# Move all but the last N log entries to the archive file. | |
with fin, fout: | |
move_lines(fin, fout, parsed_args.lines_to_leave, is_csv) | |
print("Done.") | |
if __name__ == "__main__": | |
# I have main() accept any list of arguments to make this easier to call | |
# from another Python script or from the interactive interpreter. | |
main(sys.argv) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment