pdf-accessibility/logger_config.py
Vadym Samoilenko 0e24602096 Add production readiness: authentication, logging, retry logic, and test suite
Phase 1: Critical bug fixes
- Fix missing os/sys imports in pdf_remediation.py (line 427 crash)
- Install Python dependencies (venv with 11 packages)
- Create runtime directories (uploads, results, .cache)
- Configure environment (.env from .env.example)

Phase 2: Production features
- Add authentication module (auth.php) with API key support
- Integrate auth into api.php with CORS headers update
- Add structured logging framework (logger_config.py) with rotation
- Add retry helper (retry_helper.py) with exponential backoff
- Apply retry decorators to AI API calls (Claude and Google Vision)
- Create comprehensive test suite (31 tests, 34% coverage)
  * Unit tests for checker and remediation
  * Integration tests for API and authentication
  * pytest configuration with coverage reporting

Documentation:
- Add requirements specifications (BRS, FRS, SAD) to docs_req/
- Add PDF-UA-1 technical background
- Add sample accessibility report

All tests passing (31/31). Ready for production deployment.

Co-Authored-By: Claude Sonnet 4.5 (1M context) <noreply@anthropic.com>
2026-02-25 13:26:02 +00:00

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")