From 15367e953c5145a4e216af749bb63e3854c2db56 Mon Sep 17 00:00:00 2001 From: sali72 Date: Wed, 11 Dec 2024 17:59:01 +0330 Subject: [PATCH] feat: implement a better logging system for exceptions --- commons/exception_handlers.py | 38 +++++++++++++++++++++++++++++++++-- commons/logging_config.py | 7 +++++++ database/database.py | 4 +++- 3 files changed, 46 insertions(+), 3 deletions(-) create mode 100644 commons/logging_config.py diff --git a/commons/exception_handlers.py b/commons/exception_handlers.py index 68f6d67..77e2366 100644 --- a/commons/exception_handlers.py +++ b/commons/exception_handlers.py @@ -1,5 +1,13 @@ -from fastapi.responses import JSONResponse +import logging +import traceback + from fastapi import HTTPException +from fastapi.responses import JSONResponse +from commons.logging_config import setup_logging + +setup_logging() +logger = logging.getLogger(__name__) + exception_status_map = { # Built-in Python exception @@ -13,17 +21,42 @@ "InvalidId": 400, } + def get_exception_name(exc: Exception) -> str: """Get the name of the exception.""" return type(exc).__name__ + def get_status_code(exception_name: str) -> int: """Get the status code based on the exception name.""" return exception_status_map.get(exception_name, 500) + +def extract_traceback_info(exc: Exception): + """Extract file name and line number from the exception traceback.""" + tb = traceback.extract_tb(exc.__traceback__) + if tb: + last_trace = tb[-1] + return last_trace.filename, last_trace.lineno + return "Unknown", "Unknown" + + +def log_exception(exc: Exception, file_name: str, line_number: int): + """Log the full exception information.""" + logging.error( + "Exception occurred: %s\nFile: %s, Line: %d\nTraceback: %s", + str(exc), + file_name, + line_number, + "".join(traceback.format_exception(type(exc), exc, exc.__traceback__)), + ) + + async def base_exception_handler(request, exc: Exception): exception_name = get_exception_name(exc) status_code = get_status_code(exception_name) + file_name, line_number = extract_traceback_info(exc) + log_exception(exc, file_name, line_number) return JSONResponse( status_code=status_code, @@ -33,6 +66,7 @@ async def base_exception_handler(request, exc: Exception): }, ) + async def http_exception_handler(request, exc: HTTPException): return JSONResponse( status_code=exc.status_code, @@ -40,4 +74,4 @@ async def http_exception_handler(request, exc: HTTPException): "exception_name": "HTTPException", "detail": exc.detail, }, - ) \ No newline at end of file + ) diff --git a/commons/logging_config.py b/commons/logging_config.py new file mode 100644 index 0000000..e8a27ea --- /dev/null +++ b/commons/logging_config.py @@ -0,0 +1,7 @@ +import logging + +def setup_logging(): + logging.basicConfig( + level=logging.INFO, + format='%(asctime)s - %(levelname)s - %(message)s' + ) \ No newline at end of file diff --git a/database/database.py b/database/database.py index 71f3137..eac0c81 100644 --- a/database/database.py +++ b/database/database.py @@ -5,6 +5,7 @@ from dotenv import load_dotenv from mongoengine.connection import get_connection +from commons.logging_config import setup_logging from database.initialize_db import ( initialize_common_asset_types, initialize_common_categories, @@ -21,7 +22,8 @@ MONGO_ATLAS_CONNECTION_STRING = os.getenv("MONGO_ATLAS_CONNECTION_STRING") TEST_MODE = os.getenv("TEST_MODE") -logging.basicConfig(level=logging.INFO) + +setup_logging() logger = logging.getLogger(__name__)