0

I am running a simple FastAPI application under uvicorn. The FastAPI code is this:

from fastapi import FastAPI

@app.post("/events")
def create_events():
    print("entering create_events()")
    raise Exception("an error")

I run the app:

uvicorn api.main:app --reload --log-level=debug

I now post to the endpoint using wget:

wget -O- --header='Content-Type:application/json' --post-file=/tmp/data.json http://127.0.0.1:8000/events

Not surprisingly, the wget returns a 500 Internal Server Error.

In the output of the terminal where I ran uvicorn I see this:

entering create_events()

In other web application contexts (Perl, Ruby on Rails, Python with Flask) if the server raises an unhandled exception I can see the error message on the server side somewhere: in a log file, on standard output, somewhere. But in this FastAPI/uvicorn application I cannot find any error message. I don't see it in the place where I ran the wget and I don't see it in the uvicorn terminal.

Where is the 500 error message logged/displayed?

rlandster
  • 7,294
  • 14
  • 58
  • 96
  • you have added raise exception in the api end point function. this error is coming from that – sahasrara62 Jul 25 '23 at 17:42
  • You might find the following answers helpful: [this](https://stackoverflow.com/a/72833284/17865804), [this](https://stackoverflow.com/a/71800464/17865804), as well as [this](https://stackoverflow.com/a/70954531/17865804) and [this](https://stackoverflow.com/a/71682274/17865804) – Chris Jul 26 '23 at 04:36

2 Answers2

0

If you want your Fastapi endpoint to return specific Http error you need to use HTTPException. If code executed by endpoint throws any other exception, it will return 500, which is internal server error.

example:

from fastapi import FastAPI, HTTPException, status

@app.post("/events")
def create_events():
    print("entering create_events()")
    raise HTTPException(
        status_code=status.HTTP_400_BAD_REQUEST,
        detail="an error",
    )

If you want to log error message, you could add custom handler:

from fastapi import Request
from fastapi.responses import PlainTextResponse

async def unhandled_exception_handler(request: Request, exc: Exception) -> PlainTextResponse:
    """
    This middleware will log all unhandled exceptions.
    Unhandled exceptions are all exceptions that are not HTTPExceptions or RequestValidationErrors.
    """
    logger.debug("Our custom unhandled_exception_handler was called")
    host = getattr(getattr(request, "client", None), "host", None)
    port = getattr(getattr(request, "client", None), "port", None)
    url = f"{request.url.path}?{request.query_params}" if request.query_params else request.url.path
    exception_type, exception_value, exception_traceback = sys.exc_info()
    exception_name = getattr(exception_type, "__name__", None)
    logger.error(
        f'{host}:{port} - "{request.method} {url}" 500 Internal Server Error <{exception_name}: {exception_value}>'
    )
    return PlainTextResponse(str(exc), status_code=500)

Then you can add the handler to your app:

app.add_exception_handler(Exception, unhandled_exception_handler)
w8eight
  • 605
  • 1
  • 6
  • 21
  • Thank you for your response, but what I am trying to determine is where FastAPI/uvicorn is logging or displaying unhandled errors. – rlandster Jul 25 '23 at 17:50
  • @rlandster I updated the answer, maybe this can help – w8eight Jul 25 '23 at 17:51
  • Thanks for that, but what happens if there is a bug in unhandled_exception_handler? There _must_ be a place of last resort that the system sends error messages. – rlandster Jul 25 '23 at 17:52
  • @rlandster That should be handled by uvicorn, you should see error code and traceback in logs. Did you modify uvicorn logger perhaps? – w8eight Jul 25 '23 at 17:56
  • No. I did a pip install of uvicorn and run it as I stated in my question. No explicit customizations. – rlandster Jul 25 '23 at 17:57
0

I don't think this is an issue with uvicorn. If there is an error it displays it on terminal by default unless you have changed some configuration. If you haven't changed any configuration and still not seeing the log you can pass the log configuration file during command.

filename: log_config.yml

{
    "version": 1,
    "disable_existing_loggers": false,
    "formatters": {
        "verbose": {
            "format": "%(asctime)s - %(name)s - %(levelname)s - %(funcName)s:%(lineno)d - %(message)s"
        }
    },
    "handlers": {
        "uvicorn": {
            "class": "logging.handlers.TimedRotatingFileHandler",
            "level": "DEBUG",
            "formatter": "verbose",
            "when": "D",
            "backupCount": 0,
            "filename": "uvicorn.log"
        }
    },
    "loggers": {
        "uvicorn": {
            "level": "DEBUG",
            "handlers": ["uvicorn"],
            "propagate": true,
            "qualname": "uvicorn"
        }
    }
}

command: uvicorn api.main:app --reload --log-config=log_config.yml After this you will see the logs in uvicorn.log file. Note:You may need to create uvicorn.log file beforehand