Source code for belso.utils.logging

import os
import sys
import logging
from typing import Optional, Dict, Any

# Create a dedicated logger for the belso package
logger = logging.getLogger("belso")

# Store original logger level to restore it if needed
_original_level = logger.level

[docs] def get_logger(name:Optional[str]=None) -> logging.Logger: """ Get a logger instance for a specific module within belso.\n --- ### Args - `name` (`str`): the name of the module (will be prefixed with 'belso.').\n --- ### Returns - `logging.Logger`: the logger instance. """ if name: # Check if name already starts with "belso." to avoid duplication if name.startswith("belso."): return logging.getLogger(name) else: return logging.getLogger(f"belso.{name}") return logger
[docs] def configure_logger( level: int = logging.INFO, log_file: Optional[str] = None, log_format: Optional[str] = None, propagate: bool = True, handler_config: Optional[Dict[str, Any]] = None ) -> None: """ Configure the belso logger without affecting parent loggers.\n --- ### Args - `level` (`int`): the logging level. - `log_file` (`str`): the path to the log file. - `log_format` (`str`): the log format. - `propagate` (`bool`): whether to propagate logs to parent loggers. - `handler_config` (`Dict[str, Any]`): additional configuration for handlers.\n """ # Set propagation (whether logs should be passed to parent loggers) logger.propagate = propagate # Set level if provided if level is not None: logger.setLevel(level) # Default format if not specified if log_format is None: log_format = "[%(levelname)s][%(name)s] %(message)s" # Configure handlers based on what's requested if log_file or not logger.handlers: # Clear existing handlers if we're explicitly configuring for handler in logger.handlers[:]: logger.removeHandler(handler) # Add console handler if no handlers exist or explicit config is requested console_handler = logging.StreamHandler(sys.stdout) console_handler.setLevel(level or logging.INFO) console_formatter = logging.Formatter(log_format) console_handler.setFormatter(console_formatter) logger.addHandler(console_handler) # Add file handler if requested if log_file: try: os.makedirs(os.path.dirname(os.path.abspath(log_file)), exist_ok=True) file_handler = logging.FileHandler(log_file) file_handler.setLevel(level or logging.INFO) file_formatter = logging.Formatter(log_format) file_handler.setFormatter(file_formatter) logger.addHandler(file_handler) except (OSError, IOError) as e: # Don't fail if log file can't be created, just log a warning console_handler.setLevel(logging.WARNING) logger.warning(f"Could not create log file at {log_file}: {e}") # Apply any additional handler configuration if handler_config: for handler in logger.handlers: for key, value in handler_config.items(): if hasattr(handler, key): setattr(handler, key, value)
[docs] def disable_logging() -> None: """ Temporarily disable belso logging. """ global _original_level _original_level = logger.level logger.setLevel(logging.CRITICAL + 1)
[docs] def restore_logging() -> None: """ Restore belso logging to its previous state. """ logger.setLevel(_original_level)
[docs] def log_exception( e: Exception, message: str = "An error occurred" ) -> None: """ Log an exception with consistent formatting.\n --- ### Args - `e` (`Exception`): the exception to log. - `message` (`str`): a message to accompany the exception. """ logger.error(f"{message}: {str(e)}") logger.debug("Exception details", exc_info=True)