import os
import sys
from enum import IntEnum
from loguru import logger
simple_log_format_enabled = os.getenv("SIMPLE_LOG_FORMAT", "true").lower() in ("true", "1", "yes")
default_log_level = os.getenv("LOG_LEVEL", "INFO")
# Define custom log levels
class LogLevel(IntEnum):
"""Custom log levels."""
VERBOSE = 5
DEBUG = 10
INFO = 20
WARNING = 30
ERROR = 40
CRITICAL = 50
# Configuration Constants
COLORED_FORMAT = (
"{time:YYYY-MM-DD HH:mm:ss} | "
"{level: <8} | "
"{name} | "
"{file}:{line} | "
"{message}"
)
SIMPLE_COLORED_FORMAT = "{time:YYYY-MM-DD HH:mm:ss} | " "{level: <8} | " "{message}"
class LogManager:
"""Manages logger configuration."""
_instance = None
def __new__(cls):
"""Create a singleton instance."""
if cls._instance is None:
cls._instance = super(LogManager, cls).__new__(cls)
cls._instance.handler_id = None
cls._instance.current_level = default_log_level
cls._instance._initialize()
return cls._instance
def _get_format_string(self):
"""Return the appropriate format string based on LOG_FORMAT_MODE."""
if simple_log_format_enabled:
if self.current_level == "DEBUG":
return COLORED_FORMAT
return SIMPLE_COLORED_FORMAT
return COLORED_FORMAT
def _initialize(self):
"""Initialize logging with console handler."""
logger.remove() # Remove default handler
log_format = self._get_format_string()
self.handler_id = logger.add(sys.stdout, format=log_format, level=self.current_level, colorize=True)
# Add custom level only if it doesn't exist
try:
logger.level("VERBOSE", no=LogLevel.VERBOSE, color="")
except ValueError:
# Level already exists, ignore the error
pass
def get_current_log_level(self):
"""Get the current log level."""
return self.current_level
def update_log_level(self, level):
"""Update the log level of the console handler.
This can be called at any time during runtime to change the log level.
"""
level = level.upper()
if level not in ["VERBOSE", "DEBUG", "INFO", "WARNING", "ERROR", "CRITICAL"]:
raise ValueError(f"Invalid log level: {level}")
logger.remove(self.handler_id)
self.current_level = level
log_format = self._get_format_string()
self.handler_id = logger.add(sys.stdout, format=log_format, level=self.current_level, colorize=True)
# Instantiate LogManager to ensure logging is initialized on module import
log_manager = LogManager()
# Add verbose method to logger
def verbose(self, message, *args, **kwargs):
"""Log a verbose message."""
self.log("VERBOSE", message, *args, **kwargs)
logger.__class__.verbose = verbose
# Function to get the logger
def get_logger(name):
"""Get a logger instance bound with a name."""
return logger.bind(name=name)