import os
import sys
from datetime import datetime
from pathlib import Path
from typing import Optional, Union
from loguru import logger as loguru_logger
# Remove default configuration
loguru_logger.remove()
# Set up default configuration for console logging
loguru_logger.add(
sys.stderr,
level="DEBUG",
format="<green>{time:YYYY-MM-DD HH:mm:ss}</green> | <level>{level: <8}</level> | <cyan>{name}</cyan>:<cyan>{function}</cyan>:<cyan>{line}</cyan> - <level>{message}</level>",
)
# Create logs directory if it doesn't exist
logs_dir = Path(os.getcwd()) / "pleiades_logs"
logs_dir.mkdir(exist_ok=True)
# Set up default log file with hourly timestamp
default_log_filename = f"pleiades_{datetime.now().strftime('%Y%m%d_%H')}.log"
default_log_path = logs_dir / default_log_filename
# Add file logger with default settings
loguru_logger.add(
default_log_path,
level="DEBUG",
format="{time:YYYY-MM-DD HH:mm:ss} | {level: <8} | {name}:{function}:{line} - {message}",
rotation="10 MB",
retention="30 days",
)
def _log_and_raise_error(logger, message: str, exception_class: Exception):
"""
Log an error message and raise an exception.
Args:
logger: The logger instance to use for logging the error.
message (str): The error message to log and raise.
exception_class (Exception): The class of the exception to raise.
Raises:
exception_class: The exception with the provided message.
"""
logger.error(message)
raise exception_class(message)
[docs]
class Logger:
"""
Backward-compatible Logger class that wraps loguru.
This class maintains the same interface as the original Logger class
but uses loguru under the hood for better logging capabilities.
"""
[docs]
def __init__(self, name: str, level: str = "DEBUG", log_file: Optional[str] = None):
"""
Initialize a Logger instance.
Args:
name (str): The name of the logger.
level (str): The logging level (default is "DEBUG").
log_file (str, optional): The file to log messages to (default is None).
"""
self.name = name
self.level = level
# If custom log file is specified, configure a new sink for it
if log_file and log_file != str(default_log_path):
log_path = Path(log_file)
# If not an absolute path, place in logs directory
if not log_path.is_absolute():
log_path = logs_dir / log_path
self.log_file = log_path
# Add a file handler if specified
loguru_logger.add(
self.log_file,
level=level,
format="{time:YYYY-MM-DD HH:mm:ss} | {level: <8} | {name}:{function}:{line} - {message}",
rotation="10 MB",
retention="30 days",
)
# Log a break line to indicate initialization
loguru_logger.bind(name=name).info("logging initialized...")
[docs]
def debug(self, message: str):
"""
Log a debug message.
Args:
message (str): The debug message to log.
"""
loguru_logger.bind(name=self.name).debug(message)
[docs]
def info(self, message: str):
"""
Log an info message.
Args:
message (str): The info message to log.
"""
loguru_logger.bind(name=self.name).info(message)
[docs]
def warning(self, message: str):
"""
Log a warning message.
Args:
message (str): The warning message to log.
"""
loguru_logger.bind(name=self.name).warning(message)
[docs]
def error(self, message: str):
"""
Log an error message.
Args:
message (str): The error message to log.
"""
loguru_logger.bind(name=self.name).error(message)
[docs]
def critical(self, message: str):
"""
Log a critical message.
Args:
message (str): The critical message to log.
"""
loguru_logger.bind(name=self.name).critical(message)
# Make the loguru logger available directly
get_logger = loguru_logger.bind