Skip to main content

A tiny prod-safe perf footer & toolbar for ASGI apps.

Project description

pagebar

A tiny prod-safe perf footer for ASGI apps. One line at the bottom of every page, click to expand. No SQL text, no env vars, no stack traces — nothing that could leak.

v2026.6.19 · 22ms · 4 SQL · GET /editeurs · 200

Install

pip install pagebar              # core only
pip install pagebar[sqlalchemy]  # with SQL query counter

Use

Starlette / FastAPI

from pagebar import PagebarMiddleware, pagebar_html
from starlette.applications import Starlette
from starlette.middleware import Middleware

app = Starlette(
    middleware=[Middleware(PagebarMiddleware, package="my-app")],
    routes=[...],
)

Litestar (and other mw_cls(app)-style frameworks)

Litestar instantiates middleware as cls(app) with no further kwargs, so config has to be baked in. Use PagebarMiddleware.bound(...):

from litestar import Litestar
from pagebar import PagebarMiddleware

app = Litestar(
    middleware=[
        PagebarMiddleware.bound(package="my-app", unsafe=False),
    ],
    route_handlers=[...],
)

.bound(**kwargs) returns a thin subclass with the kwargs baked into __init__. Same fields as the regular constructor.

Flask (WSGI)

Flask isn't ASGI, so there's no middleware — the pagebar[flask] extra ships a small extension that wires the same data collection into Flask's request lifecycle:

from flask import Flask
from pagebar.flask import Pagebar

app = Flask(__name__)
Pagebar(app, package="my-app", unsafe=app.debug)

Same knobs as PagebarMiddleware. pagebar_html is registered as a Jinja global, so the template usage below works unchanged. enabled/unsafe callables receive the Flask request (the ASGI versions get the connection scope).

Template

In your base template, anywhere inside <body>:

{{ pagebar_html() | safe }}
</body>

That's it. One name for the middleware, one for the helper.

What's on screen

Field Source
Version importlib.metadata.version(package) — or explicit version=
Time time.perf_counter() delta
SQL SQLAlchemy before_cursor_execute listener (if installed)
Request method + path
Memory resource.getrusage().ru_maxrss — RSS in MiB
Uptime time.monotonic() since worker import
Threads threading.active_count()
GC gc.get_count() — gen0/gen1/gen2 pending
Python sys.version_info
PID os.getpid()

No SQL text. No params. No env. No traces. That's the whole surface.

Knobs

PagebarMiddleware(
    app,
    package="my-app",     # distribution name (PyPI / pyproject.toml)
    version="",           # escape hatch: bypass importlib.metadata lookup
    enabled=True,         # bool or callable(scope) -> bool
    unsafe=False,         # bool or callable(scope) -> bool — see below
    query_budget=20,      # >0 → log a WARNING when SQL count exceeds this
)

Unsafe mode

In dev, you usually want to see the SQL text. Flip unsafe=True and the bar adds, per request: each statement (truncated), bound parameters, and per-statement timing. A red UNSAFE badge in the pill makes the mode obvious.

import os
PagebarMiddleware(app, package="my-app", unsafe=bool(os.getenv("DEBUG")))
# or framework-driven
PagebarMiddleware(app, package="my-app", unsafe=app.debug)

unsafe defaults to False and only takes its value from constructor wiring — no URL parameter, no header, no cookie. The host's deploy config is the authority.

enabled lets you hide the bar from JSON endpoints, healthchecks, or admin routes:

def show(scope):
    return not scope["path"].startswith(("/api/", "/health"))

Middleware(PagebarMiddleware, package="my-app", enabled=show)

Bots are skipped automatically (User-Agent matching bot|crawler|spider|googlebot|bingbot).

CSP

pagebar_html() accepts a nonce keyword that's applied to the inline <style> and <script>:

{{ pagebar_html(nonce=csp_nonce) | safe }}

Otherwise the host needs 'unsafe-inline' for both directives. No external assets, no third-party requests.

Why not the Django/Flask/Litestar debug toolbars?

They reveal SQL text, environment, settings, request bodies, stack traces — fine in dev, unacceptable in production. pagebar surfaces a fixed, public-safe set of fields. The shape is the security model.

Non-goals

No panels system, no plugins, no per-framework adapters, no APM, no time series, no SQL EXPLAIN, no profiler. Pure ASGI middleware + one helper function in one file.

License

MIT.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

pagebar-0.1.1.tar.gz (143.4 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

pagebar-0.1.1-py3-none-any.whl (10.8 kB view details)

Uploaded Python 3

File details

Details for the file pagebar-0.1.1.tar.gz.

File metadata

  • Download URL: pagebar-0.1.1.tar.gz
  • Upload date:
  • Size: 143.4 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: uv/0.11.16 {"installer":{"name":"uv","version":"0.11.16","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"macOS","version":null,"id":null,"libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}

File hashes

Hashes for pagebar-0.1.1.tar.gz
Algorithm Hash digest
SHA256 9fb8f2488e04a37c3acb5e33ae2b1a028fe6c1fe0f3e7da2e2835c821bcc273b
MD5 1d002ab62d9a19a04bae90107fcf7ee2
BLAKE2b-256 93216e6e9c5037b3b082e3080b7391d34cf21a695d8d006876dafde0ed5b3ce2

See more details on using hashes here.

File details

Details for the file pagebar-0.1.1-py3-none-any.whl.

File metadata

  • Download URL: pagebar-0.1.1-py3-none-any.whl
  • Upload date:
  • Size: 10.8 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: uv/0.11.16 {"installer":{"name":"uv","version":"0.11.16","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"macOS","version":null,"id":null,"libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}

File hashes

Hashes for pagebar-0.1.1-py3-none-any.whl
Algorithm Hash digest
SHA256 766e3c27a323f2807338082d30eb0f707cef0d9f1b5a3638295485f8b2917355
MD5 58ff24cbbadc1ab98aeb3cd50ff4a2f7
BLAKE2b-256 e02d622c85dbe347fbe84dbe186a97d6c974e135209728fddb05cb7738ada2a5

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page