import logging import os from typing import Optional, Dict, Any from fastapi.requests import Request from api_library.date_time_actions.date_functions import system_arrow class UserActivityLogger: def __init__(self): self.logger = logging.getLogger("user_activity") self.logger.setLevel(logging.INFO) # Add handlers if not already added if not self.logger.handlers: log_path = "/service_app/logs/user_activity.log" os.makedirs(os.path.dirname(log_path), exist_ok=True) handler = logging.FileHandler(log_path) formatter = logging.Formatter( "%(asctime)s - %(name)s - %(levelname)s - %(message)s" ) handler.setFormatter(formatter) self.logger.addHandler(handler) def _get_request_metadata(self, request: Request) -> Dict[str, Any]: """Extract common metadata from request""" return { "agent": request.headers.get("User-Agent"), "ip": getattr(request, "remote_addr", None) or request.headers.get("X-Forwarded-For"), "platform": request.headers.get("Origin"), "timestamp": str(system_arrow.now()), } def log_login_attempt( self, request: Request, user_id: int, domain: str, access_key: str, success: bool, error: Optional[str] = None, ): """Log login attempts""" metadata = self._get_request_metadata(request) log_data = { "event": "login_attempt", "user_id": user_id, "domain": domain, "access_key": access_key, "success": success, "error": error, **metadata, } if success: self.logger.info("Login successful", extra=log_data) else: self.logger.warning("Login failed", extra=log_data) def log_password_change( self, request: Request, user_id: int, change_type: str, success: bool, error: Optional[str] = None, ): """Log password changes""" metadata = self._get_request_metadata(request) log_data = { "event": "password_change", "user_id": user_id, "change_type": change_type, "success": success, "error": error, **metadata, } if success: self.logger.info("Password change successful", extra=log_data) else: self.logger.warning("Password change failed", extra=log_data) def log_session_activity( self, request: Request, user_id: int, activity_type: str, domain: Optional[str] = None, success: bool = True, error: Optional[str] = None, ): """Log session activities (logout, disconnect, etc)""" metadata = self._get_request_metadata(request) log_data = { "event": "session_activity", "activity_type": activity_type, "user_id": user_id, "domain": domain, "success": success, "error": error, **metadata, } if success: self.logger.info(f"{activity_type} successful", extra=log_data) else: self.logger.warning(f"{activity_type} failed", extra=log_data) # Global logger instance user_logger = UserActivityLogger()