fastapi_profiler.py 1.0 KB

12345678910111213141516171819202122232425262728293031323334353637
  1. import re
  2. from pathlib import Path
  3. import yappi
  4. from starlette.types import ASGIApp
  5. from starlette.types import Receive
  6. from starlette.types import Scope
  7. from starlette.types import Send
  8. from clean_python import now
  9. class ProfilerMiddleware:
  10. def __init__(
  11. self,
  12. app: ASGIApp,
  13. *,
  14. profile_dir: Path,
  15. path: str = ".*",
  16. ):
  17. self.app = app
  18. profile_dir.mkdir(exist_ok=True)
  19. self.profile_dir = profile_dir
  20. self.path = re.compile(path)
  21. async def __call__(self, scope: Scope, receive: Receive, send: Send) -> None:
  22. if scope["type"] != "http" or not self.path.match(scope["path"]):
  23. await self.app(scope, receive, send)
  24. return
  25. yappi.set_clock_type("wall")
  26. received = now()
  27. with yappi.run():
  28. await self.app(scope, receive, send)
  29. stats = yappi.convert2pstats(yappi.get_func_stats())
  30. stats.dump_stats(self.profile_dir / f"{received.isoformat()}.pstats")
  31. yappi.clear_stats()