[object Object]

← back to Exo

feature: Simplest utilities for logging

7dd8a979d200ed3d9b29a8fe20211e6985bdd3d4 · 2025-07-02 22:13:42 +0100 · Arbion Halili

Files touched

Diff

commit 7dd8a979d200ed3d9b29a8fe20211e6985bdd3d4
Author: Arbion Halili <99731180+ToxicPine@users.noreply.github.com>
Date:   Wed Jul 2 22:13:42 2025 +0100

    feature: Simplest utilities for logging
---
 shared/logger.py      | 44 +++++++++++++++++++++++++++++++++++++++-----
 shared/pyproject.toml |  1 -
 uv.lock               | 11 -----------
 3 files changed, 39 insertions(+), 17 deletions(-)

diff --git a/shared/logger.py b/shared/logger.py
index 1d522fc2..659f551e 100644
--- a/shared/logger.py
+++ b/shared/logger.py
@@ -1,21 +1,48 @@
 import logging
 import logging.handlers
-from collections.abc import Sequence
+from collections.abc import Sequence, Set
+from enum import Enum
 from queue import Queue
 
+from pydantic import BaseModel
 from rich.logging import RichHandler
 
 
+class LogEntryType(str, Enum):
+    telemetry = "telemetry"
+    metrics = "metrics"
+    cluster = "cluster"
+
+
+class LogEntry(BaseModel):
+    event_type: Set[LogEntryType]
+
+
+class LogFilterByType(logging.Filter):
+    def __init__(self, log_types: Set[LogEntryType]):
+        super().__init__()
+        self.log_types = log_types
+
+    def filter(self, record: logging.LogRecord) -> bool:
+        message = record.getMessage()
+        LogEntry.model_validate_json(message)
+        return True
+
+
 def configure_logger(
     logger_name: str,
     log_level: int = logging.INFO,
     effect_handlers: Sequence[logging.Handler] | None = None,
 ) -> logging.Logger:
+    existing_logger = logging.Logger.manager.loggerDict.get(logger_name)
+    if existing_logger is not None:
+        raise RuntimeError(f"Logger with name '{logger_name}' already exists.")
+
     logger = logging.getLogger(logger_name)
     logger.setLevel(log_level)
     logger.propagate = False
+    logging.raiseExceptions = True
 
-    # If the named logger already has handlers, we assume it has been configured.
     if logger.hasHandlers():
         return logger
 
@@ -33,13 +60,20 @@ def configure_logger(
     return logger
 
 
-def attach_to_queue(logger: logging.Logger, queue: Queue[logging.LogRecord]) -> None:
-    logger.addHandler(logging.handlers.QueueHandler(queue))
+def attach_to_queue(
+    logger: logging.Logger,
+    filter_with: Sequence[logging.Filter],
+    queue: Queue[logging.LogRecord],
+) -> None:
+    handler = logging.handlers.QueueHandler(queue)
+    for log_filter in filter_with:
+        handler.addFilter(log_filter)
+    logger.addHandler(handler)
 
 
 def create_queue_listener(
     log_queue: Queue[logging.LogRecord],
-    effect_handlers: list[logging.Handler],
+    effect_handlers: Sequence[logging.Handler],
 ) -> logging.handlers.QueueListener:
     listener = logging.handlers.QueueListener(
         log_queue, *effect_handlers, respect_handler_level=True
diff --git a/shared/pyproject.toml b/shared/pyproject.toml
index 5721f6ad..d4ee919e 100644
--- a/shared/pyproject.toml
+++ b/shared/pyproject.toml
@@ -10,7 +10,6 @@ dependencies = [
     "protobuf>=6.31.1",
     "pydantic>=2.11.7",
     "rich>=14.0.0",
-    "structlog>=25.4.0",
 ]
 
 [build-system]
diff --git a/uv.lock b/uv.lock
index b76dd752..d08efbb3 100644
--- a/uv.lock
+++ b/uv.lock
@@ -141,7 +141,6 @@ dependencies = [
     { name = "protobuf", marker = "sys_platform == 'darwin' or sys_platform == 'linux'" },
     { name = "pydantic", marker = "sys_platform == 'darwin' or sys_platform == 'linux'" },
     { name = "rich", marker = "sys_platform == 'darwin' or sys_platform == 'linux'" },
-    { name = "structlog", marker = "sys_platform == 'darwin' or sys_platform == 'linux'" },
 ]
 
 [package.dev-dependencies]
@@ -156,7 +155,6 @@ requires-dist = [
     { name = "protobuf", specifier = ">=6.31.1" },
     { name = "pydantic", specifier = ">=2.11.7" },
     { name = "rich", specifier = ">=14.0.0" },
-    { name = "structlog", specifier = ">=25.4.0" },
 ]
 
 [package.metadata.requires-dev]
@@ -488,15 +486,6 @@ wheels = [
     { url = "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl", hash = "sha256:2f6da418d1f1e0fddd844478f41680e794e6051915791a034ff65e5f100525a2", size = 10235, upload-time = "2024-02-25T23:20:01.196Z" },
 ]
 
-[[package]]
-name = "structlog"
-version = "25.4.0"
-source = { registry = "https://pypi.org/simple" }
-sdist = { url = "https://files.pythonhosted.org/packages/79/b9/6e672db4fec07349e7a8a8172c1a6ae235c58679ca29c3f86a61b5e59ff3/structlog-25.4.0.tar.gz", hash = "sha256:186cd1b0a8ae762e29417095664adf1d6a31702160a46dacb7796ea82f7409e4", size = 1369138, upload-time = "2025-06-02T08:21:12.971Z" }
-wheels = [
-    { url = "https://files.pythonhosted.org/packages/a0/4a/97ee6973e3a73c74c8120d59829c3861ea52210667ec3e7a16045c62b64d/structlog-25.4.0-py3-none-any.whl", hash = "sha256:fe809ff5c27e557d14e613f45ca441aabda051d119ee5a0102aaba6ce40eed2c", size = 68720, upload-time = "2025-06-02T08:21:11.43Z" },
-]
-
 [[package]]
 name = "tqdm"
 version = "4.67.1"

← 40793f1d refactor: Refactor most things  ·  back to Exo  ·  feature: Interfaces for graph interfaces 4bb3a995 →