from fastapi import Request from fastapi.responses import JSONResponse from starlette.middleware.base import BaseHTTPMiddleware from sqlalchemy.orm import Session from app.db.models import OperationLog,User from app.core.apiexception import APIException from app.core.dbmanager import get_log_db from app.db.crud import create_log import json class LoggingMiddleware(BaseHTTPMiddleware): async def dispatch(self, request: Request, call_next): if request.method in ("POST", "PUT", "PATCH","DELETE"): try: request.state.body = await request.json() except json.JSONDecodeError: request.state.body = await request.body() else: request.state.body = None try: response = await call_next(request) state = request.state except Exception as e: await self.log_error(request, e) response = JSONResponse( content={"detail": "Internal Server Error"}, status_code=500 ) if hasattr(request.state, "user") and hasattr(request.state, "tenant"): await self.log_request(request, response,state) return response async def log_request(self, request: Request, response,state): try: headers = dict(request.headers) route = request.scope.get("route") if route: path_template = route.path else: path_template = request.url.path db_operation = OperationLog(tenantid =request.state.tenant, clientip = request.client.host if request.client else None, useragent =headers.get("user-agent", ""), userid = request.state.user, operation = request.method, function = path_template, parameters = str({"path": request.path_params,"query": dict(request.query_params),"body": request.state.body}), response = f"status_code:{response.status_code }" ) db = request.state.db if db: await self.write_log_to_db(db_operation,db) except Exception as e: print(f"Logging failed: {str(e)}") async def log_error(self, request: Request, e: Exception): exc = APIException('operation:dispatch',request.url._url,f"Error occurred while writting operation log:",e) db = get_log_db() try: create_log(db,exc.error) finally: db.close() async def write_log_to_db(self, db_operation,db): db.add(db_operation) db.commit()