Improved logging

* added logging level critical
 * critical messages will be displayed in a popup
This commit is contained in:
Christoph Stahl 2025-02-15 16:35:07 +01:00
parent 0265ddda71
commit 284eb8c6b7
2 changed files with 41 additions and 7 deletions

View file

@ -13,6 +13,7 @@ be one of:
""" """
from __future__ import annotations from __future__ import annotations
import logging
import os import os
import asyncio import asyncio
import datetime import datetime
@ -63,6 +64,7 @@ def default_config() -> dict[str, Optional[int | str]]:
"qr_box_size": 5, "qr_box_size": 5,
"qr_position": "bottom-right", "qr_position": "bottom-right",
"show_advanced": False, "show_advanced": False,
"log_level": "info",
} }
@ -112,6 +114,8 @@ class State:
- `bottom-right` - `bottom-right`
* `show_advanced` (`bool`): If the advanced options should be shown in the * `show_advanced` (`bool`): If the advanced options should be shown in the
gui. gui.
* `log_level` (`str`): The log level of the client. One of: `debug`, `info`, `warning`,
`error`, `critical`. Default is `info`.
:type config: dict[str, Any]: :type config: dict[str, Any]:
""" """
@ -130,6 +134,7 @@ class Client:
config["config"] = default_config() | config["config"] config["config"] = default_config() | config["config"]
self.is_running = False self.is_running = False
self.set_log_level(config["config"]["log_level"])
self.sio = socketio.AsyncClient(json=jsonencoder) self.sio = socketio.AsyncClient(json=jsonencoder)
self.loop: Optional[asyncio.AbstractEventLoop] = None self.loop: Optional[asyncio.AbstractEventLoop] = None
self.skipped: list[UUID] = [] self.skipped: list[UUID] = []
@ -145,6 +150,19 @@ class Client:
) )
self.register_handlers() self.register_handlers()
def set_log_level(self, level: str) -> None:
match level:
case "debug":
logger.setLevel(logging.DEBUG)
case "info":
logger.setLevel(logging.INFO)
case "warning":
logger.setLevel(logging.WARNING)
case "error":
logger.setLevel(logging.ERROR)
case "critical":
logger.setLevel(logging.CRITICAL)
def register_handlers(self) -> None: def register_handlers(self) -> None:
self.sio.on("update_config", self.handle_update_config) self.sio.on("update_config", self.handle_update_config)
self.sio.on("skip-current", self.handle_skip_current) self.sio.on("skip-current", self.handle_skip_current)
@ -174,12 +192,16 @@ class Client:
msg_type = data.get("type", "info") msg_type = data.get("type", "info")
match msg_type: match msg_type:
case "debug":
logger.debug(data["msg"])
case "info": case "info":
logger.info(data["msg"]) logger.info(data["msg"])
case "warning": case "warning":
logger.warning(data["msg"]) logger.warning(data["msg"])
case "error": case "error":
logger.error(data["msg"]) logger.error(data["msg"])
case "critical":
logger.critical(data["msg"])
async def handle_update_config(self, data: dict[str, Any]) -> None: async def handle_update_config(self, data: dict[str, Any]) -> None:
""" """
@ -427,7 +449,7 @@ class Client:
await self.sio.emit("get-first") await self.sio.emit("get-first")
else: else:
reason = data.get("reason", "Unknown") reason = data.get("reason", "Unknown")
logger.warning(f"Registration failed: {reason}") logger.critical(f"Registration failed: {reason}")
await self.sio.disconnect() await self.sio.disconnect()
async def handle_request_config(self, data: dict[str, Any]) -> None: async def handle_request_config(self, data: dict[str, Any]) -> None:
@ -543,7 +565,7 @@ class Client:
except asyncio.CancelledError: except asyncio.CancelledError:
pass pass
except ConnectionError: except ConnectionError:
logger.error("Could not connect to server") logger.critical("Could not connect to server")
finally: finally:
self.is_running = False self.is_running = False
if self.player.mpv is not None: if self.player.mpv is not None:

View file

@ -466,6 +466,13 @@ class GeneralConfig(OptionFrame):
["top-left", "top-right", "bottom-left", "bottom-right"], ["top-left", "top-right", "bottom-left", "bottom-right"],
config["qr_position"], config["qr_position"],
) )
self.add_choose_option(
"log_level",
"Log Level",
["debug", "info", "warning", "error", "critical"],
config["log_level"],
)
self.add_bool_option("show_advanced", "Show Advanced Options", config["show_advanced"])
self.simple_options = ["server", "room", "secret"] self.simple_options = ["server", "room", "secret"]
@ -658,7 +665,6 @@ class SyngGui(QMainWindow):
self.syng_client_logging_listener = QueueListener(self.logqueue, self.log_label_handler) self.syng_client_logging_listener = QueueListener(self.logqueue, self.log_label_handler)
self.syng_client_logging_listener.start() self.syng_client_logging_listener.start()
logger.setLevel(logging.DEBUG)
self.setCentralWidget(self.central_widget) self.setCentralWidget(self.central_widget)
@ -787,8 +793,14 @@ class SyngGui(QMainWindow):
self.client.quit_callback() self.client.quit_callback()
self.set_client_button_start() self.set_client_button_start()
@pyqtSlot(str) @pyqtSlot(str, int)
def print_log(self, log: str) -> None: def print_log(self, log: str, level: int) -> None:
if level == logging.CRITICAL:
log_msg_box = QMessageBox(self)
log_msg_box.setIcon(QMessageBox.Icon.Critical)
log_msg_box.setWindowTitle("Critical Error")
log_msg_box.setText(log)
log_msg_box.exec()
self.log_text.append(f"[{datetime.now().strftime('%H:%M:%S')}] {log}") self.log_text.append(f"[{datetime.now().strftime('%H:%M:%S')}] {log}")
def change_qr(self, data: str) -> None: def change_qr(self, data: str) -> None:
@ -816,7 +828,7 @@ class SyngGui(QMainWindow):
class LoggingLabelHandler(logging.Handler): class LoggingLabelHandler(logging.Handler):
class LogSignalEmiter(QObject): class LogSignalEmiter(QObject):
log_signal = pyqtSignal(str) log_signal = pyqtSignal(str, int)
def __init__(self, parent: Optional[QObject] = None): def __init__(self, parent: Optional[QObject] = None):
super().__init__(parent) super().__init__(parent)
@ -830,7 +842,7 @@ class LoggingLabelHandler(logging.Handler):
if not self._cleanup: # This could race condition, but it's not a big if not self._cleanup: # This could race condition, but it's not a big
# deal since it only causes a race condition, # deal since it only causes a race condition,
# when the program ends # when the program ends
self.log_signal_emiter.log_signal.emit(self.format(record)) self.log_signal_emiter.log_signal.emit(self.format(record), record.levelno)
def cleanup(self) -> None: def cleanup(self) -> None:
self._cleanup = True self._cleanup = True