diff --git a/posthog/exception_capture.py b/posthog/exception_capture.py index ef08bc98..71c21132 100644 --- a/posthog/exception_capture.py +++ b/posthog/exception_capture.py @@ -9,6 +9,8 @@ from enum import Enum from typing import TYPE_CHECKING, List, Optional +from posthog.synthetic_exception import SyntheticException + if TYPE_CHECKING: from posthog.client import Client @@ -50,18 +52,23 @@ def close(self): def exception_handler(self, exc_type, exc_value, exc_traceback): # don't affect default behaviour. - self.capture_exception((exc_type, exc_value, exc_traceback)) + synthetic_exc = SyntheticException(exc_type, exc_value, exc_traceback) + self.capture_exception(synthetic_exc) self.original_excepthook(exc_type, exc_value, exc_traceback) def thread_exception_handler(self, args): - self.capture_exception((args.exc_type, args.exc_value, args.exc_traceback)) + synthetic_exc = SyntheticException( + args.exc_type, args.exc_value, args.exc_traceback + ) + self.capture_exception(synthetic_exc) def exception_receiver(self, exc_info, extra_properties): if "distinct_id" in extra_properties: metadata = {"distinct_id": extra_properties["distinct_id"]} else: metadata = None - self.capture_exception((exc_info[0], exc_info[1], exc_info[2]), metadata) + synthetic_exc = SyntheticException(exc_info[0], exc_info[1], exc_info[2]) + self.capture_exception(synthetic_exc, metadata) def capture_exception(self, exception, metadata=None): try: diff --git a/posthog/exception_utils.py b/posthog/exception_utils.py index 23ee483f..caab6ead 100644 --- a/posthog/exception_utils.py +++ b/posthog/exception_utils.py @@ -19,6 +19,8 @@ # Python 3.10 and below BaseExceptionGroup = None # type: ignore +from posthog.synthetic_exception import SyntheticException + DEFAULT_MAX_VALUE_LENGTH = 1024 @@ -797,6 +799,10 @@ def exc_info_from_error(error): # type: (Union[BaseException, ExcInfo]) -> ExcInfo if isinstance(error, tuple) and len(error) == 3: exc_type, exc_value, tb = error + elif isinstance(error, SyntheticException): + exc_type = error.exc_type + exc_value = error.exc_value + tb = error.exc_traceback elif isinstance(error, BaseException): tb = getattr(error, "__traceback__", None) if tb is not None: diff --git a/posthog/synthetic_exception.py b/posthog/synthetic_exception.py new file mode 100644 index 00000000..a4154dab --- /dev/null +++ b/posthog/synthetic_exception.py @@ -0,0 +1,14 @@ +class SyntheticException(BaseException): + """A synthetic exception that wraps exc_info tuples for proper exception handling.""" + + def __init__(self, exc_type, exc_value, exc_traceback): + self.exc_type = exc_type + self.exc_value = exc_value + self.exc_traceback = exc_traceback + self.__traceback__ = exc_traceback + + # Set the exception message + if exc_value: + super().__init__(str(exc_value)) + else: + super().__init__(f"{exc_type.__name__}")