You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Provide an ASGI counterpart to TraceErrorsMiddleware so ASGI applications (Starlette, FastAPI, bare ASGI apps) can get crash reporting through the existing reporters (email, Sentry).
Done criteria:
A new AsgiTraceErrorsMiddleware (e.g. in backlash/tracing/errors/) that:
Passes through non-http scopes (websocket, lifespan) untouched.
Catches unhandled exceptions, builds the context (context injectors receive the ASGI scope), captures the traceback, logs it, and dispatches it to the configured reporters.
Sends a plain 500 Internal Server Error response when http.response.start has not been sent; logs and re-raises when the response already started (matching AsgiDebuggedApplication post-start semantics from Add ASGI support for the interactive debugger #23).
Supports the recorded-exception protocol: after the app completes, a backlash.exc_info key stashed in the scope by the framework is popped and reported (ASGI analog of the WSGI environ['backlash.exc_info'] handshake used by TurboGears).
Reporters are reused unchanged.
Error output goes to the backlash logger / sys.stderr (no wsgi.errors equivalent exists in ASGI).
Behavior is covered by in-process ASGI tests mirroring the existing WSGI middleware semantics.
Out of scope: TraceSlowRequestsMiddleware. Its thread-ident stack snapshotting (sys._current_frames()) is meaningless under an event loop and needs a redesign around asyncio.Task.get_stack(); that deserves its own issue.
Why
#23 brings the interactive debugger to ASGI, but production crash reporting (email/Sentry) remains WSGI-only, so ASGI users get development-time parity without the production-facing half. The middleware is structurally a stripped-down AsgiDebuggedApplication (run app, capture, report, plain 500), and the reporters already consume only the transport-agnostic Traceback object, so the port is a thin adapter (~60 lines) over existing scaffolding.
One caveat worth addressing during implementation: EmailReporter uses synchronous smtplib, which blocks the event loop while reporting. Consider offloading reporter dispatch (e.g. asyncio.to_thread) or documenting the trade-off; the Sentry reporter queues internally and is unaffected.
References
backlash/tracing/errors/middleware.py (TraceErrorsMiddleware) — WSGI logic to mirror, including the backlash.exc_info / backlash.exc_environ recorded-exception handshake.
backlash/asgi.py (AsgiDebuggedApplication, from Add ASGI support for the interactive debugger #23) — established ASGI shell patterns: scope filtering, response-started tracking, post-start re-raise, logger/stderr error sink.
backlash/tracing/reporters/ (mail.py, sentry.py) — transport-agnostic reporters to reuse.
Goal
Provide an ASGI counterpart to
TraceErrorsMiddlewareso ASGI applications (Starlette, FastAPI, bare ASGI apps) can get crash reporting through the existing reporters (email, Sentry).Done criteria:
AsgiTraceErrorsMiddleware(e.g. inbacklash/tracing/errors/) that:httpscopes (websocket,lifespan) untouched.scope), captures the traceback, logs it, and dispatches it to the configured reporters.500 Internal Server Errorresponse whenhttp.response.starthas not been sent; logs and re-raises when the response already started (matchingAsgiDebuggedApplicationpost-start semantics from Add ASGI support for the interactive debugger #23).backlash.exc_infokey stashed in the scope by the framework is popped and reported (ASGI analog of the WSGIenviron['backlash.exc_info']handshake used by TurboGears).backlashlogger /sys.stderr(nowsgi.errorsequivalent exists in ASGI).Out of scope:
TraceSlowRequestsMiddleware. Its thread-ident stack snapshotting (sys._current_frames()) is meaningless under an event loop and needs a redesign aroundasyncio.Task.get_stack(); that deserves its own issue.Why
#23 brings the interactive debugger to ASGI, but production crash reporting (email/Sentry) remains WSGI-only, so ASGI users get development-time parity without the production-facing half. The middleware is structurally a stripped-down
AsgiDebuggedApplication(run app, capture, report, plain 500), and the reporters already consume only the transport-agnosticTracebackobject, so the port is a thin adapter (~60 lines) over existing scaffolding.One caveat worth addressing during implementation:
EmailReporteruses synchronoussmtplib, which blocks the event loop while reporting. Consider offloading reporter dispatch (e.g.asyncio.to_thread) or documenting the trade-off; the Sentry reporter queues internally and is unaffected.References
backlash/tracing/errors/middleware.py(TraceErrorsMiddleware) — WSGI logic to mirror, including thebacklash.exc_info/backlash.exc_environrecorded-exception handshake.backlash/asgi.py(AsgiDebuggedApplication, from Add ASGI support for the interactive debugger #23) — established ASGI shell patterns: scope filtering, response-started tracking, post-start re-raise, logger/stderr error sink.backlash/tracing/reporters/(mail.py,sentry.py) — transport-agnostic reporters to reuse.