|
|
from __future__ import annotations |
|
|
|
|
|
import logging |
|
|
from datetime import datetime |
|
|
from typing import Callable, Optional |
|
|
from zoneinfo import ZoneInfo |
|
|
|
|
|
from motor.motor_asyncio import AsyncIOMotorCollection |
|
|
|
|
|
logger = logging.getLogger(__name__) |
|
|
|
|
|
|
|
|
class ApiLogger: |
|
|
"""Persists API invocation metadata for observability/auditing.""" |
|
|
|
|
|
def __init__(self, collection_getter: Callable[[], AsyncIOMotorCollection]) -> None: |
|
|
self._collection_getter = collection_getter |
|
|
|
|
|
def _collection(self) -> AsyncIOMotorCollection: |
|
|
return self._collection_getter() |
|
|
|
|
|
@staticmethod |
|
|
def _current_ist_timestamp() -> str: |
|
|
now = datetime.now(ZoneInfo("Asia/Kolkata")) |
|
|
return now.strftime("%d-%m-%Y %H:%M:%S:%Z") |
|
|
|
|
|
async def log_categorization( |
|
|
self, |
|
|
*, |
|
|
name: str, |
|
|
status: str, |
|
|
response_time: float, |
|
|
user_id: Optional[str], |
|
|
error_message: Optional[str] = None, |
|
|
) -> None: |
|
|
doc = { |
|
|
"name": name, |
|
|
"status": status, |
|
|
"date": self._current_ist_timestamp(), |
|
|
"response_time": round(response_time, 3), |
|
|
} |
|
|
if user_id: |
|
|
doc["user_id"] = user_id |
|
|
if error_message: |
|
|
doc["error_message"] = error_message |
|
|
|
|
|
try: |
|
|
await self._collection().insert_one(doc) |
|
|
except Exception: |
|
|
logger.exception("Failed to write categorize API log") |
|
|
|