Question about exception handling
sralloza opened this issue · comments
I'm having problems detecting the root of some 500 error servers (using FastAPI, a2wsgi and Apache) because exceptions are not logged nor printed anywhere.
Given the following wsgi FastAPI app:
from a2wsgi import ASGIMiddleware
from fastapi import FastAPI
app = FastAPI()
@app.get("/good")
def good():
return "good"
@app.get("/bad")
def bad():
raise ValueError("some error")
application = ASGIMiddleware(app)
Executed by werkzeug simulating an wsgi server, as Apache with mod_wsgi:
from werkzeug import run_simple
run_simple("localhost", 80, application)
When accesing /good
, the browser shows "good"
, as expected. But when accesing /bad
, the browser outputs Internal Server Error
, and no error is logged in the console. The console only outputs 127.0.0.1 - - [20/Oct/2020 22:33:44] "GET /bad HTTP/1.1" 500 -
.
So, I'd like to know how could make mod_wsgi write the exception to the error log or (as I understand this issue may be outside the module's scope) how can I make a2wsgi print the exception to stderr, so then the mod_wsgi can treat the output as an error.
Thanks in advance.
When you initiated this issue, I refactored the code of ASGIMiddleware
. Maybe you can try the latest version of a2wsgi.
In addition, throwing exceptions is not what WSGI applications need to do, it should be done by WSGI Server. https://www.python.org/dev/peps/pep-3333/#the-start-response-callable
Can you use the following WSGI application to test and see if it has Traceback output?
def return_exc_info(environ, start_response):
try:
raise RuntimeError("Something went wrong")
except RuntimeError:
status = "500 Internal Server Error"
output = b"Internal Server Error"
headers = [
("Content-Type", "text/plain; charset=utf-8"),
("Content-Length", str(len(output))),
]
start_response(status, headers, exc_info=sys.exc_info())
yield output
First of all, thanks for the fast reply. I've read the PEP about wsgi and you're right, it's the server's job to check if the wsgi application raised an error.
I executed the code you sent and nothing is printed, but I think it's a werkzeug's problem.
Just in case someone has the same error, I decided to log myself the exception, using FastAPI's exception handling:
from uuid import uuid4
import logging
from starlette.responses import JSONResponse
logger = logging.getLogger(__name__)
@app.exception_handler(500)
def catch_errors(request, exc):
error_id = uuid4()
scope = request.scope
request_info = (
f"{request.client.host}: {scope['scheme'].upper()}/{scope['http_version']} "
f"{scope['method']} {scope['path']}"
)
exc_info = (exc.__class__, exc, exc.__traceback__)
logger.critical(
"Unhandled exception [id=%s] in request '%s':",
error_id,
request_info,
exc_info=exc_info,
)
return JSONResponse(
status_code=500,
content={
"detail": "Internal Server Error, please contact the server administrator."
},
headers={"X-Error-ID": str(error_id)},
)
By the way, amazing tool you have created. I'm using it to deploy a FastAPI backend using Apache, which doesn't support ASGI yet.
Thank you for your sharing.