Spaces:
Running
Running
| """ | |
| Logging Configuration Utility | |
| Provides centralized logging setup for the Vibeon Translator API | |
| """ | |
| import logging | |
| import sys | |
| from pathlib import Path | |
| import uuid | |
| from typing import Callable, Optional | |
| from starlette.middleware.base import BaseHTTPMiddleware # type: ignore | |
| from starlette.requests import Request # type: ignore | |
| def setup_logging(log_level: str = "INFO", log_file: Optional[str] = None): | |
| """ | |
| Setup logging configuration for the application | |
| Args: | |
| log_level: Logging level (DEBUG, INFO, WARNING, ERROR, CRITICAL) | |
| log_file: Optional log file path | |
| """ | |
| # Create formatter | |
| formatter = logging.Formatter( | |
| '%(asctime)s - %(name)s - %(levelname)s - %(message)s', | |
| datefmt='%Y-%m-%d %H:%M:%S' | |
| ) | |
| # Get root logger | |
| root_logger = logging.getLogger() | |
| root_logger.setLevel(getattr(logging, log_level.upper())) | |
| # Clear existing handlers | |
| root_logger.handlers.clear() | |
| # Console handler with UTF-8 encoding for Unicode support | |
| console_handler = logging.StreamHandler(sys.stdout) | |
| console_handler.setFormatter(formatter) | |
| # Force UTF-8 encoding to handle Unicode characters (Kinyarwanda, Hindi, etc.) | |
| if hasattr(sys.stdout, 'reconfigure'): | |
| try: | |
| sys.stdout.reconfigure(encoding='utf-8', errors='replace') | |
| except Exception: | |
| pass # Fallback silently if reconfigure not available | |
| root_logger.addHandler(console_handler) | |
| # File handler if log file is specified | |
| if log_file: | |
| # Create log directory if it doesn't exist | |
| log_path = Path(log_file) | |
| log_path.parent.mkdir(parents=True, exist_ok=True) | |
| # Use UTF-8 encoding for file handler as well | |
| file_handler = logging.FileHandler(log_file, encoding='utf-8', errors='replace') | |
| file_handler.setFormatter(formatter) | |
| root_logger.addHandler(file_handler) | |
| # Set specific log levels for noisy libraries | |
| logging.getLogger("uvicorn.access").setLevel(logging.WARNING) | |
| logging.getLogger("httpx").setLevel(logging.WARNING) | |
| logging.getLogger("transformers").setLevel(logging.WARNING) | |
| logging.getLogger("torch").setLevel(logging.WARNING) | |
| return root_logger | |
| class RequestIdLoggingMiddleware(BaseHTTPMiddleware): | |
| """Attach request ID header and log structured request/response""" | |
| async def dispatch(self, request: Request, call_next: Callable): | |
| request_id = request.headers.get("X-Request-ID") or str(uuid.uuid4()) | |
| request.state.request_id = request_id | |
| logger = logging.getLogger("request") | |
| try: | |
| response = await call_next(request) | |
| response.headers["X-Request-ID"] = request_id | |
| logger.info( | |
| "method=%s path=%s status=%s request_id=%s", | |
| request.method, | |
| str(request.url.path), | |
| response.status_code, | |
| request_id, | |
| ) | |
| return response | |
| except Exception: | |
| logger.exception("error request_id=%s", request_id) | |
| raise | |