Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
31 changes: 29 additions & 2 deletions src/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,13 @@

import sentry_sdk
from fastapi import FastAPI, HTTPException, Request
from fastapi.exception_handlers import http_exception_handler
from fastapi.openapi.utils import get_openapi
from fastapi.responses import JSONResponse
from fastapi.staticfiles import StaticFiles
from sentry_sdk.integrations.fastapi import FastApiIntegration
from sentry_sdk.integrations.logging import LoggingIntegration
from starlette.exceptions import HTTPException as StarletteHTTPException
from starlette.middleware.sessions import SessionMiddleware

from src.config import settings
Expand Down Expand Up @@ -62,18 +64,43 @@
)


@app.exception_handler(StarletteHTTPException)
async def log_http_exception(request: Request, exc: StarletteHTTPException):
sentry_sdk.capture_exception(exc)
app_logger.error(
"HTTPException %s on %s %s: %s",
exc.status_code,
request.method,
request.url.path,
exc.detail,
exc_info=(type(exc), exc, exc.__traceback__),
)
return await http_exception_handler(request, exc)


@app.exception_handler(Exception)
async def global_exception_handler(request: Request, exc: Exception):
if isinstance(exc, HTTPException):
sentry_sdk.capture_exception(exc)
app_logger.error(
f"HTTPException {exc.status_code}: {exc.detail}", exc_info=True
"HTTPException %s on %s %s: %s",
exc.status_code,
request.method,
request.url.path,
exc.detail,
exc_info=(type(exc), exc, exc.__traceback__),
)
raise exc
else:
# Non-HTTPException errors
sentry_sdk.capture_exception(exc)
app_logger.error(f"Unexpected exception caught: {exc}", exc_info=True)
app_logger.error(
"Unexpected exception on %s %s: %s",
request.method,
request.url.path,
exc,
exc_info=True,
)
return JSONResponse(
status_code=500, content={"detail": "Internal server error"}
)
Expand Down
35 changes: 35 additions & 0 deletions src/tests/unit/test_logging.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import logging

import pytest
from fastapi import HTTPException
from starlette.requests import Request

from src.main import log_http_exception


@pytest.mark.asyncio
async def test_http_exception_logs_detail(caplog):
request = Request(
{
"type": "http",
"method": "GET",
"path": "/resource-server/groups/",
"headers": [],
"query_string": b"",
"server": ("testserver", 80),
"scheme": "http",
"client": ("testclient", 50000),
}
)
exception = HTTPException(
status_code=401,
detail="Token does not contain 'sub' claim",
headers={"WWW-Authenticate": "Bearer"},
)

with caplog.at_level(logging.ERROR, logger="src"):
response = await log_http_exception(request, exception)

assert response.status_code == 401
assert "HTTPException 401 on GET /resource-server/groups/" in caplog.text
assert "Token does not contain 'sub' claim" in caplog.text
Loading