#!/usr/bin/env python3 """ Logging Configuration Module Provides structured logging with file and console handlers. Supports log rotation and multiple log levels. """ import logging import sys from pathlib import Path from datetime import datetime from logging.handlers import RotatingFileHandler def setup_logger( name: str, log_file: str = None, level: int = logging.INFO, max_bytes: int = 10 * 1024 * 1024, # 10MB backup_count: int = 5 ) -> logging.Logger: """ Setup logger with file and console handlers Args: name: Logger name (usually __name__) log_file: Optional log file name (will be placed in logs/ directory) level: Logging level (DEBUG, INFO, WARNING, ERROR, CRITICAL) max_bytes: Maximum size of log file before rotation (default: 10MB) backup_count: Number of backup files to keep (default: 5) Returns: Configured logger instance Example: >>> from logger_config import setup_logger >>> logger = setup_logger(__name__, "my_app.log") >>> logger.info("Application started") """ logger = logging.getLogger(name) logger.setLevel(level) # Prevent duplicate handlers if logger.handlers: return logger # Format with timestamp, logger name, level, and message formatter = logging.Formatter( '%(asctime)s - %(name)s - %(levelname)s - %(message)s', datefmt='%Y-%m-%d %H:%M:%S' ) # Console handler - always enabled console_handler = logging.StreamHandler(sys.stdout) console_handler.setLevel(level) console_handler.setFormatter(formatter) logger.addHandler(console_handler) # File handler - optional if log_file: # Create logs directory if it doesn't exist log_dir = Path("logs") log_dir.mkdir(exist_ok=True) log_path = log_dir / log_file # Use RotatingFileHandler for automatic log rotation file_handler = RotatingFileHandler( log_path, maxBytes=max_bytes, backupCount=backup_count, encoding='utf-8' ) file_handler.setLevel(level) file_handler.setFormatter(formatter) logger.addHandler(file_handler) return logger # Create default logger for this module logger = setup_logger(__name__, "pdf_checker.log") def get_logger(name: str, log_file: str = None) -> logging.Logger: """ Get or create a logger with the specified name Args: name: Logger name log_file: Optional log file name Returns: Logger instance """ return setup_logger(name, log_file) # Convenience functions for direct logging def debug(msg: str, *args, **kwargs): """Log a debug message""" logger.debug(msg, *args, **kwargs) def info(msg: str, *args, **kwargs): """Log an info message""" logger.info(msg, *args, **kwargs) def warning(msg: str, *args, **kwargs): """Log a warning message""" logger.warning(msg, *args, **kwargs) def error(msg: str, *args, **kwargs): """Log an error message""" logger.error(msg, *args, **kwargs) def critical(msg: str, *args, **kwargs): """Log a critical message""" logger.critical(msg, *args, **kwargs) def exception(msg: str, *args, **kwargs): """Log an exception with traceback""" logger.exception(msg, *args, **kwargs) if __name__ == "__main__": # Test the logger test_logger = setup_logger("test", "test.log", level=logging.DEBUG) test_logger.debug("This is a debug message") test_logger.info("This is an info message") test_logger.warning("This is a warning message") test_logger.error("This is an error message") test_logger.critical("This is a critical message") print("\n✅ Logger test complete. Check logs/test.log")