Exemple #1
0
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': {}
    }
Exemple #2
0
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()
Exemple #4
0
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')
Exemple #5
0
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')
Exemple #6
0
    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)
Exemple #7
0
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()
Exemple #8
0
def fixture_scrubber():
    return SentryScrubber()