neva-asgi
ASGI middleware for the Neva framework.
python-neva is the framework-agnostic core: it must not import an ASGI
framework. This package holds the middleware that used to live in
neva.obs.middleware, so that boundary holds.
It sits below the protocol integrations rather than inside one — neva-fastapi
and neva-faststream (in its ASGI mode) can both consume it without depending
on each other.
Install
uv add neva-asgi
Middleware
CorrelationMiddleware
Assigns a correlation ID to every HTTP and WebSocket request, reusing an
inbound X-Request-ID or X-Correlation-ID when it is a valid UUID and
generating one otherwise. The ID is published on scope["state"]["correlation_id"]
and echoed on the response. It is also bound into structlog's context, so every
log line emitted while handling the request carries correlation_id without the
caller threading it through — structlog's default processor chain merges
contextvars, so this needs no logging configuration.
from neva.asgi import CorrelationMiddleware
app.add_middleware(CorrelationMiddleware, header_name="X-Request-ID")
generator and validator are both injectable, so a service that uses ULIDs or
a non-UUID scheme can swap them.
ProfilerMiddleware
Profiles each HTTP request with pyinstrument
and writes an HTML report per request. It names the file after the correlation
ID when CorrelationMiddleware runs ahead of it, and falls back to a timestamp.
from neva.asgi import ProfilerMiddleware
app.add_middleware(ProfilerMiddleware, path="./profiles", interval=0.001)
Intended for local and staging use: it profiles every request and writes a file per request.
TracingMiddleware
Requires the otel extra:
uv add "neva-asgi[otel]"
Emits an OpenTelemetry HTTP server span per request, carrying the matched
route's template rather than the resolved path — /users/{id}, not
/users/42. Without that, every request is its own operation name and no
endpoint can be aggregated, so a trace backend has nothing to graph.
from neva.asgi import CorrelationMiddleware
from neva.asgi.tracing import TracingMiddleware
from neva.fastapi import route_template
app.add_middleware(TracingMiddleware, route_resolver=route_template)
app.add_middleware(CorrelationMiddleware)
The span is not written here: opentelemetry-instrumentation-asgi already
carries the semantic conventions, the server metrics, header capture, context
propagation and WebSockets. This middleware composes it and adds the one thing
it cannot know — the route — because it runs outside the application, where
nothing has matched yet. opentelemetry-instrumentation-fastapi is not the
answer either: it re-walks app.routes to resolve the route, and since FastAPI
0.137 made include_router lazy that walk no longer reaches the prefixed
template.
route_resolveris injected rather than imported, so this package depends on no web framework andneva-fastapidepends on no OpenTelemetry.neva.fastapi.route_templateis the FastAPI implementation; any(scope) -> str | Nonewill do.- The correlation ID is stamped on the span as
correlation_idwhenCorrelationMiddlewarehas run, which is what pivots a client-reported request ID to the trace that served it. Either middleware order works — the span is stamped once routing is done, by which point both have run. - Unmatched requests keep a bare method as the span name (
GET, orHTTPfor a method the client invented) and carry nohttp.route. Upstream's default appends the request path, which lets a bot sweep mint one operation name per URL it probes. - Unknown keyword arguments are forwarded to the instrumentor, so
excluded_urls, the request hooks, header capture and an explicittracer_providerall still work. Two upstream defaults are overridden and can be set back:default_span_detailsandexclude_spans, the latter because upstream emits a child span per ASGIreceiveandsendevent.
Importing neva.asgi does not import OpenTelemetry — neva.asgi.tracing
is the only module that does, and nothing re-exports it. A test asserts that in
a subprocess, because a single convenience re-export would quietly make the
extra mandatory for every CorrelationMiddleware user.
Develop
uv sync --all-extras
poe lint && poe fmt && poe tc && poe test
Agent guidelines
neva/asgi/guidelines/fragments/ is what this package contributes to
neva-boost. Those files are the source and
the thing to edit; poe guidelines holds them to the frontmatter contract and runs in
CI.
Renders are not committed — requires is evaluated against installed versions, so
one is only correct for the environment that produced it. Compose your own:
poe guidelines-render # .claude/skills/, gitignored
uv run neva-boost install --target agents # AGENTS.md instead
Commits follow Conventional Commits with gitmoji via cz commit; releases are
cut with cz bump.
Metadata
Release files for neva-asgi 0.2.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| neva_asgi-0.2.0.tar.gz | 118.6 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| neva_asgi-0.2.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 134.2 kB
Release files / neva_asgi-0.2.0.tar.gz
| Download URL | neva_asgi-0.2.0.tar.gz |
|---|---|
| Size | 118.6 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
a4e27b674eb573f28e0e8b37afec1c4ce3a507bbc94b5d5f33a318e67aee5c25
|
|
BLAKE2b-256 checksum How to use checksums |
d204bfe9d7a6c2db9ab1482a26a4948eb513afb92778f4a99500af3628b33e88
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
uv/0.8.22
|
Release files / neva_asgi-0.2.0-py3-none-any.whl
| Download URL | neva_asgi-0.2.0-py3-none-any.whl |
|---|---|
| Size | 15.6 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
b99849bc515ce14aa6524de98b2a97da5489e7e20782990c24eaaab0e68a0620
|
|
BLAKE2b-256 checksum How to use checksums |
77e3e1b8c6599ba934a4ad92bf96f66d93a28af2841261ac595e501c9ba8ecd1
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
uv/0.8.22
|