Skip to content

Commit 9277a38

Browse files
fynnosbigabig
authored andcommitted
improve generic endpoint exception handler
1 parent 31cd550 commit 9277a38

File tree

2 files changed

+43
-19
lines changed

2 files changed

+43
-19
lines changed

backend/src/common/exception_handler.py

Lines changed: 33 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,45 @@
1+
import traceback
2+
from collections.abc import Callable
3+
14
from fastapi import Request
25
from fastapi.responses import PlainTextResponse
36
from loguru import logger
47

58
exception_handlers = []
69

710

8-
def exception_handler(http_status_code: int):
11+
def exception_handler(
12+
http_status_code: int | Callable[[Exception], int],
13+
extract_message: Callable[[Exception], str] = lambda exc: str(exc),
14+
):
915
def decorator(exception_class):
1016
def handle_exception(req: Request, exc: Exception):
11-
logger.exception(exc)
12-
return PlainTextResponse(str(exc), status_code=http_status_code)
17+
*_, (frame, lineno) = traceback.walk_tb(exc.__traceback__)
18+
19+
# start traceback at our code by skipping any library code (starlette etc.)
20+
tb = exc.__traceback__
21+
while tb is not None and "site-packages" in tb.tb_frame.f_code.co_filename:
22+
tb = tb.tb_next
23+
24+
# override line, function name, module etc. because loguru would
25+
# otherwise use the current file location, function name etc.
26+
logger.patch(
27+
lambda record: record.update(
28+
line=lineno, # type: ignore
29+
function=frame.f_code.co_name,
30+
module=frame.f_globals["__name__"].split(".")[-1],
31+
name=frame.f_globals["__name__"],
32+
)
33+
).opt(exception=(type(exc), exc, tb)).error(extract_message(exc))
34+
35+
if isinstance(http_status_code, int):
36+
status_code = http_status_code
37+
elif isinstance(http_status_code, Callable):
38+
status_code = http_status_code(exc)
39+
else:
40+
status_code = 500 # type: ignore
41+
42+
return PlainTextResponse(extract_message(exc), status_code)
1343

1444
exception_handlers.append((exception_class, handle_exception))
1545
return exception_class

backend/src/main.py

Lines changed: 10 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -8,15 +8,14 @@
88
from fastapi.middleware.cors import CORSMiddleware
99
from fastapi.middleware.gzip import GZipMiddleware
1010
from fastapi.openapi.utils import get_openapi
11-
from fastapi.responses import PlainTextResponse
1211
from fastapi.routing import APIRoute
1312
from loguru import logger
1413
from psycopg2.errors import UniqueViolation
1514
from sqlalchemy.exc import IntegrityError
1615
from starlette.middleware.sessions import SessionMiddleware
1716
from uvicorn.main import run
1817

19-
from common.exception_handler import exception_handlers
18+
from common.exception_handler import exception_handler, exception_handlers
2019
from repos.elastic.elastic_repo import ElasticSearchRepo
2120
from repos.llm_repo import LLMRepo
2221
from utils.import_utils import import_by_suffix
@@ -118,21 +117,16 @@ def custom_openapi():
118117
app.include_router(em.router)
119118

120119

121-
@app.exception_handler(IntegrityError)
122-
async def integrity_error_handler(_, exc: IntegrityError):
123-
logger.exception(exc)
124-
if isinstance(exc.orig, UniqueViolation):
125-
msg = str(exc.orig.pgerror).split("\n")[1]
126-
return PlainTextResponse(msg, status_code=409)
127-
else:
128-
return PlainTextResponse(str(exc), status_code=500)
129-
130-
131-
@app.exception_handler(NoSuchJobError)
132-
async def no_such_job_error_handler(_, exc: NoSuchJobError):
133-
logger.exception(exc)
134-
return PlainTextResponse(str(exc), status_code=404)
120+
exception_handler(
121+
http_status_code=lambda exc: 409
122+
if isinstance(exc, IntegrityError) and isinstance(exc.orig, UniqueViolation)
123+
else 500,
124+
extract_message=lambda exc: str(exc.orig.pgerror).split("\n")[1]
125+
if isinstance(exc, IntegrityError) and isinstance(exc.orig, UniqueViolation)
126+
else str(exc),
127+
)(IntegrityError)
135128

129+
exception_handler(404)(NoSuchJobError)
136130

137131
# register all exception handlers in fastAPI
138132
for ex_class, handler_func in exception_handlers:

0 commit comments

Comments
 (0)