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())