feat: add colored and formatted logging

Add a custom logging setup function to add custom levels and custom
formatters (partly for future use with extended logging functionality).
Also implemented a basic colored formatter to make our logs nicer.

Also improved the handling of logging in external libraries, so now we
should only get WARNings or above.

ref: N25B-233
This commit is contained in:
2025-10-31 21:22:32 +01:00
parent 657c300bc7
commit d5de644828
6 changed files with 131 additions and 8 deletions

View File

@@ -0,0 +1 @@
from .setup_logging import setup_logging

View File

@@ -0,0 +1,50 @@
import logging
import logging.config
import os
import yaml
def add_logging_level(level_name: str, level_num: int, method_name: str | None = None) -> None:
"""
Adds a logging level to the `logging` module and the
currently configured logging class.
"""
if not method_name:
method_name = level_name.lower()
if hasattr(logging, level_name):
raise AttributeError(f"{level_name} already defined in logging module")
if hasattr(logging, method_name):
raise AttributeError(f"{method_name} already defined in logging module")
if hasattr(logging.getLoggerClass(), method_name):
raise AttributeError(f"{method_name} already defined in logger class")
def log_for_level(self, message, *args, **kwargs):
if self.isEnabledFor(level_num):
self._log(level_num, message, args, **kwargs)
def log_to_root(message, *args, **kwargs):
logging.log(level_num, message, *args, **kwargs)
logging.addLevelName(level_num, level_name)
setattr(logging, level_name, level_num)
setattr(logging.getLoggerClass(), method_name, log_for_level)
setattr(logging, method_name, log_to_root)
def setup_logging(path: str = "logging_config.yaml") -> None:
if os.path.exists(path):
with open(path) as f:
try:
config = yaml.safe_load(f.read())
if "custom_levels" in config:
for level_name, level_num in config["custom_levels"].items():
add_logging_level(level_name, level_num)
logging.config.dictConfig(config)
except (AttributeError, yaml.YAMLError) as e:
logging.warning(f"Could not load logging configuration: {e}")
else:
logging.warning("Logging config file not found. Using default logging configuration.")