error log

This commit is contained in:
Jesse Bannon 2023-10-20 23:53:07 -07:00
parent d2fdab9ab7
commit 7d4a5417af
5 changed files with 57 additions and 56 deletions

View file

@ -57,7 +57,7 @@ def _maybe_write_subscription_log_file(
persist_log_path = Path(config.config_options.persist_logs.logs_directory) / log_filename
if not success:
Logger.log_exit_exception(exception=exception, log_filepath=persist_log_path)
Logger.log_exception(exception=exception, log_filepath=persist_log_path)
os.makedirs(os.path.dirname(persist_log_path), exist_ok=True)
FileHandler.copy(Logger.debug_log_filename(), persist_log_path)
@ -90,7 +90,6 @@ def _download_subscriptions_from_yaml_files(
Any exception during download
"""
subscriptions: List[Subscription] = []
has_exception = False
# Load all the subscriptions first to perform all validation before downloading
for path in subscription_paths:
@ -110,7 +109,6 @@ def _download_subscriptions_from_yaml_files(
else:
subscription.download(dry_run=dry_run)
has_exception = has_exception or subscription.exception is not None
_maybe_write_subscription_log_file(
config=config,
subscription=subscription,
@ -118,9 +116,7 @@ def _download_subscriptions_from_yaml_files(
exception=subscription.exception,
)
if not has_exception:
Logger.cleanup() # Cleanup logger if no exceptions occurred
Logger.cleanup(cleanup_error_log=False)
gc.collect() # Garbage collect after each subscription download
return subscriptions

View file

@ -49,7 +49,8 @@ def output_summary(subscriptions: List[Subscription]) -> None:
summary: List[str] = []
# Initialize totals to 0
total_subs: int = 0
total_subs: int = len(subscriptions)
total_subs_str = f"Total: {total_subs}"
total_added: int = 0
total_modified: int = 0
total_removed: int = 0
@ -57,7 +58,7 @@ def output_summary(subscriptions: List[Subscription]) -> None:
total_errors: int = 0
# Initialize widths to 0
width_sub_name: int = 0
width_sub_name: int = len(total_subs_str)
width_num_entries_added: int = 0
width_num_entries_modified: int = 0
width_num_entries_removed: int = 0
@ -99,21 +100,18 @@ def output_summary(subscriptions: List[Subscription]) -> None:
)
# Add total
total_subs += 1
total_added += subscription.num_entries_added
total_modified += subscription.num_entries_modified
total_removed -= subscription.num_entries_removed
total_entries += subscription.num_entries
total_errors += int(subscription.exception is not None)
total_subs_str = f"Total: {total_subs} Subscriptions"
total_errors_str = (
_green("All Successful")
_green("success!")
if total_errors == 0
else _red(f"{total_errors} Error{'s' if total_errors > 1 else ''}")
else _red(f"{total_errors} error{'s' if total_errors > 1 else ''}")
)
summary.append("") # new line
summary.append(
f"{total_subs_str:<{width_sub_name}} "
f"{_color_int(total_added):>{width_num_entries_added}} "
@ -125,7 +123,7 @@ def output_summary(subscriptions: List[Subscription]) -> None:
if total_errors > 0:
summary.append("")
summary.append(f"See `{Logger.debug_log_filename()}` for details on errors.")
summary.append(f"See `{Logger.error_log_filename()}` for details on errors.")
summary.append("Consider making a GitHub issue including the uploaded log file.")
# Hack to always show download summary, even if logs are set to quiet

View file

@ -24,9 +24,9 @@ def main():
"""
try:
_main()
Logger.cleanup() # Ran successfully, so we can delete the debug file
Logger.cleanup(cleanup_error_log=True) # Ran successfully, so we can delete the debug file
except Exception as exc: # pylint: disable=broad-except
Logger.log_exit_exception(exception=exc)
Logger.log_exception(exception=exc)
sys.exit(1)
sys.exit(0)

View file

@ -91,11 +91,9 @@ class Logger:
# Ignore 'using with' warning since this will be cleaned up later
# pylint: disable=R1732
_DEBUG_LOGGER_FILE = tempfile.NamedTemporaryFile(prefix="ytdl-sub.", delete=False)
_ERROR_LOG_FILE = tempfile.NamedTemporaryFile(prefix="ytdl-sub.errors", delete=False)
# pylint: enable=R1732
# Whether the final exception lines were added to the debug log
_LOGGED_EXIT_EXCEPTION: bool = False
# Keep track of all Loggers created
_LOGGERS: List[logging.Logger] = []
@ -108,6 +106,10 @@ class Logger:
"""
return cls._DEBUG_LOGGER_FILE.name
@classmethod
def error_log_filename(cls) -> str:
return cls._ERROR_LOG_FILE.name
@classmethod
def set_log_level(cls, log_level_name: str):
"""
@ -204,7 +206,7 @@ class Logger:
redirect_stream.flush()
@classmethod
def log_exit_exception(cls, exception: Exception, log_filepath: Optional[Path] = None):
def log_exception(cls, exception: Exception, log_filepath: Optional[Path] = None):
"""
Performs the final log before exiting from an error
@ -215,34 +217,37 @@ class Logger:
log_filepath
Optional. The filepath to the debug logs
"""
if not cls._LOGGED_EXIT_EXCEPTION:
logger = cls.get()
logger = cls.get()
# Log validation exceptions as-is
if isinstance(exception, ValidationException):
logger.error(str(exception))
# Log permission errors explicitly
elif isinstance(exception, PermissionError):
logger.error(
"A permission error occurred:\n%s\n"
"The user running ytdl-sub must have permission to this file/directory.",
str(exception),
)
# For other uncaught errors, log as bug:
else:
logger.exception("An uncaught error occurred:")
logger.error(
"Version %s\nPlease upload the error log file '%s' and make a Github "
"issue at https://github.com/jmbannon/ytdl-sub/issues with your config and "
"command/subscription yaml file to reproduce. Thanks for trying ytdl-sub!",
__local_version__,
log_filepath if log_filepath else Logger.debug_log_filename(),
)
# Log validation exceptions as-is
if isinstance(exception, ValidationException):
logger.error(str(exception))
# Log permission errors explicitly
elif isinstance(exception, PermissionError):
logger.error(
"A permission error occurred:\n%s\n"
"The user running ytdl-sub must have permission to this file/directory.",
str(exception),
)
# For other uncaught errors, log as bug:
else:
logger.exception("An uncaught error occurred:")
logger.error(
"Version %s\nPlease upload the error log file '%s' and make a Github "
"issue at https://github.com/jmbannon/ytdl-sub/issues with your config and "
"command/subscription yaml file to reproduce. Thanks for trying ytdl-sub!",
__local_version__,
log_filepath if log_filepath else Logger.error_log_filename(),
)
cls._LOGGED_EXIT_EXCEPTION = True
# Any time an exception occurs, dump all debug logs into the error log
with open(cls.debug_log_filename(), mode="r", encoding="utf-8") as debug_logs, open(
cls.error_log_filename(), mode="a", encoding="utf-8"
) as error_logs:
error_logs.writelines(debug_logs.readlines())
@classmethod
def cleanup(cls):
def cleanup(cls, cleanup_error_log: bool = False):
"""
Cleans up debug log file left behind
"""
@ -251,6 +256,8 @@ class Logger:
handler.close()
cls._DEBUG_LOGGER_FILE.close()
FileHandler.delete(cls.debug_log_filename())
cls._LOGGED_EXIT_EXCEPTION = False
if cleanup_error_log:
cls._ERROR_LOG_FILE.close()
FileHandler.delete(cls.error_log_filename())

View file

@ -142,17 +142,17 @@ def test_subscription_logs_write_to_file(
if dry_run or (mock_success_output and not keep_successful_logs):
assert len(log_directory_files) == 0
return
# If not success, expect 1 log file
# If not success, expect 2 log files for both sub errors
elif not mock_success_output:
assert len(log_directory_files) == 1
log_path = log_directory_files[0]
assert bool(re.match(r"\d{4}-\d{2}-\d{2}-\d{6}\.john_smith\.error\.log", log_path.name))
with open(log_path, "r", encoding="utf-8") as log_file:
assert log_file.readlines()[-1] == (
f"Please upload the error log file '{str(log_path)}' and make a Github issue "
f"at https://github.com/jmbannon/ytdl-sub/issues with your config and "
f"command/subscription yaml file to reproduce. Thanks for trying ytdl-sub!\n"
)
assert len(log_directory_files) == 2
for log_path in log_directory_files:
assert bool(re.match(r"\d{4}-\d{2}-\d{2}-\d{6}\.john_smith\.error\.log", log_path.name))
with open(log_path, "r", encoding="utf-8") as log_file:
assert log_file.readlines()[-1] == (
f"Please upload the error log file '{str(log_path)}' and make a Github issue "
f"at https://github.com/jmbannon/ytdl-sub/issues with your config and "
f"command/subscription yaml file to reproduce. Thanks for trying ytdl-sub!\n"
)
# If success and success logging, expect 3 log files
else:
assert len(log_directory_files) == num_subscriptions