简体   繁体   中英

FastApi : traceback.exc_format return none when using add_exception_handler

I develop with FastApi, and want to contain traceback info in response when error occur;
To do so, I define exception handlers in exception_handler.py :

from fastapi.responses import JSONResponse
from fastapi import status
from fastapi import FastAPI, Request
from traceback import format_exc, print_exc


def general_exception_handler(req: Request, exc: Exception):
    '''
    Exception handler for unspecified exceptions 
    '''
    
    tracback_msg = format_exc() 
    return JSONResponse(
        {
            "code": status.HTTP_500_INTERNAL_SERVER_ERROR,
            "message": f"error info: {tracback_msg}",
            # "message": f"error info: {str(exc)}",
            "data": "",
        },
        status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
    )

And attach those handler to fastappi app instance in server.py :

server.py is where I create app instance and attach extra function to it like middlewares or exception handlers.

from core import router # api routers are defined in router.py
from fastapi import FastAPI
from core.exception_handler import general_exception_handler


app = FastAPI(
    debug=False,
    docs_url=None,
    redoc_url=None
)


# attach exception handler to app instance
app.add_exception_handler(Exception, general_exception_handler)

# include routers to app intance
app.include_router(router.router)

The problem is, when exception was raised, traceback message return by format_exc() is None ;
But when I used str(exc) like the annotated code, I got the exception info properly but of course without traceback info.

It will not work because the exception handler receives the exception as parameter instead of catching the exception itself, meaning that there is no stacktrace in this case.

If you want to have the stacktrace, you should create a middleware or a custom API router that will actually capture the exception and return the message the way you want. I usually prefer to use a custom API Route instead of using middleware because it is more explicit and gives you more flexibility.

You can write something like this

class MyRoute(APIRoute):
    def get_route_handler(self) -> Callable:
        original_route_handler = super().get_route_handler()

        async def custom_route_handler(request: Request) -> Response:
            try:
                return await original_route_handler(request)
            except Exception as exc:
                tracback_msg = format_exc()
                # your return goes here

        return custom_route_handler

Then you override the default route handler from fastapi

app = FastAPI()
app.router.route_class = MyRoute

It should give you want you want

There's always format_exception , which takes an explicit exception argument, rather than grabbing the current one from sys.exc_info() .

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM