def test_scrub_unnecessary_fields(scrubber): # default assert scrubber.scrub_event({'default': 'field'}) == {'default': 'field'} # custom custom_scrubber = SentryScrubber() custom_scrubber.event_fields_to_cut = ['new', 'default'] assert custom_scrubber.scrub_event({ 'default': 'event', 'new': 'field', 'modules': {} }) == { 'modules': {} }
def test_before_send(): SentryReporter.thread_strategy.set(None) # default scrubber = SentryScrubber() SentryReporter.init('', scrubber=scrubber) # pylint: disable=protected-access SentryReporter.last_event = None assert SentryReporter._before_send({}, {}) == {} assert SentryReporter._before_send(None, {}) is None assert SentryReporter._before_send(None, None) is None SentryReporter.global_strategy = SentryStrategy.SEND_SUPPRESSED assert SentryReporter.last_event is None # check that an event is stored assert SentryReporter._before_send({'a': 'b'}, None) is None assert SentryReporter.last_event == {'a': 'b'} # check an event has been processed SentryReporter.global_strategy = SentryStrategy.SEND_ALLOWED assert SentryReporter._before_send({'c': 'd'}, None) == {'c': 'd'} assert SentryReporter.last_event == {'a': 'b'} # check that event can be ignored assert SentryReporter._before_send( {'a': 'b'}, {'exc_info': [KeyboardInterrupt]}) is None # check information has been scrubbed assert SentryReporter._before_send( {'contexts': { 'reporter': { '_stacktrace': ['/Users/username/'] } }}, None) == { 'contexts': { 'reporter': { '_stacktrace': [f'/Users/{scrubber.placeholder_user}/'] } } } # check release assert SentryReporter._before_send({'release': '7.6.0'}, None) == { 'release': '7.6.0' } assert SentryReporter._before_send({'release': '7.6.0-GIT'}, None) == { 'release': None } # check confirmation SentryReporter.global_strategy = SentryStrategy.SEND_ALLOWED_WITH_CONFIRMATION SentryReporter.get_confirmation = lambda e: False assert SentryReporter._before_send({'a': 'b'}, None) is None SentryReporter.get_confirmation = lambda e: True assert SentryReporter._before_send({'a': 'b'}, None) == {'a': 'b'}
def test_init(mocked_init: Mock, sentry_reporter: SentryReporter): # test that `init` method set all necessary variables and calls `sentry_sdk.init()` sentry_reporter.init(sentry_url='url', release_version='release', scrubber=SentryScrubber(), strategy=SentryStrategy.SEND_SUPPRESSED) assert sentry_reporter.scrubber assert sentry_reporter.global_strategy == SentryStrategy.SEND_SUPPRESSED mocked_init.assert_called_once()
def init_sentry_reporter(): """ Initialise sentry reporter We use `sentry_url` as a URL for normal tribler mode and TEST_SENTRY_URL as a URL for sending sentry's reports while a Tribler client running in test mode """ test_sentry_url = os.environ.get('TEST_SENTRY_URL', None) if not test_sentry_url: SentryReporter.init( sentry_url=sentry_url, release_version=version_id, scrubber=SentryScrubber(), strategy=SentryStrategy.SEND_ALLOWED_WITH_CONFIRMATION) logger.info('Sentry has been initialised in normal mode') else: SentryReporter.init(sentry_url=test_sentry_url, release_version=version_id, scrubber=None, strategy=SentryStrategy.SEND_ALLOWED) logger.info('Sentry has been initialised in debug mode')
def init_sentry_reporter(): """ Initialise sentry reporter We use `sentry_url` as a URL for normal tribler mode and TRIBLER_TEST_SENTRY_URL as a URL for sending sentry's reports while a Tribler client running in test mode """ sentry_reporter = default_core_exception_handler.sentry_reporter from tribler_core.version import sentry_url, version_id test_sentry_url = sentry_reporter.get_test_sentry_url() if not test_sentry_url: sentry_reporter.init(sentry_url=sentry_url, release_version=version_id, scrubber=SentryScrubber(), strategy=SentryStrategy.SEND_ALLOWED_WITH_CONFIRMATION) logger.info('Sentry has been initialised in normal mode') else: sentry_reporter.init(sentry_url=test_sentry_url, release_version=version_id, scrubber=None, strategy=SentryStrategy.SEND_ALLOWED) logger.info('Sentry has been initialised in debug mode')
def __init__( # pylint: disable=too-many-arguments, too-many-locals self, parent, exception_text, tribler_version, start_time, sentry_event=None, error_reporting_requires_user_consent=True, stop_application_on_close=True, additional_tags=None, ): QDialog.__init__(self, parent) uic.loadUi(get_ui_file_path('feedback_dialog.ui'), self) self.setWindowTitle(tr("Unexpected error")) self.selected_item_index = 0 self.tribler_version = tribler_version self.sentry_event = sentry_event self.scrubber = SentryScrubber() self.stop_application_on_close = stop_application_on_close self.additional_tags = additional_tags # Qt 5.2 does not have the setPlaceholderText property if hasattr(self.comments_text_edit, "setPlaceholderText"): placeholder = tr( "What were you doing before this crash happened? " "This information will help Tribler developers to figure out and fix the issue quickly." ) self.comments_text_edit.setPlaceholderText(placeholder) def add_item_to_info_widget(key, value): item = QTreeWidgetItem(self.env_variables_list) item.setText(0, key) scrubbed_value = self.scrubber.scrub_text(value) item.setText(1, scrubbed_value) stacktrace = self.scrubber.scrub_text(exception_text.rstrip()) self.error_text_edit.setPlainText(stacktrace) connect(self.cancel_button.clicked, self.on_cancel_clicked) connect(self.send_report_button.clicked, self.on_send_clicked) # Add machine information to the tree widget add_item_to_info_widget('os.getcwd', f'{os.getcwd()}') add_item_to_info_widget('sys.executable', f'{sys.executable}') add_item_to_info_widget('os', os.name) add_item_to_info_widget('platform', sys.platform) add_item_to_info_widget('platform.details', platform.platform()) add_item_to_info_widget('platform.machine', platform.machine()) add_item_to_info_widget('python.version', sys.version) add_item_to_info_widget('indebug', str(__debug__)) add_item_to_info_widget('tribler_uptime', f"{time.time() - start_time}") for argv in sys.argv: add_item_to_info_widget('sys.argv', f'{argv}') for path in sys.path: add_item_to_info_widget('sys.path', f'{path}') for key in os.environ.keys(): add_item_to_info_widget('os.environ', f'{key}: {os.environ[key]}') # Add recent requests to feedback dialog request_ind = 1 for request, status_code in sorted(tribler_performed_requests, key=lambda rq: rq[0].time)[-30:]: add_item_to_info_widget( 'request_%d' % request_ind, '%s %s %s (time: %s, code: %s)' % (request.url, request.method, request.raw_data, request.time, status_code), ) request_ind += 1 # Add recent events to feedback dialog events_ind = 1 for event, event_time in received_events[:30][::-1]: add_item_to_info_widget('event_%d' % events_ind, f'{json.dumps(event)} (time: {event_time})') events_ind += 1 # Users can remove specific lines in the report connect(self.env_variables_list.customContextMenuRequested, self.on_right_click_item) self.send_automatically = FeedbackDialog.can_send_automatically(error_reporting_requires_user_consent) if self.send_automatically: self.stop_application_on_close = True self.on_send_clicked(True)
class FeedbackDialog(AddBreadcrumbOnShowMixin, QDialog): def __init__( # pylint: disable=too-many-arguments, too-many-locals self, parent, exception_text, tribler_version, start_time, sentry_event=None, error_reporting_requires_user_consent=True, stop_application_on_close=True, additional_tags=None, ): QDialog.__init__(self, parent) uic.loadUi(get_ui_file_path('feedback_dialog.ui'), self) self.setWindowTitle(tr("Unexpected error")) self.selected_item_index = 0 self.tribler_version = tribler_version self.sentry_event = sentry_event self.scrubber = SentryScrubber() self.stop_application_on_close = stop_application_on_close self.additional_tags = additional_tags # Qt 5.2 does not have the setPlaceholderText property if hasattr(self.comments_text_edit, "setPlaceholderText"): placeholder = tr( "What were you doing before this crash happened? " "This information will help Tribler developers to figure out and fix the issue quickly." ) self.comments_text_edit.setPlaceholderText(placeholder) def add_item_to_info_widget(key, value): item = QTreeWidgetItem(self.env_variables_list) item.setText(0, key) scrubbed_value = self.scrubber.scrub_text(value) item.setText(1, scrubbed_value) stacktrace = self.scrubber.scrub_text(exception_text.rstrip()) self.error_text_edit.setPlainText(stacktrace) connect(self.cancel_button.clicked, self.on_cancel_clicked) connect(self.send_report_button.clicked, self.on_send_clicked) # Add machine information to the tree widget add_item_to_info_widget('os.getcwd', f'{os.getcwd()}') add_item_to_info_widget('sys.executable', f'{sys.executable}') add_item_to_info_widget('os', os.name) add_item_to_info_widget('platform', sys.platform) add_item_to_info_widget('platform.details', platform.platform()) add_item_to_info_widget('platform.machine', platform.machine()) add_item_to_info_widget('python.version', sys.version) add_item_to_info_widget('indebug', str(__debug__)) add_item_to_info_widget('tribler_uptime', f"{time.time() - start_time}") for argv in sys.argv: add_item_to_info_widget('sys.argv', f'{argv}') for path in sys.path: add_item_to_info_widget('sys.path', f'{path}') for key in os.environ.keys(): add_item_to_info_widget('os.environ', f'{key}: {os.environ[key]}') # Add recent requests to feedback dialog request_ind = 1 for request, status_code in sorted(tribler_performed_requests, key=lambda rq: rq[0].time)[-30:]: add_item_to_info_widget( 'request_%d' % request_ind, '%s %s %s (time: %s, code: %s)' % (request.url, request.method, request.raw_data, request.time, status_code), ) request_ind += 1 # Add recent events to feedback dialog events_ind = 1 for event, event_time in received_events[:30][::-1]: add_item_to_info_widget('event_%d' % events_ind, f'{json.dumps(event)} (time: {event_time})') events_ind += 1 # Users can remove specific lines in the report connect(self.env_variables_list.customContextMenuRequested, self.on_right_click_item) self.send_automatically = FeedbackDialog.can_send_automatically(error_reporting_requires_user_consent) if self.send_automatically: self.stop_application_on_close = True self.on_send_clicked(True) @staticmethod def can_send_automatically(error_reporting_requires_user_consent): test_sentry_url_is_defined = os.environ.get('TEST_SENTRY_URL', None) is not None return test_sentry_url_is_defined and not error_reporting_requires_user_consent def on_remove_entry(self): self.env_variables_list.takeTopLevelItem(self.selected_item_index) def on_right_click_item(self, pos): item_clicked = self.env_variables_list.itemAt(pos) if not item_clicked: return self.selected_item_index = self.env_variables_list.indexOfTopLevelItem(item_clicked) menu = TriblerActionMenu(self) remove_action = QAction(tr("Remove entry"), self) connect(remove_action.triggered, self.on_remove_entry) menu.addAction(remove_action) menu.exec_(self.env_variables_list.mapToGlobal(pos)) def on_cancel_clicked(self, checked): self.close() def on_report_sent(self, response): if not response: return if self.send_automatically: self.close() sent = response['sent'] success_text = tr("Successfully sent the report! Thanks for your contribution.") error_text = tr("Could not send the report! Please post this issue on GitHub.") box = QMessageBox(self.window()) box.setWindowTitle(tr("Report Sent") if sent else tr("ERROR: Report Sending Failed")) box.setText(success_text if sent else error_text) box.setStyleSheet("QPushButton { color: white; }") box.exec_() self.close() def on_send_clicked(self, checked): self.send_report_button.setEnabled(False) self.send_report_button.setText(tr("SENDING...")) endpoint = 'http://reporter.tribler.org/report' sys_info = "" sys_info_dict = defaultdict(lambda: []) for ind in range(self.env_variables_list.topLevelItemCount()): item = self.env_variables_list.topLevelItem(ind) key = item.text(0) value = item.text(1) sys_info += f"{key}\t{value}\n" sys_info_dict[key].append(value) comments = self.comments_text_edit.toPlainText() if len(comments) == 0: comments = tr("Not provided") stack = self.error_text_edit.toPlainText() post_data = { "version": self.tribler_version, "machine": platform.machine(), "os": platform.platform(), "timestamp": int(time.time()), "sysinfo": sys_info, "comments": comments, "stack": stack, } SentryReporter.send_event(self.sentry_event, post_data, sys_info_dict, self.additional_tags) TriblerNetworkRequest(endpoint, self.on_report_sent, raw_data=tribler_urlencode(post_data), method='POST') def closeEvent(self, close_event): if self.stop_application_on_close: QApplication.quit() close_event.ignore()
def fixture_scrubber(): return SentryScrubber()