From b4f46ad31e3b7f009cbd93787395d9f7561e55d8 Mon Sep 17 00:00:00 2001 From: K4YT3X Date: Sun, 13 Sep 2020 16:38:44 -0400 Subject: [PATCH] enhanced logging and error reporting system --- src/bilogger.py | 13 ++++++------- src/video2x.py | 37 +++++++++++++++++++++++++++---------- src/video2x_gui.py | 43 +++++++++++++++++++++++++++++-------------- src/video2x_gui.ui | 7 ------- 4 files changed, 62 insertions(+), 38 deletions(-) diff --git a/src/bilogger.py b/src/bilogger.py index cbb23d7..6d533f1 100755 --- a/src/bilogger.py +++ b/src/bilogger.py @@ -4,12 +4,11 @@ Creator: Video2X Bidirectional Logger Author: K4YT3X Date Created: June 4, 2020 -Last Modified: July 17, 2020 +Last Modified: September 13, 2020 """ # built-in imports import _io -import pathlib class BiLogger(object): @@ -19,15 +18,15 @@ class BiLogger(object): Original code from: https://stackoverflow.com/a/14906787 """ - def __init__(self, terminal: _io.TextIOWrapper, logfile: pathlib.Path): + def __init__(self, terminal: _io.TextIOWrapper, log_file: _io.BufferedRandom): """ initialize BiLogger Args: terminal (_io.TextIOWrapper): original terminal IO wrapper - logfile (pathlib.Path): target log file path object + logfile (_io.BufferedRandom): log file wrapper """ self.terminal = terminal - self.log = logfile.open(mode='a+', encoding='utf-8') + self.log_file = log_file def write(self, message: str): """ write message to original terminal output and log file @@ -37,8 +36,8 @@ class BiLogger(object): """ self.terminal.write(message) self.terminal.flush() - self.log.write(message) - self.log.flush() + self.log_file.write(message) + self.log_file.flush() def flush(self): """ flush logger (for compability only) diff --git a/src/video2x.py b/src/video2x.py index e4e3501..4c5e6ef 100755 --- a/src/video2x.py +++ b/src/video2x.py @@ -56,7 +56,6 @@ from upscaler import Upscaler # built-in imports import argparse -import datetime import gettext import importlib import locale @@ -81,7 +80,7 @@ language = gettext.translation(DOMAIN, LOCALE_DIRECTORY, [default_locale], fallb language.install() _ = language.gettext -CLI_VERSION = '4.3.0' +CLI_VERSION = '4.3.1' LEGAL_INFO = _('''Video2X CLI Version: {} Upscaler Version: {} @@ -119,9 +118,7 @@ def parse_arguments(): video2x_options.add_argument('-c', '--config', type=pathlib.Path, help=_('video2x config file path'), action='store', default=pathlib.Path(__file__).parent.absolute() / 'video2x.yaml') - video2x_options.add_argument('--log', type=pathlib.Path, help=_('log file path'), - default=pathlib.Path(__file__).parent.absolute() / f'video2x_{datetime.datetime.now().strftime("%Y-%m-%d_%H-%M-%S")}.log') - video2x_options.add_argument('--disable_logging', help=_('disable logging'), action='store_true') + video2x_options.add_argument('--log', type=pathlib.Path, help=_('log file path')) video2x_options.add_argument('-v', '--version', help=_('display version, lawful information and exit'), action='store_true') # scaling options @@ -191,11 +188,15 @@ if video2x_args.ratio is not None and (video2x_args.width is not None or video2x sys.exit(1) # redirect output to both terminal and log file -if video2x_args.disable_logging is False: - LOGFILE = video2x_args.log - Avalon.debug_info(_('Redirecting console logs to {}').format(LOGFILE)) - sys.stdout = BiLogger(sys.stdout, LOGFILE) - sys.stderr = BiLogger(sys.stderr, LOGFILE) +if video2x_args.log is not None: + log_file = video2x_args.log.open(mode='a+', encoding='utf-8') +else: + log_file = tempfile.TemporaryFile(mode='a+', suffix='.log', prefix='video2x_', encoding='utf-8') + +original_stdout = sys.stdout +original_stderr = sys.stderr +sys.stdout = BiLogger(sys.stdout, log_file) +sys.stderr = BiLogger(sys.stderr, log_file) # read configurations from configuration file config = read_config(video2x_args.config) @@ -272,5 +273,21 @@ try: Avalon.info(_('Program completed, taking {} seconds').format(round((time.time() - begin_time), 5))) except Exception: + Avalon.error(_('An exception has occurred')) traceback.print_exc() + + if video2x_args.log is not None: + log_file_path = video2x_args.log.absolute() + else: + log_file_path = tempfile.mkstemp(suffix='.log', prefix='video2x_')[1] + with open(log_file_path, 'w', encoding='utf-8') as permanent_log_file: + log_file.seek(0) + permanent_log_file.write(log_file.read()) + + Avalon.error(_('The error log file can be found at: {}').format(log_file_path)) + +finally: + sys.stdout = original_stdout + sys.stderr = original_stderr + log_file.close() diff --git a/src/video2x_gui.py b/src/video2x_gui.py index db52863..09d1f73 100755 --- a/src/video2x_gui.py +++ b/src/video2x_gui.py @@ -4,7 +4,7 @@ Creator: Video2X GUI Author: K4YT3X Date Created: May 5, 2020 -Last Modified: September 12, 2020 +Last Modified: September 13, 2020 """ # local imports @@ -15,7 +15,6 @@ from wrappers.ffmpeg import Ffmpeg # built-in imports import contextlib -import datetime import json import mimetypes import os @@ -195,8 +194,10 @@ class Video2XMainWindow(QMainWindow): super().__init__(*args, **kwargs) uic.loadUi(str(resource_path('video2x_gui.ui')), self) - # generate log file name - self.logfile = pathlib.Path(__file__).parent.absolute() / f'video2x_{datetime.datetime.now().strftime("%Y-%m-%d_%H-%M-%S")}.log' + # redirect output to both terminal and log file + self.log_file = tempfile.TemporaryFile(mode='a+', suffix='.log', prefix='video2x_', encoding='utf-8') + sys.stdout = BiLogger(sys.stdout, self.log_file) + sys.stderr = BiLogger(sys.stderr, self.log_file) # create thread pool for upscaler workers self.threadpool = QThreadPool() @@ -288,7 +289,6 @@ class Video2XMainWindow(QMainWindow): self.image_output_extension_line_edit = self.findChild(QLineEdit, 'imageOutputExtensionLineEdit') self.video_output_extension_line_edit = self.findChild(QLineEdit, 'videoOutputExtensionLineEdit') self.preserve_frames_check_box = self.findChild(QCheckBox, 'preserveFramesCheckBox') - self.disable_logging_check_box = self.findChild(QCheckBox, 'disableLoggingCheckBox') # frame preview self.frame_preview_show_preview_check_box = self.findChild(QCheckBox, 'framePreviewShowPreviewCheckBox') @@ -894,6 +894,12 @@ class Video2XMainWindow(QMainWindow): return None return pathlib.Path(folder_selected) + def select_save_file(self, *args, **kwargs) -> pathlib.Path: + save_file_selected = QFileDialog.getSaveFileName(self, *args, **kwargs) + if not isinstance(save_file_selected, tuple) or save_file_selected[0] == '': + return None + return pathlib.Path(save_file_selected[0]) + def update_output_path(self): # if input list is empty # clear output path @@ -1050,6 +1056,16 @@ class Video2XMainWindow(QMainWindow): message_box.exec_() def show_error(self, exception: Exception): + + def _process_button_press(button_pressed): + # if the user pressed the save button, save log file to destination + if button_pressed.text() == 'Save': + log_file_saving_path = self.select_save_file('Select Log File Saving Destination', 'video2x_error.log') + if log_file_saving_path is not None: + with open(log_file_saving_path, 'w', encoding='utf-8') as log_file: + self.log_file.seek(0) + log_file.write(self.log_file.read()) + # QErrorMessage(self).showMessage(message.replace('\n', '
')) message_box = QMessageBox(self) message_box.setWindowTitle('Error') @@ -1058,11 +1074,15 @@ class Video2XMainWindow(QMainWindow): error_message = '''Upscaler ran into an error:\\ {}\\ -Check the console output for details.\\ -When reporting an error, please include console output.\\ +Check the console output or the log file for details.\\ You can [submit an issue on GitHub](https://github.com/k4yt3x/video2x/issues/new?assignees=K4YT3X&labels=bug&template=bug-report.md&title={}) to report this error.\\ -It\'s also highly recommended for you to attach the [log file]({}) under the programs\'s parent folder named {}.''' - message_box.setText(error_message.format(exception, urllib.parse.quote(str(exception)), self.logfile.as_uri(), self.logfile.name)) +It\'s highly recommended to attach the log file.\\ +You can click \"Save\" to save the log file.''' + message_box.setText(error_message.format(exception, urllib.parse.quote(str(exception)))) + + message_box.setStandardButtons(QMessageBox.Save | QMessageBox.Close) + message_box.setDefaultButton(QMessageBox.Save) + message_box.buttonClicked.connect(_process_button_press) message_box.exec_() def progress_monitor(self, progress_callback: pyqtSignal): @@ -1177,11 +1197,6 @@ It\'s also highly recommended for you to attach the [log file]({}) under the pro self.show_warning('Output path unspecified') return - if self.disable_logging_check_box.isChecked() is False: - print(f'Redirecting console logs to {self.logfile}', file=sys.stderr) - sys.stdout = BiLogger(sys.stdout, self.logfile) - sys.stderr = BiLogger(sys.stderr, self.logfile) - if len(self.input_table_data) == 1: input_directory = self.input_table_data[0] else: diff --git a/src/video2x_gui.ui b/src/video2x_gui.ui index 7b0ef59..388ea94 100644 --- a/src/video2x_gui.ui +++ b/src/video2x_gui.ui @@ -558,13 +558,6 @@ - - - - Disable Logging - - -