From 94d6ae410140c56f7310210dc1d754d25e4c46e9 Mon Sep 17 00:00:00 2001 From: grglcy Date: Sat, 18 Jan 2025 17:41:00 +0000 Subject: [PATCH] Implement logging --- src/log/__init__.py | 2 ++ src/log/log.py | 78 +++++++++++++++++++++++++++++++++++++++++++++ src/log/logcat.py | 22 +++++++++++++ 3 files changed, 102 insertions(+) create mode 100644 src/log/__init__.py create mode 100644 src/log/log.py create mode 100644 src/log/logcat.py diff --git a/src/log/__init__.py b/src/log/__init__.py new file mode 100644 index 0000000..8b8291a --- /dev/null +++ b/src/log/__init__.py @@ -0,0 +1,2 @@ +from .log import Log +from .logcat import LogCat diff --git a/src/log/log.py b/src/log/log.py new file mode 100644 index 0000000..ea0a2df --- /dev/null +++ b/src/log/log.py @@ -0,0 +1,78 @@ +from datetime import datetime +from multiprocessing import Lock +from threading import Thread +from queue import Queue, Empty + + +class Log(object): + def __init__(self, path, queue=None, print_output=True, timeout=1): + self.__terminated = False + self.file_lock = Lock() + + if not path.exists(): + path.mkdir() + elif not path.is_dir(): + raise Exception("Path exists and is not a directory") + + self.log_dir = path + self.print = print_output + self.today_date = None + self.log_file = None + + self.thread = Thread(target=self.write_loop, args=(64, timeout)) + if queue is None: + self.queue = Queue() + else: + self.queue = queue + + try: + self.thread.start() + except KeyboardInterrupt: + self.__terminated = True + except Exception: + raise Exception("Exception in main log loop.") + + def stop(self): + self.__terminated = True + + def write_loop(self, lines, timeout): + while not self.__terminated: + log_msg_list = [] + try: + while len(log_msg_list) < lines: + try: + log_line = self.queue.get(block=True, timeout=timeout) + if self.print: + print(log_line) + log_msg_list.append(f"{log_line.encode('cp1252', errors='replace').decode('cp1252')}\n") + except Empty: + break + finally: + self.write_log(log_msg_list) + self.save() + + def save(self): + self.write_log(self.queue_get_remaining()) + + def queue_get_remaining(self): + log_msg_list = [] + while True: + try: + log_msg_list.append(f"{self.queue.get(block=False)}\n") + except Empty: + break + return log_msg_list + + def set_log_file(self): + with self.file_lock: + self.today_date = datetime.today().date() + today_string = self.today_date.strftime("%Y-%m-%d") + self.log_file = self.log_dir / f"{today_string}.log" + + def write_log(self, log_msg_list: list): + if len(log_msg_list) > 0: + if self.today_date != datetime.today().date() or self.log_file is None: + self.set_log_file() + with self.file_lock: + with open(self.log_file, mode='a') as log_file: + log_file.writelines(log_msg_list) diff --git a/src/log/logcat.py b/src/log/logcat.py new file mode 100644 index 0000000..8e46b0b --- /dev/null +++ b/src/log/logcat.py @@ -0,0 +1,22 @@ +from datetime import datetime +from multiprocessing import Queue + + +class LogCat(object): + def __init__(self, log_queue: Queue, category: str): + self.queue = log_queue + + self.category = category + + def _write(self, level: str, function: str, message: str) -> None: + time = datetime.now().strftime("%Y-%m-%dT%H:%M:%S") + self.queue.put(f"{level} | {time} - {self.category.upper()}.{function.upper()}: {message}") + + def info(self, function: str, message: str) -> None: + self._write("INFO", function, message) + + def warning(self, function: str, message: str) -> None: + self._write("WARN", function, message) + + def error(self, function: str, message: str) -> None: + self._write("ERR ", function, message)