diff --git a/clashroyalebuildabot/bot/bot.py b/clashroyalebuildabot/bot/bot.py index 1b13704..5aa22e9 100644 --- a/clashroyalebuildabot/bot/bot.py +++ b/clashroyalebuildabot/bot/bot.py @@ -44,7 +44,6 @@ def __init__(self, actions, config): self.auto_start = config["bot"]["auto_start_game"] self.end_of_game_clicked = False self.should_run = True - self._setup_logger() cards = [action.CARD for action in actions] if len(cards) != 8: @@ -74,20 +73,6 @@ def _log_and_wait(prefix, delay): logger.info(message) time.sleep(delay) - @staticmethod - def _setup_logger(): - config_path = os.path.join(SRC_DIR, "config.yaml") - with open(config_path, encoding="utf-8") as file: - config = yaml.safe_load(file) - log_level = config.get("bot", {}).get("log_level", "INFO").upper() - logger.remove() - logger.add(sys.stdout, level=log_level) - logger.add( - os.path.join(DEBUG_DIR, "bot.log"), - rotation="500 MB", - level=log_level, - ) - @staticmethod def _handle_keyboard_shortcut(): while True: diff --git a/clashroyalebuildabot/gui/main_window.py b/clashroyalebuildabot/gui/main_window.py index 56d6b93..57ff64e 100644 --- a/clashroyalebuildabot/gui/main_window.py +++ b/clashroyalebuildabot/gui/main_window.py @@ -1,5 +1,7 @@ from threading import Thread +from loguru import logger +from PyQt6.QtWidgets import QApplication from PyQt6.QtWidgets import QMainWindow from PyQt6.QtWidgets import QVBoxLayout from PyQt6.QtWidgets import QWidget @@ -10,6 +12,7 @@ from clashroyalebuildabot.gui.layout_setup import setup_tabs from clashroyalebuildabot.gui.layout_setup import setup_top_bar from clashroyalebuildabot.gui.styles import set_styles +from clashroyalebuildabot.utils.logger import colorize_log class MainWindow(QMainWindow): @@ -38,6 +41,14 @@ def __init__(self, config, actions): set_styles(self) start_play_button_animation(self) + def log_handler_function(self, message): + formatted_message = colorize_log(message) + self.log_display.append(formatted_message) + QApplication.processEvents() + self.log_display.verticalScrollBar().setValue( + self.log_display.verticalScrollBar().maximum() + ) + def toggle_start_stop(self): if self.is_running: self.stop_bot() @@ -66,17 +77,16 @@ def start_bot(self): self.start_stop_button.setText("■") self.play_pause_button.show() self.server_id_label.setText("Status - Running") - self.append_log("Bot started") + logger.info("Starting bot") def stop_bot(self): - if not self.bot: - return - self.bot.stop() + if self.bot: + self.bot.stop() self.is_running = False self.start_stop_button.setText("▶") self.play_pause_button.hide() self.server_id_label.setText("Status - Stopped") - self.append_log("Bot stopped") + logger.info("Bot stopped") def restart_bot(self): if self.is_running: @@ -106,11 +116,18 @@ def update_config(self): self.config["adb"]["device_serial"] = self.device_serial_input.text() def bot_task(self): - self.bot = Bot(actions=self.actions, config=self.config) - self.bot.visualizer.frame_ready.connect( - self.visualize_tab.update_frame - ) - self.bot.run() + try: + self.bot = Bot(actions=self.actions, config=self.config) + self.bot.visualizer.frame_ready.connect( + self.visualize_tab.update_frame + ) + self.bot.run() + self.stop_bot() + except Exception as e: + # output error in logger + logger.error(f"Bot crashed: {e}") + self.stop_bot() + raise def append_log(self, message): self.log_display.append(message) diff --git a/clashroyalebuildabot/utils/logger.py b/clashroyalebuildabot/utils/logger.py new file mode 100644 index 0000000..061fe93 --- /dev/null +++ b/clashroyalebuildabot/utils/logger.py @@ -0,0 +1,53 @@ +import os +import sys + +from loguru import logger +import yaml + +from clashroyalebuildabot.constants import DEBUG_DIR +from clashroyalebuildabot.constants import SRC_DIR + +COLORS = dict(context_info="#118aa2", time="#459028") + + +def setup_logger(main_window): + config_path = os.path.join(SRC_DIR, "config.yaml") + with open(config_path, encoding="utf-8") as file: + config = yaml.safe_load(file) + log_level = config.get("bot", {}).get("log_level", "INFO").upper() + logger.remove() + logger.add(sys.stdout, level=log_level) + logger.add( + os.path.join(DEBUG_DIR, "bot.log"), + rotation="500 MB", + level=log_level, + ) + logger.add( + main_window.log_handler_function, + format="{time} {level} {module}:{function}:{line} - {message}", + level=log_level, + ) + + +def colorize_log(message): + log_record = message.record + level = log_record["level"].name + time = log_record["time"].strftime("%Y-%m-%d %H:%M:%S") + module = log_record["module"] + function = log_record["function"] + line = log_record["line"] + log_message = log_record["message"] + + if level == "DEBUG": + color = "#147eb8" + elif level == "INFO": + color = "white" + level = "INFO " + elif level == "WARNING": + color = "orange" + elif level == "ERROR": + color = "red" + else: + color = "black" + + return f"""[{time}] {level} | {module}:{function}:{line} - {log_message}""" diff --git a/main.py b/main.py index 02aa774..e2a7a54 100644 --- a/main.py +++ b/main.py @@ -14,14 +14,7 @@ from clashroyalebuildabot.actions import WitchAction from clashroyalebuildabot.gui.main_window import MainWindow from clashroyalebuildabot.gui.utils import load_config - -logger.remove() -logger.add( - sys.stderr, - format="{time} {level} {message}", - backtrace=False, - diagnose=False, -) +from clashroyalebuildabot.utils.logger import setup_logger def main(): @@ -40,6 +33,7 @@ def main(): app = QApplication(sys.argv) window = MainWindow(config, actions) + setup_logger(window) window.show() sys.exit(app.exec())