PDF-accessibility-saas/logger_config.py

141 lines
3.7 KiB
Python

#!/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")