"""Structured logging setup using loguru - Container optimized.""" import sys import os from pathlib import Path from loguru import logger from app.core.config import settings def setup_logging() -> None: """Configure structured logging with loguru.""" # Remove default handler logger.remove() # Always add console handler with custom format logger.add( sys.stdout, level=settings.log_level, format="{time:YYYY-MM-DD HH:mm:ss} | {level: <8} | {name}:{function}:{line} - {message}", colorize=True ) # Only add file logging in development or when explicitly enabled if _should_enable_file_logging(): _setup_file_logging() else: logger.info("File logging disabled - using stdout only (recommended for containers)") def _should_enable_file_logging() -> bool: """Determine if file logging should be enabled.""" # Check explicit environment variable disable_file_logging = os.getenv("DISABLE_FILE_LOGGING", "false").lower() if disable_file_logging == "true": return False # Check if we're likely in a container environment container_indicators = [ os.getenv("CONTAINER_ENV") == "true", os.path.exists("/.dockerenv"), os.getenv("KUBERNETES_SERVICE_HOST") is not None, os.getenv("RAILWAY_ENVIRONMENT") is not None, os.getenv("RENDER") is not None, os.getenv("HEROKU") is not None, ] if any(container_indicators): return False # Try to write to the logs directory try: log_dir = _get_log_directory() test_file = log_dir / ".write_test" test_file.write_text("test") test_file.unlink() return True except (OSError, PermissionError): return False def _setup_file_logging() -> None: """Set up file-based logging handlers.""" log_dir = _get_log_directory() # Add file handler for errors logger.add( log_dir / "error.log", level="ERROR", format="{time:YYYY-MM-DD HH:mm:ss} | {level: <8} | {name}:{function}:{line} - {message}", rotation="10 MB", retention="30 days", compression="zip" ) # Add file handler for all logs logger.add( log_dir / "app.log", level="INFO", format="{time:YYYY-MM-DD HH:mm:ss} | {level: <8} | {name}:{function}:{line} - {message}", rotation="50 MB", retention="7 days", compression="zip" ) logger.info(f"File logging enabled. Logs directory: {log_dir}") def _get_log_directory() -> Path: """Get the appropriate log directory based on environment.""" # Check for custom log directory from environment custom_log_dir = os.getenv("LOG_DIR") if custom_log_dir: log_dir = Path(custom_log_dir) else: # Default to logs/ directory log_dir = Path("logs") # Create directory if it doesn't exist log_dir.mkdir(parents=True, exist_ok=True) return log_dir def get_logger(name: str): """Get a logger instance for a specific module.""" return logger.bind(name=name)