Package: pyloot
PyLootPyLoot is a memory leak detector based onDozerandvprofwith added support for servers with multiple workers/processes.This project is in active development and may contain bugs or otherwise work in ways not expected or intended.Installation$pipinstallpylootBasic API UsagefrompylootimportPyLootloot=PyLoot()"""Collect objects still in `gc.get_objects` after a call to `gc.collect`."""loot.collect_objects()"""Collecting data in a background thread every 30 seconds.If gevent is detected, gevent.threadpool.spawn is used.Otherwise, threading.Thread is used."""loot.start()"""Stop running the collector background thread.NOTE: This does not do a "final" collection.To ensure objects were collected in a short lived execution, call collect_objects().:param blocking: When true, wait until the thread has died"""loot.stop()"""Return a WSGI compatible application serving the PyLoot remote backend andand the website.:return: ::class::`PyLootServer`"""loot.get_wsgi()Running embedded within a serverStarlette/FastApi/ASGIsee note below about bypassing themultiprocessing checkfrompylootimportPyLootfromfastapiimportFastAPIfromstarlette.applicationsimportStarlettefromstarlette.middleware.wsgiimportWSGIMiddlewareapp=FastAPI()# or Starlette()pyloot=PyLoot()app.on_event("startup")(pyloot.start)app.mount("/_pyloot",WSGIMiddleware(pyloot.get_wsgi()))Flask/WSGIfrompylootimportPyLootfromflaskimportFlaskfromwerkzeug.middleware.dispatcherimportDispatcherMiddlewareapp=Flask(__name__)pyloot=PyLoot()app.on_before_first_request(pyloot.start)app=DispatcherMiddleware(app,{'/_pyloot':pyloot.get_wsgi()})Running in remote mode (multi-process servers)# Embedded codefrompylootimportPyLoot...pyloot=PyLoot(host="127.0.0.1",port=8000)...# Start the remote server$pyloot--help
usage:pyloot[-hHOST][-pPORT][--help]optionalarguments:
-hHOST,--hostHOSTHosttolistenon.(Default:0.0.0.0)-pPORT,--portPORTPorttolistenon.(Default:8000)--helpshowthishelpmessageandexitBypass the multiprocessing checkIf pyloot detects it is running in a multiprocessing environment with an inmemory backend
it will refuse to serve the webpages/requests.This environment is common for gunicorn servers running with multiple workers.
If you run pyloot embedded in a gunicorn server with multiple workers, statistics will be collected in each individual worker and a random worker will be selected when returning statistics.
When using multiple workers, pyloot will give the most accurate information using the http backend.
For dev servers or servers with really low traffic (e.g. <1 request per second), you can also reduce the workers to 1.
Pyloot cannot detect how many workers are running so the bypass is still needed when only 1 worker is used.The WSGIMiddleware of starlette setsenviron["wsgi.multiprocess"]=Trueregardless of the server.
This can be bypassed with a wrapperuse with caution:pyloot=PyLoot()defpyloot_wrapper(wsgi_environ,start_response):pyloot_environ=wsgi_environ.copy()pyloot_environ["wsgi.multiprocess"]=Falsewsgi=pyloot.get_wsgi()returnwsgi(pyloot_environ,start_response)app.mount("/_pyloot",WSGIMiddleware(pyloot_wrapper))Disabling gzip encodingBy default, the pyloot server will gzip encode the response metadata.
If pyloot is running behind a middleware that gzip encodes data, encoding can happen twice.
This will result in the following error being shown in the UI:Error parsing the response data. Check the server logs. If everything looks ok, you make need to disable gzip in pyloot. For more info see the README.To disable gzip encoding do the following:frompylootimportPyLootfrompylootimportPyLootServerpyloot=PyLoot(server=PyLootServer(disable_response_gzip=True))If a remote server is used, it must be configured directly on the server like so:frompylootimportPyLootfrompylootimportPyLootServerfrompylootimportHTTPRemoteBackendbackend=HTTPRemoteBackend(host="127.0.0.1",port=8000)pyloot=PyLoot(server=PyLootServer(backend=backend,disable_response_gzip=True))ScreenshotsView history of object counts by object group:Modify history page sizeSearch history pageView objects by groupModify objects fetch sizeModify objects page sizeView an object, its attributes,repr, children, and parents