clan-app: full context tracebacks
If an exception now is thrown in one of the middlewares we will get a proper traceback instead of a cut off one like before
This commit is contained in:
@@ -5,7 +5,7 @@ from clan_lib.api import MethodRegistry, from_dict
|
||||
|
||||
from clan_app.api.api_bridge import BackendRequest
|
||||
|
||||
from .base import Middleware, MiddlewareContext
|
||||
from .base import Middleware, MiddlewareContext, MiddlewareError
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
@@ -27,7 +27,6 @@ class ArgumentParsingMiddleware(Middleware):
|
||||
reconciled_arguments[k] = from_dict(arg_class, v)
|
||||
|
||||
# Create a new request with reconciled arguments
|
||||
|
||||
updated_request = BackendRequest(
|
||||
method_name=context.request.method_name,
|
||||
args=reconciled_arguments,
|
||||
@@ -37,12 +36,12 @@ class ArgumentParsingMiddleware(Middleware):
|
||||
context.request = updated_request
|
||||
|
||||
except Exception as e:
|
||||
log.exception(
|
||||
f"Error while parsing arguments for {context.request.method_name}",
|
||||
# Create enhanced exception with original calling context
|
||||
enhanced_error = MiddlewareError(
|
||||
f"Error in method '{context.request.method_name}'",
|
||||
context.original_traceback,
|
||||
e,
|
||||
)
|
||||
context.bridge.send_api_error_response(
|
||||
context.request.op_key or "unknown",
|
||||
str(e),
|
||||
["argument_parsing", context.request.method_name],
|
||||
)
|
||||
raise
|
||||
|
||||
# Chain the exceptions to preserve both tracebacks
|
||||
raise enhanced_error from e
|
||||
|
||||
@@ -12,6 +12,25 @@ class MiddlewareContext:
|
||||
request: "BackendRequest"
|
||||
bridge: "ApiBridge"
|
||||
exit_stack: ExitStack
|
||||
original_traceback: list[str]
|
||||
|
||||
|
||||
class MiddlewareError(Exception):
|
||||
"""Exception that preserves original calling context."""
|
||||
|
||||
def __init__(
|
||||
self, message: str, original_frames: list[str], original_error: Exception
|
||||
) -> None:
|
||||
# Store just the original error message for API responses
|
||||
super().__init__(str(original_error))
|
||||
self.method_message = message
|
||||
self.original_frames = original_frames
|
||||
self.original_error = original_error
|
||||
|
||||
def __str__(self) -> str:
|
||||
# For traceback display, show in proper Python traceback order (oldest to newest)
|
||||
original_context = "".join(self.original_frames)
|
||||
return f"Traceback (most recent call last):\n{original_context.rstrip()}\nMethodExecutionError: {self.original_error}"
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
|
||||
@@ -8,7 +8,7 @@ from clan_lib.async_run import AsyncContext, get_async_ctx, set_async_ctx
|
||||
from clan_lib.custom_logger import RegisteredHandler, setup_logging
|
||||
from clan_lib.log_manager import LogManager
|
||||
|
||||
from .base import Middleware, MiddlewareContext
|
||||
from .base import Middleware, MiddlewareContext, MiddlewareError
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
@@ -43,15 +43,15 @@ class LoggingMiddleware(Middleware):
|
||||
).get_file_path()
|
||||
|
||||
except Exception as e:
|
||||
log.exception(
|
||||
f"Error while handling request header of {context.request.method_name}",
|
||||
# Create enhanced exception with original calling context
|
||||
enhanced_error = MiddlewareError(
|
||||
f"Error in method '{context.request.method_name}'",
|
||||
context.original_traceback,
|
||||
e,
|
||||
)
|
||||
context.bridge.send_api_error_response(
|
||||
context.request.op_key or "unknown",
|
||||
str(e),
|
||||
["header_middleware", context.request.method_name],
|
||||
)
|
||||
return
|
||||
|
||||
# Chain the exceptions to preserve both tracebacks
|
||||
raise enhanced_error from e
|
||||
|
||||
# Register logging context manager
|
||||
class LoggingContextManager:
|
||||
|
||||
@@ -5,7 +5,7 @@ from clan_lib.api import MethodRegistry
|
||||
|
||||
from clan_app.api.api_bridge import BackendResponse
|
||||
|
||||
from .base import Middleware, MiddlewareContext
|
||||
from .base import Middleware, MiddlewareContext, MiddlewareError
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
@@ -31,11 +31,12 @@ class MethodExecutionMiddleware(Middleware):
|
||||
context.bridge.send_api_response(response)
|
||||
|
||||
except Exception as e:
|
||||
log.exception(
|
||||
f"Error while handling result of {context.request.method_name}",
|
||||
)
|
||||
context.bridge.send_api_error_response(
|
||||
context.request.op_key or "unknown",
|
||||
str(e),
|
||||
["method_execution", context.request.method_name],
|
||||
# Create enhanced exception with original calling context
|
||||
enhanced_error = MiddlewareError(
|
||||
f"Error in method '{context.request.method_name}'",
|
||||
context.original_traceback,
|
||||
e,
|
||||
)
|
||||
|
||||
# Chain the exceptions to preserve both tracebacks
|
||||
raise enhanced_error from e
|
||||
|
||||
Reference in New Issue
Block a user