"""Structured logging configuration Provides consistent logging across the application with JSON formatting for production environments. """ import logging import sys from typing import Any import json from datetime import datetime class JSONFormatter(logging.Formatter): """Custom JSON formatter for structured logging""" def format(self, record: logging.LogRecord) -> str: """Format log record as JSON""" log_data: dict[str, Any] = { "timestamp": datetime.utcnow().isoformat(), "level": record.levelname, "logger": record.name, "message": record.getMessage(), "module": record.module, "function": record.funcName, "line": record.lineno, } # Add exception info if present if record.exc_info: log_data["exception"] = self.formatException(record.exc_info) # Add extra fields from record if hasattr(record, "extra"): log_data.update(record.extra) return json.dumps(log_data) def setup_logging(level: str = "INFO", use_json: bool = False) -> None: """Configure application logging Args: level: Log level (DEBUG, INFO, WARNING, ERROR, CRITICAL) use_json: Whether to use JSON formatting (for production) """ log_level = getattr(logging, level.upper(), logging.INFO) # Configure root logger root_logger = logging.getLogger() root_logger.setLevel(log_level) # Remove existing handlers root_logger.handlers.clear() # Create console handler console_handler = logging.StreamHandler(sys.stdout) console_handler.setLevel(log_level) # Set formatter if use_json: formatter = JSONFormatter() else: formatter = logging.Formatter( fmt="%(asctime)s - %(name)s - %(levelname)s - %(message)s", datefmt="%Y-%m-%d %H:%M:%S" ) console_handler.setFormatter(formatter) root_logger.addHandler(console_handler) # Reduce noise from third-party libraries logging.getLogger("httpx").setLevel(logging.WARNING) logging.getLogger("httpcore").setLevel(logging.WARNING) logging.getLogger("openai").setLevel(logging.WARNING) logging.getLogger("qdrant_client").setLevel(logging.WARNING) def get_logger(name: str) -> logging.Logger: """Get a logger instance Args: name: Logger name (usually __name__ of the module) Returns: Logger instance """ return logging.getLogger(name)