Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Missing execution stack and output for handled errors #3646

Closed
armenzg opened this issue Oct 11, 2024 · 0 comments · Fixed by #3673
Closed

Missing execution stack and output for handled errors #3646

armenzg opened this issue Oct 11, 2024 · 0 comments · Fixed by #3673
Labels
Component: SDK Core Dealing with the core of the SDK

Comments

@armenzg
Copy link
Member

armenzg commented Oct 11, 2024

When capturing errors, the Sentry stack traces only contain the frames from when an error happens. It does not contain any frames from the beginning of the execution.

This screenshot shows that only lines 25 and 17 are tracked (see [1] for full code; link to event). Lines 11 and 29 are missing:
Image

You can also notice that all breadcrumbs are missing [2].

You can check how I hacked a script [3] to give those extra missing frames by using traceback.extract_stack(); if you're curious.
link to event
Image

[1]

import os
import traceback

import sentry_sdk
from sentry_sdk import capture_exception

sentry_sdk.init(dsn=os.environ.get("SENTRY_DSN"))


def main():
    foo()  # line 11


def foo():
    try:
        print("Message before exception")
        bar()  # line 17
    except Exception:
        print("Message after capturing exception")
        traceback.print_exc()
        capture_exception()


def bar():
    raise Exception("This is a test exception")  # line 25


if __name__ == "__main__":
    main()  # line 29

[2] Output

Message before exception
Message after capturing exception
Traceback (most recent call last):
  File "/Users/armenzg/code/learning/scripts/foo.py", line 16, in foo
    bar()
  File "/Users/armenzg/code/learning/scripts/foo.py", line 23, in bar
    raise Exception("This is a test exception")
Exception: This is a test exception

[3]

import os
import sys
import traceback

import sentry_sdk
from sentry_sdk import capture_exception

# For Python 3.11+
if sys.version_info >= (3, 11):
    from builtins import ExceptionGroup
else:
    # For Python versions before 3.11
    from exceptiongroup import ExceptionGroup

sentry_sdk.init(dsn=os.environ.get("SENTRY_DSN"))


class CustomException(Exception):
    def __init__(self, message, tb_frames):
        super().__init__(message)
        self.tb_frames = tb_frames

    def __str__(self):
        frames = []
        for f in self.tb_frames[:-1]:
            # File "sentry_capture_exception.py", line 34, in foo
            line1 = f'  File "{f[0]}", line {f[1]}, in {f[2]}'
            line2 = f"    {f[3]}"
            frames.append("\n".join([line1, line2]))
        tb_str = "\n".join(frames)
        # Sample:
        # Exception: This is a test exception
        #   File "sentry_capture_exception.py", line 40, in foo
        #     bar()
        #   File "sentry_capture_exception.py", line 58, in bar
        #     raise Exception("This is a test exception")
        return f"{self.__class__.__name__}: foo\n{tb_str}"


def main():
    foo()


def foo():
    try:
        bar()
    except Exception as original_error:
        stack_trace = traceback.extract_stack()
        stack_exception = CustomException("An error occurred", stack_trace)

        # Create an ExceptionGroup with the original error and traceback exception
        exception_group = ExceptionGroup(
            "Error occurred in foo()", [original_error, stack_exception]
        )

        # Capture the ExceptionGroup
        capture_exception(exception_group)


def bar():
    raise Exception("This is a test exception")


if __name__ == "__main__":
    main()
@antonpirker antonpirker added Enhancement Component: SDK Core Dealing with the core of the SDK labels Oct 17, 2024
antonpirker added a commit that referenced this issue Dec 5, 2024
Add a new `init()` option `add_full_stack` (default `False`), when set to `True` it will add all the missing frames from the beginning of the execution to the stack trace sent to Sentry. 

Also adds another option `max_stack_frames` (default `100`) to limit the number of frames sent. The limitation is only enforced when `add_full_stack=True` to not change behavior for existing users. 

Fixes #3646
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Component: SDK Core Dealing with the core of the SDK
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants