Skip to main content

🔬 API Autopsy

Production-grade API performance analysis for Django and FastAPI.

Automatically detect performance issues — N+1 queries, blocking async calls, slow serializers — without external APM services.

Python 3.9+ License: MIT


⚡ Quickstart

Install

pip install api-autopsy

Django

# settings.py
INSTALLED_APPS += ["api_autopsy"]

MIDDLEWARE += ["api_autopsy.integrations.django.middleware.APIAutopsyMiddleware"]

FastAPI

from fastapi import FastAPI
from api_autopsy.integrations.fastapi import APIAutopsyMiddleware

app = FastAPI()
app.add_middleware(APIAutopsyMiddleware)

That's it. Visit /api-autopsy/ to see the dashboard.


🎯 What It Detects

Category Detection
N+1 Queries Repeated SQL patterns across a single request
Duplicate Queries Identical SQL executed multiple times
Slow Queries Individual queries exceeding thresholds
Missing Indexes Slow WHERE clauses on non-primary columns
Slow Serializers DRF serializer timing and nested cost
Async Violations time.sleep(), requests.* in async handlers
Memory Bloat Per-request memory allocation deltas
External Calls Outbound HTTP call count and timing

Every detection comes with actionable recommendations.


📊 Performance Score

Each endpoint receives a 0–100 score based on:

  • Latency (30%) — exponential decay from ideal threshold
  • Query Efficiency (30%) — penalizes count, duplicates, N+1
  • Memory Usage (20%) — penalizes large allocation deltas
  • Async Correctness (20%) — binary penalties for blocking calls

🖥️ Dashboard

Auto-served at /api-autopsy/ with:

  • Endpoint ranking table (sortable by score, latency, queries)
  • Performance timeline (5-minute buckets over 24h)
  • Slow endpoint heatmap (by hour)
  • Analysis findings with severity and recommendations
  • Dark/light mode toggle
  • Auto-refresh every 30s

🔧 Configuration

Django

# settings.py
API_AUTOPSY = {
    "ENABLED": True,
    "STORAGE_BACKEND": "sqlite",      # sqlite | postgres | redis
    "STORAGE_DSN": "autopsy.db",
    "SAMPLE_RATE": 1.0,               # 0.0–1.0
    "RETENTION_HOURS": 72,
    "DASHBOARD_PREFIX": "/api-autopsy",
}

FastAPI

from api_autopsy.config import configure

configure(
    sample_rate=0.1,       # 10% sampling in production
    retention_hours=48,
    storage_dsn="/var/data/autopsy.db",
)

🚀 CI/CD Mode

# Generate JSON report
api-autopsy analyze --format json --output report.json

# Fail CI if score drops below threshold
api-autopsy analyze --threshold 70

# Detect regression against a baseline
api-autopsy analyze --baseline baseline.json --threshold 10

# Cleanup old data
api-autopsy cleanup --hours 24

Exit codes: 0 = pass, 1 = regression or critical findings.


🔌 Extensibility

Custom Analyzer

from api_autopsy.plugins import register_analyzer
from api_autopsy.analyzers.base import BaseAnalyzer
from api_autopsy.core.context import Finding

@register_analyzer
class MyCustomAnalyzer(BaseAnalyzer):
    def analyze(self, ctx):
        findings = []
        if ctx.duration_ms > 1000:
            findings.append(Finding(
                severity="warning",
                category="slow_response",
                message=f"Response took {ctx.duration_ms:.0f}ms",
                recommendation="Consider caching or pagination.",
            ))
        return findings

Via Entry Points

# pyproject.toml
[project.entry-points."api_autopsy.plugins"]
my_plugin = "my_package.autopsy:register"

🏗️ Architecture

api_autopsy/
├── config.py              # Central configuration + auto-detection
├── plugins.py             # Plugin discovery system
├── core/
│   ├── context.py         # contextvars-based RequestContext
│   └── registry.py        # Collector/Analyzer registry
├── collectors/
│   ├── base.py            # Abstract collector
│   ├── timing.py          # Request duration
│   ├── sql.py             # SQL queries + duplicates
│   ├── memory.py          # Memory delta (tracemalloc)
│   ├── http_calls.py      # Outbound HTTP tracking
│   └── cache.py           # Cache hit/miss tracking
├── analyzers/
│   ├── base.py            # Abstract analyzer
│   ├── orm.py             # N+1, duplicates, slow queries
│   ├── serializer.py      # DRF serializer profiling
│   └── async_safety.py    # Blocking I/O detection
├── scoring/
│   └── engine.py          # Weighted 0–100 scoring
├── storage/
│   ├── base.py            # Abstract storage
│   └── sqlite.py          # SQLite backend (default)
├── dashboard/
│   ├── views.py           # Django + ASGI handlers
│   └── templates/
│       └── index.html     # Dashboard UI
├── integrations/
│   ├── django/
│   │   ├── apps.py        # Django AppConfig
│   │   └── middleware.py   # WSGI middleware
│   └── fastapi/
│       └── middleware.py   # ASGI middleware
└── cli/
    └── main.py            # CLI entry point

🧪 Testing

pip install -e ".[dev]"
pytest tests/ -v

Production Safety

  • Sampling: Set sample_rate to 0.01–0.1 for high-traffic
  • Overhead: < 5% with sampling; collectors are lightweight
  • Retention: Auto-cleanup via retention_hours or CLI
  • Async-safe: Uses contextvars — no thread-local issues

License

MIT

Metadata

Release files for api-autopsy 0.1.0

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

Source distribution (sdist)

Source distribution for api-autopsy 0.1.0
File Size Uploaded Provenance
api_autopsy-0.1.0.tar.gz 27.9 kB Without provenance Details

Built distribution (wheel)

Table of built distributions (wheels) for api-autopsy 0.1.0
File Interpreter ABI Platform
api_autopsy-0.1.0-py3-none-any.whl Python 3 none any Details

Total release size: 68.4 kB

Release files / api_autopsy-0.1.0.tar.gz

Download URL api_autopsy-0.1.0.tar.gz
Size 27.9 kB
Tags Source
SHA-256 checksum
How to use checksums
0de0479d52657649c3c714bddaadb2d0e21dea216fe795e3ed4367e2ae014862
BLAKE2b-256 checksum
How to use checksums
4c567682e8c910c94c2f9176b7538974e97a3a94e6f65cf1b7cab528c05c9770
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.2.0 CPython/3.10.12

Release files / api_autopsy-0.1.0-py3-none-any.whl

Download URL api_autopsy-0.1.0-py3-none-any.whl
Size 40.5 kB
Tags Python 3
SHA-256 checksum
How to use checksums
29fb845ba9af56e69c5ddc0323019da3cf4434b8461c386e36cd31f32c9560fc
BLAKE2b-256 checksum
How to use checksums
bdb31b9f54e57d1f73c823ef0f0bc2294c9bf59fa1e3bd3ca692e620aca7499b
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.2.0 CPython/3.10.12

Security for api-autopsy 0.1.0

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.0 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