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
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)
|