"""Structured logging configuration with OpenTelemetry integration.""" import logging import sys import time from typing import Any import structlog from opentelemetry import trace def configure_logging(service_name: str, log_level: str = "INFO") -> None: """Configure structured logging with structlog""" def add_service_name( # pylint: disable=unused-argument logger: Any, method_name: str, event_dict: dict[str, Any], # noqa: ARG001 ) -> dict[str, Any]: event_dict["service"] = service_name return event_dict def add_trace_id( # pylint: disable=unused-argument logger: Any, method_name: str, event_dict: dict[str, Any], # noqa: ARG001 ) -> dict[str, Any]: """Add trace ID to log entries""" span = trace.get_current_span() if span and span.get_span_context().is_valid: event_dict["trace_id"] = format(span.get_span_context().trace_id, "032x") event_dict["span_id"] = format(span.get_span_context().span_id, "016x") return event_dict def add_timestamp( # pylint: disable=unused-argument logger: Any, method_name: str, event_dict: dict[str, Any], # noqa: ARG001 ) -> dict[str, Any]: event_dict["timestamp"] = time.time() return event_dict # Configure structlog structlog.configure( processors=[ structlog.stdlib.filter_by_level, structlog.stdlib.add_logger_name, structlog.stdlib.add_log_level, add_service_name, # type: ignore add_trace_id, # type: ignore add_timestamp, # type: ignore structlog.stdlib.PositionalArgumentsFormatter(), structlog.processors.StackInfoRenderer(), structlog.processors.format_exc_info, structlog.processors.UnicodeDecoder(), structlog.processors.JSONRenderer(), ], context_class=dict, logger_factory=structlog.stdlib.LoggerFactory(), wrapper_class=structlog.stdlib.BoundLogger, cache_logger_on_first_use=True, ) # Configure standard library logging logging.basicConfig( format="%(message)s", stream=sys.stdout, level=getattr(logging, log_level.upper()), ) # Reduce noise from some libraries logging.getLogger("httpx").setLevel(logging.WARNING) logging.getLogger("httpcore").setLevel(logging.WARNING) logging.getLogger("uvicorn.access").setLevel(logging.WARNING)