From f5aa183343c9ef58263563d83fea7d9bd0ae9397 Mon Sep 17 00:00:00 2001 From: Alex Hall Date: Sun, 28 Jun 2020 19:23:03 +0200 Subject: [PATCH 1/9] Use executing to infer code qualname --- sentry_sdk/utils.py | 15 ++++++++++++++- test-requirements.txt | 1 + tests/test_client.py | 5 ++++- 3 files changed, 19 insertions(+), 2 deletions(-) diff --git a/sentry_sdk/utils.py b/sentry_sdk/utils.py index 548796399c..36ee9ecacc 100644 --- a/sentry_sdk/utils.py +++ b/sentry_sdk/utils.py @@ -28,6 +28,12 @@ from sentry_sdk._types import ExcInfo, EndpointType +try: + import executing +except ImportError: + executing = None + + epoch = datetime(1970, 1, 1) @@ -430,6 +436,13 @@ def filename_for_module(module, abs_path): return abs_path +def function_name(frame): + if executing: + return executing.Source.for_frame(frame).code_qualname(frame.f_code) + else: + return frame.f_code.co_name + + def serialize_frame(frame, tb_lineno=None, with_locals=True): # type: (FrameType, Optional[int], bool) -> Dict[str, Any] f_code = getattr(frame, "f_code", None) @@ -438,7 +451,7 @@ def serialize_frame(frame, tb_lineno=None, with_locals=True): function = None else: abs_path = frame.f_code.co_filename - function = frame.f_code.co_name + function = function_name(frame) try: module = frame.f_globals["__name__"] except Exception: diff --git a/test-requirements.txt b/test-requirements.txt index be051169ad..5a2e527154 100644 --- a/test-requirements.txt +++ b/test-requirements.txt @@ -7,3 +7,4 @@ pytest-cov==2.8.1 gevent eventlet newrelic +executing diff --git a/tests/test_client.py b/tests/test_client.py index 5b432fb03b..4968110cc6 100644 --- a/tests/test_client.py +++ b/tests/test_client.py @@ -224,7 +224,10 @@ def bar(): (event,) = events (thread,) = event["threads"]["values"] functions = [x["function"] for x in thread["stacktrace"]["frames"]] - assert functions[-2:] == ["foo", "bar"] + assert functions[-2:] == [ + "test_attach_stacktrace_enabled..foo", + "test_attach_stacktrace_enabled..bar", + ] def test_attach_stacktrace_enabled_no_locals(): From af3d631eb2be90b81f1b03251a9ce84758d5f872 Mon Sep 17 00:00:00 2001 From: Alex Hall Date: Sun, 28 Jun 2020 22:18:18 +0200 Subject: [PATCH 2/9] Fix function names for django templates --- sentry_sdk/integrations/django/__init__.py | 2 +- tests/integrations/django/test_basic.py | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/sentry_sdk/integrations/django/__init__.py b/sentry_sdk/integrations/django/__init__.py index 3c14a314c5..522efd71f9 100644 --- a/sentry_sdk/integrations/django/__init__.py +++ b/sentry_sdk/integrations/django/__init__.py @@ -157,7 +157,7 @@ def process_django_templates(event, hint): for i in reversed(range(len(frames))): f = frames[i] if ( - f.get("function") in ("parse", "render") + f.get("function") in ("Parser.parse", "render") and f.get("module") == "django.template.base" ): i += 1 diff --git a/tests/integrations/django/test_basic.py b/tests/integrations/django/test_basic.py index 3c26b426f5..554b0ad391 100644 --- a/tests/integrations/django/test_basic.py +++ b/tests/integrations/django/test_basic.py @@ -438,9 +438,9 @@ def test_template_exception(sentry_init, client, capture_events): (f.get("function"), f.get("module")) for f in exception["stacktrace"]["frames"] ] assert filenames[-3:] == [ - (u"parse", u"django.template.base"), + (u"Parser.parse", u"django.template.base"), (None, None), - (u"invalid_block_tag", u"django.template.base"), + (u"Parser.invalid_block_tag", u"django.template.base"), ] From c353254d213b44f2f7966c05933653bcc2ef609a Mon Sep 17 00:00:00 2001 From: Alex Hall Date: Sun, 5 Jul 2020 15:51:17 +0200 Subject: [PATCH 3/9] Test with and without executing --- sentry_sdk/integrations/django/__init__.py | 2 +- test-requirements.txt | 1 - tests/integrations/django/test_basic.py | 19 ++++++++++++++----- tests/test_client.py | 14 +++++++++----- tox.ini | 6 +++++- 5 files changed, 29 insertions(+), 13 deletions(-) diff --git a/sentry_sdk/integrations/django/__init__.py b/sentry_sdk/integrations/django/__init__.py index 522efd71f9..dfdde1ce80 100644 --- a/sentry_sdk/integrations/django/__init__.py +++ b/sentry_sdk/integrations/django/__init__.py @@ -157,7 +157,7 @@ def process_django_templates(event, hint): for i in reversed(range(len(frames))): f = frames[i] if ( - f.get("function") in ("Parser.parse", "render") + f.get("function") in ("Parser.parse", "parse", "render") and f.get("module") == "django.template.base" ): i += 1 diff --git a/test-requirements.txt b/test-requirements.txt index 5a2e527154..be051169ad 100644 --- a/test-requirements.txt +++ b/test-requirements.txt @@ -7,4 +7,3 @@ pytest-cov==2.8.1 gevent eventlet newrelic -executing diff --git a/tests/integrations/django/test_basic.py b/tests/integrations/django/test_basic.py index 554b0ad391..66d4ab4bf9 100644 --- a/tests/integrations/django/test_basic.py +++ b/tests/integrations/django/test_basic.py @@ -17,6 +17,7 @@ from sentry_sdk import capture_message, capture_exception from sentry_sdk.integrations.django import DjangoIntegration +from sentry_sdk.utils import executing from tests.integrations.django.myapp.wsgi import application @@ -437,11 +438,19 @@ def test_template_exception(sentry_init, client, capture_events): filenames = [ (f.get("function"), f.get("module")) for f in exception["stacktrace"]["frames"] ] - assert filenames[-3:] == [ - (u"Parser.parse", u"django.template.base"), - (None, None), - (u"Parser.invalid_block_tag", u"django.template.base"), - ] + + if executing: + assert filenames[-3:] == [ + (u"Parser.parse", u"django.template.base"), + (None, None), + (u"Parser.invalid_block_tag", u"django.template.base"), + ] + else: + assert filenames[-3:] == [ + (u"parse", u"django.template.base"), + (None, None), + (u"invalid_block_tag", u"django.template.base"), + ] @pytest.mark.parametrize( diff --git a/tests/test_client.py b/tests/test_client.py index 4968110cc6..f0f4083e36 100644 --- a/tests/test_client.py +++ b/tests/test_client.py @@ -10,7 +10,7 @@ from sentry_sdk import Hub, Client, configure_scope, capture_message, capture_exception from sentry_sdk.transport import Transport from sentry_sdk._compat import reraise, text_type, PY2 -from sentry_sdk.utils import HAS_CHAINED_EXCEPTIONS +from sentry_sdk.utils import HAS_CHAINED_EXCEPTIONS, executing if PY2: # Importing ABCs from collections is deprecated, and will stop working in 3.8 @@ -224,10 +224,14 @@ def bar(): (event,) = events (thread,) = event["threads"]["values"] functions = [x["function"] for x in thread["stacktrace"]["frames"]] - assert functions[-2:] == [ - "test_attach_stacktrace_enabled..foo", - "test_attach_stacktrace_enabled..bar", - ] + + if executing: + assert functions[-2:] == [ + "test_attach_stacktrace_enabled..foo", + "test_attach_stacktrace_enabled..bar", + ] + else: + assert functions[-2:] == ["foo", "bar"] def test_attach_stacktrace_enabled_no_locals(): diff --git a/tox.ini b/tox.ini index 8e3989499e..9d48520fd1 100644 --- a/tox.ini +++ b/tox.ini @@ -20,7 +20,9 @@ envlist = # {py2.7}-django-{1.11} # {py2.7,py3.7}-django-{1.11,2.2} - {pypy,py2.7}-django-{1.6,1.7} + py{2.7,3.4,3.5,3.6,3.7,3.8,py}-executing + + {pypy,py2.7}-django-{1.6,1.7}{-executing,} {pypy,py2.7,py3.5}-django-{1.8,1.9,1.10,1.11} {py3.5,py3.6,py3.7}-django-{2.0,2.1} {py3.7,py3.8}-django-{2.2,3.0,dev} @@ -183,6 +185,8 @@ deps = py3.8: hypothesis + executing: executing + setenv = PYTHONDONTWRITEBYTECODE=1 TESTPATH=tests From 8e41d4d52365ef4895bb9adffc1109af140e5aea Mon Sep 17 00:00:00 2001 From: Alex Hall Date: Sun, 5 Jul 2020 18:28:30 +0200 Subject: [PATCH 4/9] Make mypy happy --- mypy.ini | 2 ++ sentry_sdk/utils.py | 1 + 2 files changed, 3 insertions(+) diff --git a/mypy.ini b/mypy.ini index a16903768b..1b5abb4ff7 100644 --- a/mypy.ini +++ b/mypy.ini @@ -48,3 +48,5 @@ ignore_missing_imports = True ignore_missing_imports = True [mypy-asgiref.*] ignore_missing_imports = True +[mypy-executing.*] +ignore_missing_imports = True diff --git a/sentry_sdk/utils.py b/sentry_sdk/utils.py index 36ee9ecacc..74830068ad 100644 --- a/sentry_sdk/utils.py +++ b/sentry_sdk/utils.py @@ -437,6 +437,7 @@ def filename_for_module(module, abs_path): def function_name(frame): + # type: (FrameType) -> str if executing: return executing.Source.for_frame(frame).code_qualname(frame.f_code) else: From 9ce61e578dd79e7131f31ef2c682eed9bcf6be6a Mon Sep 17 00:00:00 2001 From: Alex Hall Date: Fri, 10 Jul 2020 22:24:55 +0200 Subject: [PATCH 5/9] Use sentry_init fixture in tests instead of using Hub directly --- tests/conftest.py | 7 +++-- tests/test_client.py | 73 +++++++++++++++++++++++--------------------- 2 files changed, 43 insertions(+), 37 deletions(-) diff --git a/tests/conftest.py b/tests/conftest.py index 0e3102fb60..e8c63708c3 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -182,11 +182,12 @@ def inner(event): @pytest.fixture def sentry_init(monkeypatch_test_transport, request): - def inner(*a, **kw): + def inner(*a, transport=None, **kw): hub = sentry_sdk.Hub.current - client = sentry_sdk.Client(*a, **kw) + client = sentry_sdk.Client(*a, transport=transport, **kw) hub.bind_client(client) - monkeypatch_test_transport(sentry_sdk.Hub.current.client) + if transport is None: + monkeypatch_test_transport(sentry_sdk.Hub.current.client) if request.node.get_closest_marker("forked"): # Do not run isolation if the test is already running in diff --git a/tests/test_client.py b/tests/test_client.py index 5b432fb03b..a1c6b90a24 100644 --- a/tests/test_client.py +++ b/tests/test_client.py @@ -7,7 +7,14 @@ import time from textwrap import dedent -from sentry_sdk import Hub, Client, configure_scope, capture_message, capture_exception +from sentry_sdk import ( + Hub, + Client, + configure_scope, + capture_message, + capture_exception, + capture_event, +) from sentry_sdk.transport import Transport from sentry_sdk._compat import reraise, text_type, PY2 from sentry_sdk.utils import HAS_CHAINED_EXCEPTIONS @@ -149,41 +156,41 @@ def test_proxy_httpsselect_bothenv_http(monkeypatch): assert client.transport._pool.proxy.scheme == "http" -def test_simple_transport(): +def test_simple_transport(sentry_init): events = [] - with Hub(Client(transport=events.append)): - capture_message("Hello World!") + sentry_init(transport=events.append) + capture_message("Hello World!") assert events[0]["message"] == "Hello World!" -def test_ignore_errors(): +def test_ignore_errors(sentry_init, capture_events): class MyDivisionError(ZeroDivisionError): pass def raise_it(exc_info): reraise(*exc_info) - hub = Hub(Client(ignore_errors=[ZeroDivisionError], transport=_TestTransport())) - hub._capture_internal_exception = raise_it + sentry_init(ignore_errors=[ZeroDivisionError], transport=_TestTransport()) + Hub.current._capture_internal_exception = raise_it def e(exc): try: raise exc except Exception: - hub.capture_exception() + capture_exception() e(ZeroDivisionError()) e(MyDivisionError()) pytest.raises(EventCaptured, lambda: e(ValueError())) -def test_with_locals_enabled(): - events = [] - hub = Hub(Client(with_locals=True, transport=events.append)) +def test_with_locals_enabled(sentry_init, capture_events): + sentry_init(with_locals=True) + events = capture_events() try: 1 / 0 except Exception: - hub.capture_exception() + capture_exception() (event,) = events @@ -193,13 +200,13 @@ def test_with_locals_enabled(): ) -def test_with_locals_disabled(): - events = [] - hub = Hub(Client(with_locals=False, transport=events.append)) +def test_with_locals_disabled(sentry_init, capture_events): + sentry_init(with_locals=False) + events = capture_events() try: 1 / 0 except Exception: - hub.capture_exception() + capture_exception() (event,) = events @@ -209,15 +216,15 @@ def test_with_locals_disabled(): ) -def test_attach_stacktrace_enabled(): - events = [] - hub = Hub(Client(attach_stacktrace=True, transport=events.append)) +def test_attach_stacktrace_enabled(sentry_init, capture_events): + sentry_init(attach_stacktrace=True) + events = capture_events() def foo(): bar() def bar(): - hub.capture_message("HI") + capture_message("HI") foo() @@ -227,17 +234,15 @@ def bar(): assert functions[-2:] == ["foo", "bar"] -def test_attach_stacktrace_enabled_no_locals(): - events = [] - hub = Hub( - Client(attach_stacktrace=True, with_locals=False, transport=events.append) - ) +def test_attach_stacktrace_enabled_no_locals(sentry_init, capture_events): + sentry_init(attach_stacktrace=True, with_locals=False) + events = capture_events() def foo(): bar() def bar(): - hub.capture_message("HI") + capture_message("HI") foo() @@ -262,19 +267,19 @@ def test_attach_stacktrace_in_app(sentry_init, capture_events): assert any(f["in_app"] for f in frames) -def test_attach_stacktrace_disabled(): - events = [] - hub = Hub(Client(attach_stacktrace=False, transport=events.append)) - hub.capture_message("HI") +def test_attach_stacktrace_disabled(sentry_init, capture_events): + sentry_init(attach_stacktrace=False) + events = capture_events() + capture_message("HI") (event,) = events assert "threads" not in event -def test_capture_event_works(): - c = Client(transport=_TestTransport()) - pytest.raises(EventCaptured, lambda: c.capture_event({})) - pytest.raises(EventCaptured, lambda: c.capture_event({})) +def test_capture_event_works(sentry_init): + sentry_init(transport=_TestTransport()) + pytest.raises(EventCaptured, lambda: capture_event({})) + pytest.raises(EventCaptured, lambda: capture_event({})) @pytest.mark.parametrize("num_messages", [10, 20]) From bad98899cc71948350ccb1f42818cb606e6bf2a7 Mon Sep 17 00:00:00 2001 From: Alex Hall Date: Fri, 10 Jul 2020 22:49:20 +0200 Subject: [PATCH 6/9] Fix transport keyword arg for Python 2 --- tests/conftest.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/conftest.py b/tests/conftest.py index e8c63708c3..4f540c54bb 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -182,11 +182,11 @@ def inner(event): @pytest.fixture def sentry_init(monkeypatch_test_transport, request): - def inner(*a, transport=None, **kw): + def inner(*a, **kw): hub = sentry_sdk.Hub.current - client = sentry_sdk.Client(*a, transport=transport, **kw) + client = sentry_sdk.Client(*a, **kw) hub.bind_client(client) - if transport is None: + if "transport" not in kw: monkeypatch_test_transport(sentry_sdk.Hub.current.client) if request.node.get_closest_marker("forked"): From 35d8476efd5ffd932c899d9eab30fa912319ec1a Mon Sep 17 00:00:00 2001 From: Alex Hall Date: Sat, 11 Jul 2020 22:57:32 +0200 Subject: [PATCH 7/9] Create optional ExecutingIntegration --- sentry_sdk/integrations/executing.py | 62 +++++++++++++++++++++++++ sentry_sdk/utils.py | 15 +----- test-requirements.txt | 1 + tests/integrations/django/test_basic.py | 11 +++-- tests/test_client.py | 40 ++++++++++++---- tox.ini | 6 +-- 6 files changed, 104 insertions(+), 31 deletions(-) create mode 100644 sentry_sdk/integrations/executing.py diff --git a/sentry_sdk/integrations/executing.py b/sentry_sdk/integrations/executing.py new file mode 100644 index 0000000000..a874810418 --- /dev/null +++ b/sentry_sdk/integrations/executing.py @@ -0,0 +1,62 @@ +from __future__ import absolute_import + +from sentry_sdk import Hub +from sentry_sdk._types import MYPY +from sentry_sdk.integrations import Integration, DidNotEnable +from sentry_sdk.scope import add_global_event_processor +from sentry_sdk.utils import walk_exception_chain, iter_stacks + +if MYPY: + from typing import Optional + + from sentry_sdk._types import Event, Hint + +try: + import executing +except ImportError: + raise DidNotEnable("executing is not installed") + + +class ExecutingIntegration(Integration): + identifier = "executing" + + @staticmethod + def setup_once(): + @add_global_event_processor + def add_executing_info(event, hint): + # type: (Event, Optional[Hint]) -> Optional[Event] + if Hub.current.get_integration(ExecutingIntegration) is None: + return event + + if hint is None: + return event + + exc_info = hint.get("exc_info", None) + + if exc_info is None: + return event + + exception = event.get("exception", None) + + if exception is None: + return event + + values = exception.get("values", None) + + if values is None: + return event + + for exception, (_exc_type, _exc_value, exc_tb) in zip( + reversed(values), walk_exception_chain(exc_info) + ): + sentry_frames = exception.get("stacktrace", {}).get("frames", []) + tbs = list(iter_stacks(exc_tb)) + if len(sentry_frames) != len(tbs): + continue + + for sentry_frame, tb in zip(sentry_frames, tbs): + frame = tb.tb_frame + source = executing.Source.for_frame(frame) + sentry_frame["function"] = source.code_qualname(frame.f_code) + + return event diff --git a/sentry_sdk/utils.py b/sentry_sdk/utils.py index 74830068ad..105fbaf8fa 100644 --- a/sentry_sdk/utils.py +++ b/sentry_sdk/utils.py @@ -28,11 +28,6 @@ from sentry_sdk._types import ExcInfo, EndpointType -try: - import executing -except ImportError: - executing = None - epoch = datetime(1970, 1, 1) @@ -436,14 +431,6 @@ def filename_for_module(module, abs_path): return abs_path -def function_name(frame): - # type: (FrameType) -> str - if executing: - return executing.Source.for_frame(frame).code_qualname(frame.f_code) - else: - return frame.f_code.co_name - - def serialize_frame(frame, tb_lineno=None, with_locals=True): # type: (FrameType, Optional[int], bool) -> Dict[str, Any] f_code = getattr(frame, "f_code", None) @@ -452,7 +439,7 @@ def serialize_frame(frame, tb_lineno=None, with_locals=True): function = None else: abs_path = frame.f_code.co_filename - function = function_name(frame) + function = frame.f_code.co_name try: module = frame.f_globals["__name__"] except Exception: diff --git a/test-requirements.txt b/test-requirements.txt index be051169ad..5a2e527154 100644 --- a/test-requirements.txt +++ b/test-requirements.txt @@ -7,3 +7,4 @@ pytest-cov==2.8.1 gevent eventlet newrelic +executing diff --git a/tests/integrations/django/test_basic.py b/tests/integrations/django/test_basic.py index 66d4ab4bf9..9830d2ae5f 100644 --- a/tests/integrations/django/test_basic.py +++ b/tests/integrations/django/test_basic.py @@ -9,6 +9,7 @@ from django.core.management import execute_from_command_line from django.db.utils import OperationalError, ProgrammingError, DataError +from sentry_sdk.integrations.executing import ExecutingIntegration try: from django.urls import reverse @@ -17,7 +18,6 @@ from sentry_sdk import capture_message, capture_exception from sentry_sdk.integrations.django import DjangoIntegration -from sentry_sdk.utils import executing from tests.integrations.django.myapp.wsgi import application @@ -409,8 +409,11 @@ def test_read_request(sentry_init, client, capture_events): assert "data" not in event["request"] -def test_template_exception(sentry_init, client, capture_events): - sentry_init(integrations=[DjangoIntegration()]) +@pytest.mark.parametrize("with_executing_integration", [[], [ExecutingIntegration()]]) +def test_template_exception( + sentry_init, client, capture_events, with_executing_integration +): + sentry_init(integrations=[DjangoIntegration()] + with_executing_integration) events = capture_events() content, status, headers = client.get(reverse("template_exc")) @@ -439,7 +442,7 @@ def test_template_exception(sentry_init, client, capture_events): (f.get("function"), f.get("module")) for f in exception["stacktrace"]["frames"] ] - if executing: + if with_executing_integration: assert filenames[-3:] == [ (u"Parser.parse", u"django.template.base"), (None, None), diff --git a/tests/test_client.py b/tests/test_client.py index af90286b44..d9a13157e4 100644 --- a/tests/test_client.py +++ b/tests/test_client.py @@ -15,9 +15,10 @@ capture_exception, capture_event, ) +from sentry_sdk.integrations.executing import ExecutingIntegration from sentry_sdk.transport import Transport from sentry_sdk._compat import reraise, text_type, PY2 -from sentry_sdk.utils import HAS_CHAINED_EXCEPTIONS, executing +from sentry_sdk.utils import HAS_CHAINED_EXCEPTIONS if PY2: # Importing ABCs from collections is deprecated, and will stop working in 3.8 @@ -216,6 +217,35 @@ def test_with_locals_disabled(sentry_init, capture_events): ) +@pytest.mark.parametrize("integrations", [[], [ExecutingIntegration()]]) +def test_function_names(sentry_init, capture_events, integrations): + sentry_init(integrations=integrations) + events = capture_events() + + def foo(): + try: + bar() + except Exception: + capture_exception() + + def bar(): + 1 / 0 + + foo() + + (event,) = events + (thread,) = event["exception"]["values"] + functions = [x["function"] for x in thread["stacktrace"]["frames"]] + + if integrations: + assert functions == [ + "test_function_names..foo", + "test_function_names..bar", + ] + else: + assert functions == ["foo", "bar"] + + def test_attach_stacktrace_enabled(sentry_init, capture_events): sentry_init(attach_stacktrace=True) events = capture_events() @@ -232,13 +262,7 @@ def bar(): (thread,) = event["threads"]["values"] functions = [x["function"] for x in thread["stacktrace"]["frames"]] - if executing: - assert functions[-2:] == [ - "test_attach_stacktrace_enabled..foo", - "test_attach_stacktrace_enabled..bar", - ] - else: - assert functions[-2:] == ["foo", "bar"] + assert functions[-2:] == ["foo", "bar"] def test_attach_stacktrace_enabled_no_locals(sentry_init, capture_events): diff --git a/tox.ini b/tox.ini index 9d48520fd1..8e3989499e 100644 --- a/tox.ini +++ b/tox.ini @@ -20,9 +20,7 @@ envlist = # {py2.7}-django-{1.11} # {py2.7,py3.7}-django-{1.11,2.2} - py{2.7,3.4,3.5,3.6,3.7,3.8,py}-executing - - {pypy,py2.7}-django-{1.6,1.7}{-executing,} + {pypy,py2.7}-django-{1.6,1.7} {pypy,py2.7,py3.5}-django-{1.8,1.9,1.10,1.11} {py3.5,py3.6,py3.7}-django-{2.0,2.1} {py3.7,py3.8}-django-{2.2,3.0,dev} @@ -185,8 +183,6 @@ deps = py3.8: hypothesis - executing: executing - setenv = PYTHONDONTWRITEBYTECODE=1 TESTPATH=tests From 60fa4e963cc2b7b4e8f7b6a8e500ab1ef02e16f3 Mon Sep 17 00:00:00 2001 From: Alex Hall Date: Sun, 12 Jul 2020 12:16:45 +0200 Subject: [PATCH 8/9] Ignore frames without a function, esp. template frames --- sentry_sdk/integrations/executing.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/sentry_sdk/integrations/executing.py b/sentry_sdk/integrations/executing.py index a874810418..f8efcf0955 100644 --- a/sentry_sdk/integrations/executing.py +++ b/sentry_sdk/integrations/executing.py @@ -49,7 +49,11 @@ def add_executing_info(event, hint): for exception, (_exc_type, _exc_value, exc_tb) in zip( reversed(values), walk_exception_chain(exc_info) ): - sentry_frames = exception.get("stacktrace", {}).get("frames", []) + sentry_frames = [ + frame + for frame in exception.get("stacktrace", {}).get("frames", []) + if frame.get("function") + ] tbs = list(iter_stacks(exc_tb)) if len(sentry_frames) != len(tbs): continue From c1186d2fbe8fdbefc494d7698f151520d197572e Mon Sep 17 00:00:00 2001 From: Alex Hall Date: Sun, 12 Jul 2020 13:15:53 +0200 Subject: [PATCH 9/9] Add missing type annotation --- sentry_sdk/integrations/executing.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/sentry_sdk/integrations/executing.py b/sentry_sdk/integrations/executing.py index f8efcf0955..4fbf729bb1 100644 --- a/sentry_sdk/integrations/executing.py +++ b/sentry_sdk/integrations/executing.py @@ -22,6 +22,8 @@ class ExecutingIntegration(Integration): @staticmethod def setup_once(): + # type: () -> None + @add_global_event_processor def add_executing_info(event, hint): # type: (Event, Optional[Hint]) -> Optional[Event]