""" Structured logging configuration for the Virtual Board Member AI System. """ import logging import sys from typing import Any, Dict import structlog from structlog.stdlib import LoggerFactory from structlog.processors import ( TimeStamper, JSONRenderer, format_exc_info, add_log_level, StackInfoRenderer, ) from structlog.types import Processor from app.core.config import settings def setup_logging() -> None: """Setup structured logging configuration.""" # Configure standard library logging logging.basicConfig( format="%(message)s", stream=sys.stdout, level=getattr(logging, settings.LOG_LEVEL.upper()), ) # Configure structlog structlog.configure( processors=[ # Add timestamp TimeStamper(fmt="iso"), # Add log level add_log_level, # Add stack info StackInfoRenderer(), # Add exception info format_exc_info, # Add caller info structlog.processors.CallsiteParameterAdder( parameters={ structlog.processors.CallsiteParameter.FILENAME, structlog.processors.CallsiteParameter.FUNC_NAME, structlog.processors.CallsiteParameter.LINENO, } ), # Add process info structlog.stdlib.add_log_level_number, # Add service info structlog.stdlib.ProcessorFormatter.wrap_for_formatter, ], context_class=dict, logger_factory=LoggerFactory(), wrapper_class=structlog.stdlib.BoundLogger, cache_logger_on_first_use=True, ) # Configure formatter formatter = structlog.stdlib.ProcessorFormatter( processor=structlog.dev.ConsoleRenderer() if settings.DEBUG else JSONRenderer(), foreign_pre_chain=[ structlog.stdlib.add_log_level, structlog.stdlib.add_logger_name, structlog.stdlib.PositionalArgumentsFormatter(), structlog.processors.TimeStamper(fmt="iso"), structlog.processors.StackInfoRenderer(), structlog.processors.format_exc_info, ], ) # Configure root logger root_logger = logging.getLogger() root_logger.handlers.clear() handler = logging.StreamHandler(sys.stdout) handler.setFormatter(formatter) root_logger.addHandler(handler) root_logger.setLevel(getattr(logging, settings.LOG_LEVEL.upper())) def get_logger(name: str = None) -> structlog.BoundLogger: """Get a structured logger instance.""" return structlog.get_logger(name) class AuditLogger: """Audit logging for compliance and security events.""" def __init__(self): self.logger = get_logger("audit") def log_user_login(self, user_id: str, ip_address: str, success: bool, **kwargs) -> None: """Log user login attempt.""" self.logger.info( "User login attempt", event_type="user_login", user_id=user_id, ip_address=ip_address, success=success, **kwargs ) def log_document_access(self, user_id: str, document_id: str, action: str, **kwargs) -> None: """Log document access.""" self.logger.info( "Document access", event_type="document_access", user_id=user_id, document_id=document_id, action=action, **kwargs ) def log_query_execution(self, user_id: str, query: str, response_time: float, **kwargs) -> None: """Log query execution.""" self.logger.info( "Query execution", event_type="query_execution", user_id=user_id, query=query, response_time=response_time, **kwargs ) def log_commitment_extraction(self, document_id: str, commitments_count: int, **kwargs) -> None: """Log commitment extraction.""" self.logger.info( "Commitment extraction", event_type="commitment_extraction", document_id=document_id, commitments_count=commitments_count, **kwargs ) def log_security_event(self, event_type: str, severity: str, details: Dict[str, Any]) -> None: """Log security events.""" self.logger.warning( "Security event", event_type="security_event", security_event_type=event_type, severity=severity, details=details ) # Create audit logger instance audit_logger = AuditLogger()