Skip to content

Commit

Permalink
Merge pull request #7727 from drew2a/feature/sentry_parse_specifi_exc…
Browse files Browse the repository at this point in the history
…eptions

Refactor SentryReporter to parse last core output for specific exception types
  • Loading branch information
drew2a committed Nov 27, 2023
2 parents c09b5b5 + d6aa8a0 commit e8b8354
Show file tree
Hide file tree
Showing 2 changed files with 39 additions and 24 deletions.
29 changes: 14 additions & 15 deletions src/tribler/core/sentry_reporter/sentry_reporter.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,8 @@

from tribler.core import version
from tribler.core.sentry_reporter.sentry_tools import (
delete_item,
get_first_item,
get_last_item, get_value,
get_value,
parse_last_core_output
)

Expand Down Expand Up @@ -93,6 +92,7 @@ def __init__(self):

self._sentry_logger_name = 'SentryReporter'
self._logger = logging.getLogger(self._sentry_logger_name)
self._types_that_requires_core_output_parse = {'CoreCrashedError'}

def init(self, sentry_url='', release_version='', scrubber=None,
strategy=SentryStrategy.SEND_ALLOWED_WITH_CONFIRMATION):
Expand Down Expand Up @@ -205,19 +205,18 @@ def send_event(self, event: Dict, tags: Optional[Dict[str, Any]] = None, info: O

# try to retrieve an error from the last_core_output
if last_core_output:
# split for better representation in the web view
info[LAST_CORE_OUTPUT] = last_core_output.split('\n')
if last_core_exception := parse_last_core_output(last_core_output):
exceptions = event.get(EXCEPTION, {})
gui_exception = get_last_item(exceptions.get(VALUES, []), {})

# create a core exception extracted from the last core output
core_exception = {TYPE: last_core_exception.type, VALUE: last_core_exception.message}

# remove the stacktrace field as it doesn't give any useful information for the further investigation
delete_item(gui_exception, 'stacktrace')

exceptions[VALUES] = [gui_exception, core_exception]
info[LAST_CORE_OUTPUT] = last_core_output.split('\n') # split for better representation in the web view

# check is it necessary to parse the last core output
exceptions = event.get(EXCEPTION, {}).get(VALUES, [])
exception_types = (e.get(TYPE) for e in exceptions)
need_to_parse_core_output = any(t in self._types_that_requires_core_output_parse for t in exception_types)

if need_to_parse_core_output:
if last_core_exception := parse_last_core_output(last_core_output):
# create a core exception extracted from the last core output
core_exception = {TYPE: last_core_exception.type, VALUE: last_core_exception.message}
exceptions.append(core_exception)

event[CONTEXTS][REPORTER] = info
event[CONTEXTS][BROWSER] = {VERSION: tribler_version, NAME: TRIBLER}
Expand Down
34 changes: 25 additions & 9 deletions src/tribler/core/sentry_reporter/tests/test_sentry_reporter.py
Original file line number Diff line number Diff line change
Expand Up @@ -281,40 +281,37 @@ def test_send_last_core_output(sentry_reporter):
'exception': {
'values': [
{
'module': 'tribler.gui.utilities',
TYPE: 'CreationTraceback',
VALUE: '\n File "/Users/<user>/Projects/github.com/Tribler/tribler/src/run_tribler.py", ',
'mechanism': None
},
{
'module': 'tribler.gui.exceptions',
TYPE: 'CoreCrashedError',
VALUE: 'The Tribler core has unexpectedly finished with exit code 1 and status: 0.',
'mechanism': None,
'stacktrace': {
'frames': []
}
}
]
}
}

last_core_output = '''
File "/Applications/Xcode.app/Contents/Developer/Library/Frameworks/Python3.framework/Versions/3.8/lib/python3.8/asyncio/base_events.py", line 1461, in create_server
sock.bind(sa)
OverflowError: bind(): port must be 0-65535.Sentry is attempting to send 1 pending error messages
Waiting up to 2 seconds
Press Ctrl-C to quit
'''

actual = sentry_reporter.send_event(event=event, last_core_output=last_core_output)
expected = deepcopy(DEFAULT_EVENT)

expected['exception'] = {
'values': [
{
'module': 'tribler.gui.exceptions',
TYPE: 'CreationTraceback',
VALUE: '\n File "/Users/<user>/Projects/github.com/Tribler/tribler/src/run_tribler.py", ',
},
{
TYPE: 'CoreCrashedError',
VALUE: 'The Tribler core has unexpectedly finished with exit code 1 and status: 0.',
'mechanism': None
},
{
TYPE: 'OverflowError',
Expand All @@ -325,3 +322,22 @@ def test_send_last_core_output(sentry_reporter):
expected[CONTEXTS][REPORTER][LAST_CORE_OUTPUT] = last_core_output.split('\n')

assert actual == expected


EXCEPTION_TYPES = [
# (exception_type, called)
('CoreCrashedError', True),
('AnyOtherError', False)
]


# The `parse_last_core_output` function is patched to have an indicator that the parse bloc is called
@patch('tribler.core.sentry_reporter.sentry_reporter.parse_last_core_output')
@pytest.mark.parametrize('exception_type, called', EXCEPTION_TYPES)
def test_send_last_core_output_types_that_requires_core_output_parse(patched_parse_last_core_output, exception_type,
called, sentry_reporter):
# Test that the `send_event` function parse the "last core output" only for the specific exception types
event = {'exception': {'values': [{TYPE: exception_type}]}}
sentry_reporter.send_event(event=event, last_core_output='any last core output')

assert patched_parse_last_core_output.called == called

0 comments on commit e8b8354

Please sign in to comment.