You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

45 lines
1.3 KiB
Python

# backend/app/observability/logging.py — 구조화 JSON 로깅 (request_id·user_id 컨텍스트)
import json
import logging
from contextvars import ContextVar
request_id_ctx: ContextVar[str] = ContextVar("request_id", default="-")
user_id_ctx: ContextVar[str] = ContextVar("user_id", default="-")
class JsonFormatter(logging.Formatter):
def format(self, record: logging.LogRecord) -> str:
payload = {
"level": record.levelname,
"logger": record.name,
"msg": record.getMessage(),
"request_id": request_id_ctx.get(),
"user_id": user_id_ctx.get(),
}
for k in ("method", "path", "status", "dur_ms", "event"):
v = getattr(record, k, None)
if v is not None:
payload[k] = v
if record.exc_info:
payload["exc"] = self.formatException(record.exc_info)
return json.dumps(payload, ensure_ascii=False)
_configured = False
def configure_logging(level: str = "INFO") -> None:
global _configured
if _configured:
return
handler = logging.StreamHandler()
handler.setFormatter(JsonFormatter())
root = logging.getLogger()
root.handlers = [handler]
root.setLevel(level.upper())
_configured = True
def get_logger(name: str = "ari") -> logging.Logger:
return logging.getLogger(name)