Skip to main content

🔧 LeakySpanner

Zero-interference memory leak profiler for FastAPI.
Pure spectator mode — watches everything, touches nothing.


The Problem

FastAPI + Python async apps can silently grow to 4–5 GB RAM at peak load.
Finding where is painful because the leak could be anywhere — images held in memory,
uncleaned async tasks, connection pools, Gemini API response objects.

The Solution

LeakySpanner attaches to your FastAPI app as a pure spectator:

  • ✅ Watches every request
  • ✅ Samples memory in a background thread every N seconds
  • ✅ Tracks memory delta per endpoint
  • ✅ Uses tracemalloc to find top allocation sites
  • ✅ Writes a clean log file you can grep through
  • ❌ Never blocks a request
  • ❌ Never adds latency
  • ❌ Never modifies request/response
  • ❌ If LeakySpanner crashes — your app keeps running

Install

pip install leakyspanner

Usage

from fastapi import FastAPI
from leakyspanner import leakyspanner

app = FastAPI()

# One line — that's it
leakyspanner(app)

With options:

leakyspanner(
    app,
    enabled=True,               # set False in tests
    log_path="./leak_logs",     # where to write logs
    level="deep",               # basic | mid | deep
    interval_seconds=5.0,       # memory snapshot every 5s
    leak_threshold_mb=50.0,     # warn if RSS grows 50MB above baseline
)

Levels

Level What it tracks
basic Endpoint-level memory delta per request
mid Endpoint deltas + tracemalloc top allocation stats (default)
deep Everything + per-snapshot top allocation traces with file/line

Log Output

LeakySpanner writes to ./leakyspanner_logs/leakyspanner_YYYYMMDD_HHMMSS.log

Snapshot log (every 5s):

[14:32:05] RSS=312.4MB  VMS=890.1MB  delta=+12.1MB  GC=(142, 8, 1)
[14:32:10] RSS=318.7MB  VMS=890.1MB  delta=+18.4MB  GC=(198, 8, 1)

Endpoint delta log (when delta > 1MB):

  [14:32:07] ENDPOINT POST /ocr/process  mem_delta=+6.23MB  status=200
  [14:32:08] ENDPOINT POST /ocr/process  mem_delta=+5.91MB  status=200

Warning (when growth > threshold):

  ⚠️  [14:35:00] MEMORY GROWTH ALERT: +87.3 MB above baseline
                 (baseline=312.4 MB, current=399.7 MB)

Session summary (on shutdown):

======================================================================
  LEAKYSPANNER SESSION SUMMARY
======================================================================
  Peak RSS    : 4821.3 MB
  Final RSS   : 4103.7 MB
  Baseline RSS: 312.4 MB
  Net growth  : +3791.3 MB

  ENDPOINT MEMORY DELTAS (sorted by avg):
    POST   /ocr/process                        calls= 412  avg=+8.73MB  max=+41.20MB
    GET    /health                             calls=1204  avg=+0.00MB  max= +0.01MB
======================================================================

Deep level — tracemalloc traces:

  ── top allocations ──
    42.3KB × 18  /app/services/gemini.py:87
    38.1KB × 412 /app/services/ocr.py:134
    21.7KB × 1   /usr/lib/python3.11/ssl.py:1092

Reading the Logs

Once you have the log, look for:

  1. Endpoint with highest avg delta → that's your primary suspect
  2. Steadily rising RSS snapshots that never drops → classic leak
  3. tracemalloc lines pointing to specific file:line → that's the smoking gun
  4. GC counts growing without dropping → reference cycles not being collected

Real-world Example (OCR App)

app = FastAPI()

leakyspanner(
    app,
    level="deep",
    log_path="/var/log/myapp/leaks",
    leak_threshold_mb=200.0,     # alert at 200MB growth
    interval_seconds=10.0,       # sample every 10s in prod
)

@app.post("/ocr/process")
async def process(file_id: str):
    # LeakySpanner watches this — you change nothing
    results = await asyncio.gather(
        call_gemini_1(file_id),
        call_gemini_2(file_id),
        call_qr_service(file_id),
        fetch_from_db(file_id),
    )
    return results

License

MIT

Metadata

Release files for leakyspanner 0.1.2

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for leakyspanner 0.1.2
File Size Uploaded Provenance Actions
leakyspanner-0.1.2.tar.gz 17.2 kB Without provenance Details for leakyspanner-0.1.2.tar.gz

Built distribution (wheel)

Table of built distributions (wheels) for leakyspanner 0.1.2
File Interpreter ABI Platform Actions
leakyspanner-0.1.2-py3-none-any.whl Python 3 none any Details for leakyspanner-0.1.2-py3-none-any.whl

Total release size: 29.2 kB

Release files / leakyspanner-0.1.2.tar.gz

Download URL leakyspanner-0.1.2.tar.gz
Size 17.2 kB
Tags Source
SHA-256 checksum
How to use checksums
0cb81e4eeecf931fa0ad28f0c8f1e4ab50736d4daac72de10011ec303b7c8189
BLAKE2b-256 checksum
How to use checksums
98a011ababb2043d41273592f91aee030fc840a73b1e56189025c46972b22fcb
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.2.0 CPython/3.13.9

Release files / leakyspanner-0.1.2-py3-none-any.whl

Download URL leakyspanner-0.1.2-py3-none-any.whl
Size 12.0 kB
Tags Python 3
SHA-256 checksum
How to use checksums
ef1205410d9f5bab73e03809da2e3d6d35b41e936adcf154896ee0e8053c4577
BLAKE2b-256 checksum
How to use checksums
afea220ece6f06221bd104a8c03cc7908d1438de44b22de9a3d0d134929e0f32
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.2.0 CPython/3.13.9

Security for leakyspanner 0.1.2

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

No provenance found

None of the files in this release were uploaded with provenance metadata.

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

To learn more about protecting yourself from malicious actors, visit our package security documentation.

Release history Release notifications | RSS feed

This release

0.1.2 This release

2 release files No provenance

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page