diff --git a/src/core/ytsage_logging.py b/src/core/ytsage_logging.py
new file mode 100644
index 0000000..6e050ae
--- /dev/null
+++ b/src/core/ytsage_logging.py
@@ -0,0 +1,224 @@
+"""
+YTSage logging configuration using loguru.
+
+This module provides centralized logging configuration for the entire YTSage application.
+It replaces the inefficient print statements with structured logging using loguru.
+"""
+
+import os
+import sys
+from pathlib import Path
+
+# Try to import loguru, but handle case where it might not be available
+try:
+ from loguru import logger
+ LOGURU_AVAILABLE = True
+except ImportError:
+ LOGURU_AVAILABLE = False
+ # Create a dummy logger class that does nothing
+ class DummyLogger:
+ def info(self, *args, **kwargs): pass
+ def debug(self, *args, **kwargs): pass
+ def warning(self, *args, **kwargs): pass
+ def error(self, *args, **kwargs): pass
+ def critical(self, *args, **kwargs): pass
+ def remove(self, *args, **kwargs): pass
+ def add(self, *args, **kwargs): pass
+ def bind(self, *args, **kwargs): return self
+ @property
+ def _core(self):
+ class Core:
+ handlers = []
+ return Core()
+
+ logger = DummyLogger()
+
+
+def setup_logging():
+ """
+ Configure loguru logging for YTSage application.
+
+ Sets up multiple log levels and outputs:
+ - Console output for INFO and above
+ - File output for DEBUG and above
+ - Separate error log file for ERROR and above
+ """
+
+ if not LOGURU_AVAILABLE:
+ return logger
+
+ # Remove default logger to avoid duplicate output
+ try:
+ logger.remove()
+ except Exception:
+ pass
+
+ # Get the application data directory with fallbacks
+ try:
+ if sys.platform == 'win32':
+ localappdata = os.environ.get('LOCALAPPDATA')
+ if localappdata:
+ log_dir = Path(localappdata) / 'YTSage' / 'logs'
+ else:
+ # Fallback for PyInstaller or when LOCALAPPDATA is not set
+ log_dir = Path.home() / 'AppData' / 'Local' / 'YTSage' / 'logs'
+ elif sys.platform == 'darwin':
+ log_dir = Path.home() / 'Library' / 'Application Support' / 'YTSage' / 'logs'
+ else:
+ log_dir = Path.home() / '.local' / 'share' / 'YTSage' / 'logs'
+ except Exception:
+ # Ultimate fallback - use current directory
+ log_dir = Path.cwd() / 'logs'
+
+ # Create log directory if it doesn't exist
+ try:
+ log_dir.mkdir(parents=True, exist_ok=True)
+ except Exception:
+ # If we can't create the log directory, fall back to current directory
+ log_dir = Path.cwd()
+ try:
+ log_dir.mkdir(exist_ok=True)
+ except Exception:
+ pass # If we still can't create it, we'll just log to console
+
+ # Console handler - INFO and above, with colors
+ # Check if stdout is available (it might be None in PyInstaller windowed apps)
+ stdout_available = sys.stdout is not None
+
+ if stdout_available:
+ try:
+ logger.add(
+ sys.stdout,
+ level="INFO",
+ format="{time:YYYY-MM-DD HH:mm:ss} | {level: <8} | {name}:{function}:{line} - {message}",
+ colorize=True,
+ catch=True
+ )
+ except Exception:
+ # Fallback to basic console logging without colors
+ try:
+ logger.add(
+ sys.stdout,
+ level="INFO",
+ format="{time:YYYY-MM-DD HH:mm:ss} | {level: <8} | {message}",
+ catch=True
+ )
+ except Exception:
+ stdout_available = False
+
+ # If stdout is not available, try stderr or skip console logging entirely
+ if not stdout_available:
+ try:
+ if sys.stderr is not None:
+ logger.add(
+ sys.stderr,
+ level="WARNING", # Only warnings and errors to stderr
+ format="{time:YYYY-MM-DD HH:mm:ss} | {level: <8} | {message}",
+ catch=True
+ )
+ except Exception:
+ # If even stderr fails, we'll rely only on file logging
+ pass
+
+ # Only add file handlers if we successfully created a log directory
+ if log_dir and log_dir.exists():
+ try:
+ # Main log file - DEBUG and above, with rotation
+ logger.add(
+ log_dir / "ytsage.log",
+ level="DEBUG",
+ format="{time:YYYY-MM-DD HH:mm:ss} | {level: <8} | {name}:{function}:{line} - {message}",
+ rotation="10 MB", # Rotate when file reaches 10MB
+ retention="7 days", # Keep logs for 7 days
+ compression="zip", # Compress old logs
+ catch=True
+ )
+
+ # Error log file - ERROR and above only
+ logger.add(
+ log_dir / "ytsage_errors.log",
+ level="ERROR",
+ format="{time:YYYY-MM-DD HH:mm:ss} | {level: <8} | {name}:{function}:{line} - {message}",
+ rotation="5 MB",
+ retention="30 days", # Keep error logs longer
+ compression="zip",
+ catch=True
+ )
+ except Exception as e:
+ # If file logging fails, just log to console
+ logger.warning(f"Could not set up file logging: {e}")
+
+ # Log startup message if we have any handlers
+ if logger._core.handlers:
+ logger.info("YTSage logging system initialized")
+ if log_dir and log_dir.exists():
+ logger.debug(f"Log directory: {log_dir}")
+ else:
+ logger.warning("File logging disabled - could not create log directory")
+
+ # If no handlers were successfully added, add a null handler to prevent errors
+ if not logger._core.handlers:
+ # Add a minimal handler that just discards messages
+ # This prevents loguru from complaining about no handlers
+ import tempfile
+ try:
+ # Try to add a temporary file handler as last resort
+ temp_log = Path(tempfile.gettempdir()) / "ytsage_temp.log"
+ logger.add(temp_log, level="ERROR", catch=True)
+ except Exception:
+ # If even that fails, we're in a very restricted environment
+ # loguru should handle this gracefully with its internal fallbacks
+ pass
+
+ return logger
+
+
+def get_logger(name: str = None):
+ """
+ Get a logger instance for a specific module.
+
+ Args:
+ name: Name of the module/component requesting the logger
+
+ Returns:
+ Configured logger instance
+ """
+ if name:
+ return logger.bind(name=name)
+ return logger
+
+
+# Initialize logging when module is imported - with maximum safety
+_setup_complete = False
+
+def safe_setup():
+ """Safely initialize logging with multiple fallback strategies."""
+ global _setup_complete
+ if _setup_complete:
+ return logger
+
+ try:
+ setup_logging()
+ _setup_complete = True
+ except Exception:
+ # If all else fails, create an even simpler logger that just prints
+ if LOGURU_AVAILABLE:
+ try:
+ logger.remove()
+ except Exception:
+ pass
+
+ # At this point, just ensure we have something that won't crash
+ _setup_complete = True
+
+ return logger
+
+# Try to set up logging, but don't let it crash the module import
+try:
+ safe_setup()
+except Exception:
+ # Ultimate fallback - the module will still import successfully
+ pass
+
+# Export the main logger for convenience
+__all__ = ['logger', 'get_logger', 'setup_logging']