"""Structured logging middleware with structlog.""" import structlog from functools import wraps from typing import Callable, Any import time def configure_logging(): """Configure structured logging.""" structlog.configure( processors=[ 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.processors.JSONRenderer() ], context_class=dict, logger_factory=structlog.stdlib.LoggerFactory(), cache_logger_on_first_use=True, ) def get_logger(name: str) -> structlog.stdlib.BoundLogger: """Get a configured logger.""" return structlog.get_logger(name) def log_execution(logger: structlog.stdlib.BoundLogger): """Decorator to log function execution.""" def decorator(func: Callable) -> Callable: @wraps(func) async def async_wrapper(*args, **kwargs) -> Any: start_time = time.time() logger.info(f"Starting {func.__name__}") try: result = await func(*args, **kwargs) duration = time.time() - start_time logger.info(f"Completed {func.__name__}", duration=duration) return result except Exception as e: duration = time.time() - start_time logger.error(f"Error in {func.__name__}", error=str(e), duration=duration) raise @wraps(func) def sync_wrapper(*args, **kwargs) -> Any: start_time = time.time() logger.info(f"Starting {func.__name__}") try: result = func(*args, **kwargs) duration = time.time() - start_time logger.info(f"Completed {func.__name__}", duration=duration) return result except Exception as e: duration = time.time() - start_time logger.error(f"Error in {func.__name__}", error=str(e), duration=duration) raise return async_wrapper if hasattr(func, '__call__') and hasattr(func, '__code__') and func.__code__.co_flags & 0x80 else sync_wrapper return decorator