Source code for propflow.configs.loggers

"""Centralized Logger Configuration for the PropFlow Project.

This module sets up a standardized logging system for the entire application.
It uses the `colorlog` library to provide colored console output for improved
readability and also supports logging to files.

The configuration is driven by the `LoggingDefaults` and `get_validated_config`
in the `global_config_mapping` module. It initializes a root logger and provides a
custom `Logger` class that can be instantiated anywhere in the project for
consistent logging behavior.
"""

import logging
import os
import sys
from enum import Enum

import colorlog

from ..utils.path_utils import find_project_root
from .global_config_mapping import get_validated_config


# Load logging configuration
LOGGING_CONFIG = get_validated_config("logging")

# Ensure the log directory exists.
log_dir = find_project_root() / LOGGING_CONFIG["log_dir"]
os.makedirs(log_dir, exist_ok=True)

# Configure the root logger.
root_logger = logging.getLogger()
root_logger.setLevel(LOGGING_CONFIG["default_level"])

# Add a default file handler to the root logger for general debug logs.
file_handler = logging.FileHandler(os.path.join(log_dir, "debug_graph.log"))
file_handler.setFormatter(logging.Formatter(LOGGING_CONFIG["log_format"]))
root_logger.addHandler(file_handler)


class Verbose(Enum):
    """Represents different verbosity levels for logging."""

    VERBOSE = 40
    MILD = 30
    INFORMATIVE = 20
    HIGH = 10


[docs] class Logger(logging.Logger): """A custom logger that provides standardized console and file logging. This class extends the standard `logging.Logger` to automatically configure a colored console handler and an optional file handler based on the global logging configuration. Attributes: file_handler (logging.FileHandler): The handler for logging to a file, which is only created if file logging is enabled. console (colorlog.StreamHandler): The handler for logging to the console with colored output. """ def __init__(self, name: str, level: int = None, file: bool = None): """Initializes the custom logger. Args: name: The name of the logger, typically `__name__`. level: The logging level. If not provided, it defaults to the `default_level` in `LoggingDefaults`. file: Whether to enable file-based logging for this logger instance. If not provided, it defaults to `file_logging` in `LoggingDefaults`. """ if level is None: level = LOGGING_CONFIG["default_level"] if file is None: file = LOGGING_CONFIG["file_logging"] super().__init__(name, level) if file: self.file_handler = logging.FileHandler( os.path.join(log_dir, f"{name}.log") ) self.file_handler.setFormatter( logging.Formatter(LOGGING_CONFIG["file_format"]) ) self.addHandler(self.file_handler) self.propagate = ( False # Prevent logs from reaching the root logger's handlers ) self.console = colorlog.StreamHandler(sys.stdout) self.console.setFormatter( colorlog.ColoredFormatter( LOGGING_CONFIG["console_format"], log_colors=LOGGING_CONFIG["console_colors"], ) ) self.addHandler(self.console)