← back to Exo
feature: Simplest utilities for logging
7dd8a979d200ed3d9b29a8fe20211e6985bdd3d4 · 2025-07-02 22:13:42 +0100 · Arbion Halili
Files touched
M shared/logger.pyM shared/pyproject.tomlM uv.lock
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 →