Spaces:
Running
Running
File size: 1,873 Bytes
afd56bc | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 | import logging
import sys
import contextvars
from uuid import uuid4
# Zmienna kontekstowa definiująca unikalne ID zapytania HTTP (lub tła)
request_id_ctx_var: contextvars.ContextVar[str] = contextvars.ContextVar(
"request_id", default="SYSTEM"
)
class RequestIDFilter(logging.Filter):
"""
Filtr wstrzykujący contextvar (RequestID) do rekordu logów.
"""
def filter(self, record):
record.request_id = request_id_ctx_var.get()
return True
def setup_logging():
"""
Konfiguruje główny logger aplikacji tak, aby:
- używał StreamHandler (stdout) pod kontener (np. Render/Docker)
- dodawał ustrukturyzowany prefiks: [Data] [Poziom] [RequestID: ...] Wiadomość.
"""
logger = logging.getLogger("DotacjeAI")
logger.setLevel(logging.INFO)
# Zapobiega duplikacji, gdy powtarzamy użycie skryptu gunicorn/uvicorn
if logger.handlers:
logger.handlers.clear()
handler = logging.StreamHandler(sys.stdout)
handler.setLevel(logging.INFO)
# Format zadeklarowany we wdrożeniu (DEPLOYMENT.md)
formatter = logging.Formatter(
fmt="[%(asctime)s] [%(levelname)s] [RequestID: %(request_id)s] %(message)s",
datefmt="%Y-%m-%d %H:%M:%S",
)
handler.setFormatter(formatter)
# Dodajemy filtr wyciągający zmienne kontekstowe
filter_req_id = RequestIDFilter()
handler.addFilter(filter_req_id)
logger.addFilter(filter_req_id)
logger.addHandler(handler)
# Przechwytuj uvicorn i langserve logi w naszym stylu
logging.getLogger("uvicorn.access").addFilter(filter_req_id)
return logger
def set_request_id(req_id: str | None = None) -> str:
"""Ustawia request ID w zmiennej kontekstowej dla bieżącego cyklu asynchronicznego."""
new_id = req_id or f"req_{uuid4().hex[:8]}"
request_id_ctx_var.set(new_id)
return new_id
|