"""Structured logging configuration using structlog. Call setup_logging() once at application startup to configure structlog with human-readable (dev) or JSON (prod) output. """ import logging import sys import structlog def setup_logging(log_level: str = "info") -> None: """Configure structlog for the application. In development, output is colorized and human-readable. In production, output is JSON for structured log aggregation. Args: log_level: Minimum log level as a string (e.g., 'info', 'debug'). """ numeric_level = getattr(logging, log_level.upper(), logging.INFO) # Configure standard library logging (captured by structlog) logging.basicConfig( format="%(message)s", stream=sys.stdout, level=numeric_level, ) structlog.configure( processors=[ structlog.contextvars.merge_contextvars, structlog.stdlib.filter_by_level, structlog.stdlib.add_logger_name, structlog.stdlib.add_log_level, structlog.stdlib.PositionalArgumentsFormatter(), structlog.processors.TimeStamper(fmt="iso"), structlog.processors.StackInfoRenderer(), structlog.processors.format_exc_info, structlog.processors.UnicodeDecoder(), structlog.dev.ConsoleRenderer(), ], wrapper_class=structlog.stdlib.BoundLogger, context_class=dict, logger_factory=structlog.stdlib.LoggerFactory(), cache_logger_on_first_use=True, )