A7m0d's picture
Upload folder using huggingface_hub
7dfe46c verified
import logging
import os
import yaml
from datetime import datetime
import sys
from typing import List
class CustomLoggerTracker:
_instance = None
_initialized = False
def __new__(cls, config_path='logging_config.yaml'):
"""Singleton pattern to ensure only one instance exists."""
if cls._instance is None:
cls._instance = super(CustomLoggerTracker, cls).__new__(cls)
return cls._instance
def __init__(self, config_path='logging_config.yaml'):
"""Initialize the custom logger with configuration."""
if self._initialized:
return
self.config = self._load_config(config_path)
self.loggers = {}
self.base_log_dir = self.config.get('base_log_dir', 'logs')
self._setup_base_directory()
self._initialized = True
def _load_config(self, config_path):
"""Load configuration from YAML file."""
try:
with open(config_path, 'r') as file:
return yaml.safe_load(file)
except FileNotFoundError:
# Default configuration if file not found
return {
'base_log_dir': 'logs',
'default_level': 'INFO',
'format': '%(asctime)s - %(name)s - %(levelname)s - %(message)s',
'console_output': True,
'modules': {
'main': {'level': 'INFO'},
'utils': {'level': 'INFO'},
'old_docs': {'level': 'INFO'},
'rag': {'level': 'INFO'},
'query_utils': {'level': 'INFO'},
'prompt_temp': {'level': 'INFO'}
}
}
def _setup_base_directory(self):
"""Setup the base directory structure for logs."""
if not os.path.exists(self.base_log_dir):
os.makedirs(self.base_log_dir)
def _get_log_path(self, module_name):
"""Generate the hierarchical path for log files."""
now = datetime.now()
year_dir = os.path.join(self.base_log_dir, str(now.year))
month_dir = os.path.join(year_dir, f"{now.month:02d}")
day_dir = os.path.join(month_dir, f"{now.day:02d}")
os.makedirs(day_dir, exist_ok=True)
return os.path.join(day_dir, f"{module_name}.log")
def get_logger(self, module_name):
"""Get or create a logger for a specific module."""
if module_name in self.loggers:
return self.loggers[module_name]
# Create new logger & Models Specific Config
logger = logging.getLogger(module_name)
module_config = self.config['modules'].get(module_name, {})
level = getattr(logging, module_config.get('level', self.config['default_level']))
logger.setLevel(level)
# Clear existing handlers to avoid duplicates
logger.handlers.clear()
# Create formatter
formatter = logging.Formatter(self.config.get('format'))
# Create file handler with the hierarchical path
log_path = self._get_log_path(module_name)
file_handler = logging.FileHandler(log_path)
file_handler.setFormatter(formatter)
logger.addHandler(file_handler)
# Optionally add console handler
if self.config.get('console_output', True):
console_handler = logging.StreamHandler()
console_handler.setFormatter(formatter)
logger.addHandler(console_handler)
# Prevent propagation to avoid duplicate messages
logger.propagate = False
self.loggers[module_name] = logger
return logger
def update_config(self, new_config):
"""Update logger configuration."""
self.config.update(new_config)
# Reset all loggers to apply new configuration
for module_name in self.loggers:
logger = self.loggers[module_name]
for handler in logger.handlers[:]:
logger.removeHandler(handler)
self.loggers = {}
def log_message(self, process_log: List[str], message: str, level: str = "info", module: str = "default") -> None:
"""
Append to process_log AND send to the central logger.
Args:
process_log: List to append the message to
message: The message to log
level: Log level ('info', 'warning', 'error')
module: Module name for the logger (optional, defaults to 'default')
"""
process_log.append(message)
# Get the logger for the specified module
logger = self.get_logger(module)
# Log the message at the appropriate level
if level.lower() == "error":
logger.error(message)
elif level.lower() == "warning":
logger.warning(message)
else:
logger.info(message)
def log_info(self, message: str, module: str = "default") -> None:
"""Log an info message."""
logger = self.get_logger(module)
logger.info(message)
def log_warning(self, message: str, module: str = "default") -> None:
"""Log a warning message."""
logger = self.get_logger(module)
logger.warning(message)
def log_error(self, message: str, module: str = "default") -> None:
"""Log an error message."""
logger = self.get_logger(module)
logger.error(message)
# Alternative method names that match your original _log function pattern
def _log(self, process_log: List[str], message: str, level: str = "info", module: str = "default") -> None:
"""Alias for log_message to match your original function name."""
self.log_message(process_log, message, level, module)
# Create a default instance for easy importing
default_logger = CustomLoggerTracker()
# Expose the methods at module level for easy importing
log_message = default_logger.log_message
log_info = default_logger.log_info
log_warning = default_logger.log_warning
log_error = default_logger.log_error
_log = default_logger._log
# Example usage
if __name__ == "__main__":
# Method 1: Create your own instance
logger_tracker = CustomLoggerTracker()
process_log = []
logger_tracker.log_message(process_log, "This is a test info message", "info", "registration")
logger_tracker.log_message(process_log, "This is a warning message", "warning", "registration")
logger_tracker.log_message(process_log, "This is an error message", "error", "registration")
# Method 2: Use the default instance functions
process_log2 = []
log_message(process_log2, "Using default logger", "info", "detection")
_log(process_log2, "Using _log alias", "warning", "detection")
# Method 3: Direct logging without process_log
log_info("Direct info message", "main")
log_warning("Direct warning message", "main")
log_error("Direct error message", "main")
print("Process log 1 contents:")
for log_entry in process_log:
print(f" {log_entry}")
print("Process log 2 contents:")
for log_entry in process_log2:
print(f" {log_entry}")