logging init: Move to dedicated module

This commit is contained in:
Mykola Grymalyuk
2023-02-05 09:41:41 -07:00
parent cba9d1e224
commit f915199b92
4 changed files with 126 additions and 51 deletions

View File

@@ -13,7 +13,8 @@
- Skips calls to Apple's now defunct Developer Portal API - Skips calls to Apple's now defunct Developer Portal API
- Support local loose matching when no network connection is available - Support local loose matching when no network connection is available
- Implemented logging framework usage for more reliable logging - Implemented logging framework usage for more reliable logging
- Logs are stored under `~/OpenCore-Patcher-vX.Y.Z.log` - Logs are stored under `~/OpenCore-Patcher.log`
- Subsequent runs are appended to the log, allowing for easy debugging
- Implemented new network_handler.py module - Implemented new network_handler.py module
- Allows for more reliable network calls and downloads - Allows for more reliable network calls and downloads
- Better supports network timeouts and disconnects - Better supports network timeouts and disconnects

View File

@@ -41,7 +41,7 @@ class wx_python_gui:
self.hyperlink_colour = (25, 179, 231) self.hyperlink_colour = (25, 179, 231)
# Backup stdout for usage with wxPython # Backup stdout for usage with wxPython
self.stock_stream = logging.getLogger().handlers[1].stream self.stock_stream = logging.getLogger().handlers[0].stream
current_uid = os.getuid() current_uid = os.getuid()
@@ -108,7 +108,7 @@ class wx_python_gui:
def reset_window(self): def reset_window(self):
self.frame.DestroyChildren() self.frame.DestroyChildren()
self.frame.SetSize(self.WINDOW_WIDTH_MAIN, self.WINDOW_HEIGHT_MAIN) self.frame.SetSize(self.WINDOW_WIDTH_MAIN, self.WINDOW_HEIGHT_MAIN)
logging.getLogger().handlers[1].stream = self.stock_stream logging.getLogger().handlers[0].stream = self.stock_stream
self.reset_frame_modal() self.reset_frame_modal()
# Re-enable sleep if we failed to do so before returning to the main menu # Re-enable sleep if we failed to do so before returning to the main menu
@@ -707,7 +707,7 @@ class wx_python_gui:
self.stdout_text.SetValue("") self.stdout_text.SetValue("")
# Set StreamHandler to redirect stdout to textbox # Set StreamHandler to redirect stdout to textbox
logging.getLogger().handlers[1].stream = menu_redirect.RedirectText(self.stdout_text, False) logging.getLogger().handlers[0].stream = menu_redirect.RedirectText(self.stdout_text, False)
self.return_to_main_menu = wx.Button(self.frame_modal, label="Return to Main Menu") self.return_to_main_menu = wx.Button(self.frame_modal, label="Return to Main Menu")
self.return_to_main_menu.SetPosition( self.return_to_main_menu.SetPosition(
@@ -735,7 +735,7 @@ class wx_python_gui:
self.build_opencore.Bind(wx.EVT_BUTTON, self.install_menu) self.build_opencore.Bind(wx.EVT_BUTTON, self.install_menu)
# Reset stdout # Reset stdout
logging.getLogger().handlers[1].stream = self.stock_stream logging.getLogger().handlers[0].stream = self.stock_stream
# Throw popup asking to install OpenCore # Throw popup asking to install OpenCore
self.dialog = wx.MessageDialog( self.dialog = wx.MessageDialog(
@@ -966,9 +966,9 @@ class wx_python_gui:
self.frame_modal.SetSize(-1, self.stdout_text.GetPosition().y + self.stdout_text.GetSize().height + 40) self.frame_modal.SetSize(-1, self.stdout_text.GetPosition().y + self.stdout_text.GetSize().height + 40)
self.frame_modal.ShowWindowModal() self.frame_modal.ShowWindowModal()
logging.getLogger().handlers[1].stream = menu_redirect.RedirectText(self.stdout_text, False) logging.getLogger().handlers[0].stream = menu_redirect.RedirectText(self.stdout_text, False)
result = install.tui_disk_installation(self.constants).install_opencore(partition) result = install.tui_disk_installation(self.constants).install_opencore(partition)
logging.getLogger().handlers[1].stream = self.stock_stream logging.getLogger().handlers[0].stream = self.stock_stream
self.return_to_main_menu = wx.Button(self.frame_modal, label="Return to Main Menu") self.return_to_main_menu = wx.Button(self.frame_modal, label="Return to Main Menu")
self.return_to_main_menu.SetPosition( self.return_to_main_menu.SetPosition(
@@ -1392,7 +1392,7 @@ class wx_python_gui:
self.frame_modal.SetSize(self.WINDOW_WIDTH_BUILD, self.return_to_main_menu.GetPosition().y + self.return_to_main_menu.GetSize().height + 40) self.frame_modal.SetSize(self.WINDOW_WIDTH_BUILD, self.return_to_main_menu.GetPosition().y + self.return_to_main_menu.GetSize().height + 40)
logging.getLogger().handlers[1].stream = menu_redirect.RedirectText(self.text_box, True) logging.getLogger().handlers[0].stream = menu_redirect.RedirectText(self.text_box, True)
self.frame_modal.ShowWindowModal() self.frame_modal.ShowWindowModal()
wx.GetApp().Yield() wx.GetApp().Yield()
try: try:
@@ -1400,7 +1400,7 @@ class wx_python_gui:
except Exception as e: except Exception as e:
self.text_box.AppendText(f"- An internal error occurred while running the Root Patcher:\n{str(e)}") self.text_box.AppendText(f"- An internal error occurred while running the Root Patcher:\n{str(e)}")
pass pass
logging.getLogger().handlers[1].stream = self.stock_stream logging.getLogger().handlers[0].stream = self.stock_stream
if self.constants.root_patcher_succeeded is True: if self.constants.root_patcher_succeeded is True:
logging.info("- Root Patcher finished successfully") logging.info("- Root Patcher finished successfully")
if self.constants.needs_to_open_preferences is True: if self.constants.needs_to_open_preferences is True:
@@ -1501,7 +1501,7 @@ class wx_python_gui:
self.frame_modal.SetSize(-1, self.return_to_main_menu.GetPosition().y + self.return_to_main_menu.GetSize().height + 40) self.frame_modal.SetSize(-1, self.return_to_main_menu.GetPosition().y + self.return_to_main_menu.GetSize().height + 40)
# Start reverting root patches # Start reverting root patches
logging.getLogger().handlers[1].stream = menu_redirect.RedirectText(self.text_box, True) logging.getLogger().handlers[0].stream = menu_redirect.RedirectText(self.text_box, True)
wx.GetApp().Yield() wx.GetApp().Yield()
self.frame_modal.ShowWindowModal() self.frame_modal.ShowWindowModal()
while self.is_unpack_finished() is False: while self.is_unpack_finished() is False:
@@ -1511,7 +1511,7 @@ class wx_python_gui:
except Exception as e: except Exception as e:
self.text_box.AppendText(f"- An internal error occurred while running the Root Patcher:\n{str(e)}") self.text_box.AppendText(f"- An internal error occurred while running the Root Patcher:\n{str(e)}")
pass pass
logging.getLogger().handlers[1].stream = self.stock_stream logging.getLogger().handlers[0].stream = self.stock_stream
if self.constants.root_patcher_succeeded is True: if self.constants.root_patcher_succeeded is True:
logging.info("- Root Patcher finished successfully") logging.info("- Root Patcher finished successfully")
self.reboot_system(message="Root Patcher finished successfully\nWould you like to reboot now?") self.reboot_system(message="Root Patcher finished successfully\nWould you like to reboot now?")

View File

@@ -0,0 +1,95 @@
import logging
import sys
import threading
from pathlib import Path
class InitializeLoggingSupport:
def __init__(self) -> None:
self.log_filename: str = f"OpenCore-Patcher.log"
self.log_filepath: Path = None
self.max_file_size: int = 1024 * 1024 * 10
self.file_size_redline: int = 1024 * 1024 * 9 # When to start cleaning log file
self._initialize_logging_path()
self._clean_log_file()
self._initialize_logging_configuration()
self._implement_custom_traceback_handler()
def _initialize_logging_path(self):
"""
Initialize logging framework storage path
"""
self.log_filepath = Path(f"~/Library/Logs/{self.log_filename}").expanduser()
if self.log_filepath.parent.exists():
return
# Likely in an installer environment, store in /Users/Shared
self.log_filepath = Path("/Users/Shared") / self.log_filename
def _clean_log_file(self):
"""
Determine if log file should be cleaned
We check if we're near the max file size, and if so, we clean the log file
"""
if self.log_filepath.stat().st_size < self.file_size_redline:
return
# Check if backup log file exists
backup_log_filepath = self.log_filepath.with_suffix(".old.log")
if backup_log_filepath.exists():
backup_log_filepath.unlink()
# Rename current log file to backup log file
self.log_filepath.rename(backup_log_filepath)
def _initialize_logging_configuration(self):
"""
Initialize logging framework configuration
StreamHandler's format is used to mimic the default behavior of print()
While FileHandler's format is for more in-depth logging
"""
logging.basicConfig(
level=logging.NOTSET,
format="%(asctime)s - %(filename)s (%(lineno)d): %(message)s",
handlers=[
logging.StreamHandler(),
logging.FileHandler(self.log_filepath),
],
)
logging.getLogger().setLevel(logging.INFO)
logging.getLogger().handlers[0].setFormatter(logging.Formatter("%(message)s"))
logging.getLogger().handlers[1].maxBytes = self.max_file_size
def _implement_custom_traceback_handler(self):
"""
Reroute traceback to logging module
"""
def custom_excepthook(type, value, tb):
"""
Reroute traceback in main thread to logging module
"""
logging.error("Uncaught exception in main thread", exc_info=(type, value, tb))
def custom_thread_excepthook(args):
"""
Reroute traceback in spawned thread to logging module
"""
logging.error("Uncaught exception in spawned thread", exc_info=(args))
sys.excepthook = custom_excepthook
threading.excepthook = custom_thread_excepthook

View File

@@ -1,22 +1,35 @@
# Copyright (C) 2020-2022, Dhinak G, Mykola Grymalyuk # Copyright (C) 2020-2022, Dhinak G, Mykola Grymalyuk
import subprocess
import sys import sys
from pathlib import Path
import time import time
import threading
import logging import logging
import threading import threading
import subprocess
from pathlib import Path
from resources import cli_menu, constants, utilities, device_probe, os_probe, defaults, arguments, install, tui_helpers, reroute_payloads, commit_info
from resources.build import build
from data import model_array from data import model_array
from resources.build import build
from resources import (
cli_menu,
constants,
utilities,
device_probe,
os_probe,
defaults,
arguments,
install,
tui_helpers,
reroute_payloads,
commit_info,
logging_handler
)
class OpenCoreLegacyPatcher: class OpenCoreLegacyPatcher:
def __init__(self, launch_gui=False): def __init__(self, launch_gui=False):
self.constants = constants.Constants() self.constants = constants.Constants()
self.constants.wxpython_variant = launch_gui self.constants.wxpython_variant = launch_gui
self.initialize_logging() logging_handler.InitializeLoggingSupport()
logging.info(f"- Loading OpenCore Legacy Patcher v{self.constants.patcher_version}...") logging.info(f"- Loading OpenCore Legacy Patcher v{self.constants.patcher_version}...")
@@ -29,40 +42,6 @@ class OpenCoreLegacyPatcher:
else: else:
self.main_menu() self.main_menu()
def initialize_logging(self):
LOG_FILENAME = f"OpenCore-Patcher-v{self.constants.patcher_version}.log"
LOG_FILEPATH = Path(f"~/Library/Logs/{LOG_FILENAME}").expanduser()
if not LOG_FILEPATH.parent.exists():
# Likely in an installer environment, store in /Users/Shared
LOG_FILEPATH = Path("/Users/Shared") / LOG_FILENAME
logging.basicConfig(
level=logging.NOTSET,
format="%(asctime)s - %(filename)s (%(lineno)d): %(message)s",
handlers=[
logging.FileHandler(LOG_FILEPATH),
logging.StreamHandler(),
],
)
logging.getLogger().handlers[1].setFormatter(logging.Formatter("%(message)s"))
logging.getLogger().setLevel(logging.INFO)
logging.getLogger().handlers[1].maxBytes = 1024 * 1024 * 10
self.implement_custom_traceback_handler()
def implement_custom_traceback_handler(self):
# Reroute traceback to logging
def custom_excepthook(type, value, tb):
logging.error("Uncaught exception in main thread", exc_info=(type, value, tb))
def custom_thread_excepthook(args):
logging.error("Uncaught exception in spawned thread", exc_info=(args))
sys.excepthook = custom_excepthook
threading.excepthook = custom_thread_excepthook
def generate_base_data(self): def generate_base_data(self):
self.constants.detected_os = os_probe.detect_kernel_major() self.constants.detected_os = os_probe.detect_kernel_major()