Spaces:
Sleeping
Sleeping
| # app/core/logging.py | |
| from __future__ import annotations | |
| import logging | |
| import os | |
| import uuid | |
| from typing import Optional | |
| _DEF_FORMAT = "%(asctime)s | %(levelname)-8s | %(name)s | %(message)s" | |
| _DEF_DATEFMT = "%Y-%m-%dT%H:%M:%S%z" | |
| def setup_logging(level: Optional[str] = None) -> None: | |
| """ | |
| Idempotent logging setup. | |
| - Honors LOG_LEVEL env (default INFO) unless an explicit level is passed. | |
| - Avoids duplicate handlers if called multiple times. | |
| - Tames noisy third-party loggers by default. | |
| """ | |
| root = logging.getLogger() | |
| if root.handlers: | |
| return # already configured | |
| log_level = (level or os.getenv("LOG_LEVEL", "INFO")).upper() | |
| try: | |
| parsed_level = getattr(logging, log_level) | |
| except AttributeError: | |
| parsed_level = logging.INFO | |
| handler = logging.StreamHandler() | |
| formatter = logging.Formatter(_DEF_FORMAT, datefmt=_DEF_DATEFMT) | |
| handler.setFormatter(formatter) | |
| root.setLevel(parsed_level) | |
| root.addHandler(handler) | |
| # Quiet noisy libs by default; adjust if you need more/less detail. | |
| logging.getLogger("urllib3").setLevel(logging.WARNING) | |
| logging.getLogger("httpx").setLevel(logging.WARNING) | |
| logging.getLogger("requests").setLevel(logging.WARNING) | |
| def add_trace_id(request) -> None: | |
| """ | |
| Injects a unique `trace_id` into request.state (works with FastAPI-style objects). | |
| Duck-typed to avoid importing FastAPI here. | |
| """ | |
| try: | |
| state = getattr(request, "state", None) | |
| if state is None: | |
| # Some frameworks may not have .state; just skip silently. | |
| return | |
| if not hasattr(state, "trace_id"): | |
| state.trace_id = str(uuid.uuid4()) | |
| except Exception: | |
| # Never let logging helpers break the app. | |
| return | |